Home arrow static arrow Java Programming [Archive] - Boolean hashCode
Warning: Creating default object from empty value in /www/htdocs/w008deb8/wiki/components/com_staticxt/staticxt.php on line 51
Java Programming [Archive] - Boolean hashCode
This topic has 30 replies on 3 pages.    « Previous | 1 | 2 | 3 | Next »

Posts:4,496
Registered: 19/06/02
Re: Boolean hashCode  
Aug 2, 2004 7:53 AM (reply 15 of 30)



 
I don't know of a requirement that a hashcode be
randomly chosen. Again, got a reference ?

I just mean you probably shouldn't use the same numbers every time you write a hashCode function. I'm not suggesting you go and roll some dice.
 

Posts:441
Registered: 2/25/04
Re: Boolean hashCode  
Aug 2, 2004 7:54 AM (reply 16 of 30)



 
No. You should always have a clear idea what types your container will permit.

Unfortunately, that breaks many public APIs that you simply cannot enforce it, and there is no other mechanism for general parameter passing.

My experience has been that class cast exceptions are very common bugs .
I anticipate generics eliminating class cast exceptions to the same extent.

Fair enough, IME these simply do not occur.

With the exception of the use as named parameter sets, collections are not exposed publicly, as this is no different to exposing single valued mutable fields publicly- you can do no validation of what's put in them, and it breaks encapsulation.

So there is only localised mutation of the collection, and you always have a clear idea of what is put into the collection- things put in local to the class (and so unit tested), and things that go through the interface of the class (and so pass validation, a subset of which is type safety, so won't cause a class cast or null pointer later).

The reduction in the length of code required to
iterate over a collection is a nice side benefit.

Yes, and orthogonal to type safety. Such reduction is even more evident when you have type inference, or other metadata available.

Oh, and I don't buy the argument that Unit Testing eliminates X, therefore features that reduce instances of X are a Waste of Time.

Fair enough, I'd use generics for the reduction in key-typing, not the gain in instance-typing. And I'd rely on validation at the boundaries rather that Java's class based type system, as it allows far more powerful constraints to be applied.

Pete

 

Posts:6,487
Registered: 5/5/04
Re: Boolean hashCode  
Aug 2, 2004 7:56 AM (reply 17 of 30)



 
Say the hash table size for some reason is 6 and the
standard modulo hash function is used:

1231 % 6 = 1
1237 % 6 = 1

which means a collision. So never use Boolean as key
in a HashMap of size 6 -:)
If you are using a HashMap to look up a Boolean key, you have more problems than whether two of the keys clash.
 

Posts:3,999
Registered: 00-05-26
Re: Boolean hashCode  
Aug 2, 2004 8:02 AM (reply 18 of 30)



 
Perhaps

public int hashCode()
{
return value ? System.identityHashCode( Boolean.TRUE ) : System.identifyHashCode(Boolean.FALSE);
}

would be more generic and still work.
 

Posts:5,904
Registered: 04/03/99
Re: Boolean hashCode  
Aug 2, 2004 8:05 AM (reply 19 of 30)



 

Unfortunately, that breaks many public APIs that you
simply cannot enforce it, and there is no other
mechanism for general parameter passing.

Generics have been retro-fitted to many of the existing public APIs and doesn't break them as far as I know. Do you have a specific example in mind ?

Fair enough, IME these simply do not occur.

I'm surprised to hear that. I've worked on a lot of projects where they've been an issue, and few where they have not. The few tended to be projects where the existing infrastructure precluded the use of collection classes and fencepost errors predominated (after the usual NPEs).

With the exception of the use as named parameter sets,
collections are not exposed publicly

I don't have much time for your argument here, which I would characterise as "we test to make sure the right stuff goes in the API, so the internals won't break". Wishful thinking. If writing library code (all code ends up being used as library code one way or another) what gets passed in is out of your control. Better to whinge with a compiler error than trust the user ot pass you the right thing.

Unit tests are a Good Thing, but they do not catch all errors. Compiletime errors are massively preferable to runtime errors.

The reduction in the length of code required to
iterate over a collection is a nice side benefit.

Yes, and orthogonal to type safety.

Hence my use of the phrase "side benefit".

Such reduction is
even more evident when you have type inference, or
other metadata available.

I do not consider a "side benefit" as sufficient reason for a change in the language. Type safety, on the other hand, certainly is.

Fair enough, I'd use generics for the reduction in
key-typing, not the gain in instance-typing. And I'd
rely on validation at the boundaries rather tha[n]
Java's class based type system, as it allows far more
powerful constraints to be applied.

Powerful, but limited to runtime.

Nope, unit tests are useful. But that doesn't invalidate compile time checking.

Dave.
 

Posts:5,904
Registered: 04/03/99
Re: Boolean hashCode  
Aug 2, 2004 8:09 AM (reply 20 of 30)



 
Perhaps

public int hashCode()
{
return value ? System.identityHashCode( Boolean.TRUE )
: System.identifyHashCode(Boolean.FALSE);
}

would be more generic and still work.

By definition it wouldn't, since it wouldn't be guaranteed to return the JLS documented values here.

Dave.
 

Posts:4,496
Registered: 19/06/02
Re: Boolean hashCode  
Aug 2, 2004 8:20 AM (reply 21 of 30)



 
Perhaps

public int hashCode()
{
return value ? System.identityHashCode( Boolean.TRUE )
: System.identifyHashCode(Boolean.FALSE);
}

would be more generic and still work.

18464898 is not odd, neither is it prime. 28168925 is not prime either. And what if you loaded the Boolean class with a custom classloader?
 

Posts:13,769
Registered: 00-11-29
Re: Boolean hashCode  
Aug 2, 2004 8:23 AM (reply 22 of 30)



 
Awesome. So many 1.5 obsfucation possiblities:
int countingToThreeThenZero = 1230;boolean b = //something; if (b.hashcode() % countingToThreeThenZero  == 1) {   // do something} else if (b.hashCode() % countingToThreeThenZero  == 7) {   // do something else} else {   System.exit(0);}
 

Posts:5,965
Registered: 5/17/03
Re: Boolean hashCode  
Aug 2, 2004 8:41 AM (reply 23 of 30)



 
A good hashCode should be a
hard-coded, randomly chosen, non-zero, odd, prime
number.

The hashCodes should be as evenely distributed as possible over the value range of an int.
 

Posts:4,496
Registered: 19/06/02
Re: Boolean hashCode  
Aug 2, 2004 8:54 AM (reply 24 of 30)



 
A good hashCode should be a
hard-coded, randomly chosen, non-zero, odd, prime
number.

The hashCodes should be as evenely distributed as
possible over the value range of an int.

Yes, distribution of hash values is important as well. However if all hashCodes were written so that their values were as evenely distributed as possible over the value range of an int you have the same problem that you are trying to avoid ...
 

Posts:5,965
Registered: 5/17/03
Re: Boolean hashCode  
Aug 2, 2004 9:03 AM (reply 25 of 30)



 
A good hashCode should be a
hard-coded, randomly chosen, non-zero, odd, prime
number.

The hashCodes should be as evenely distributed as
possible over the value range of an int.

Yes, distribution of hash values is important as
well. However if all hashCodes were written so that
their values were as evenely distributed as possible
over the value range of an int you have the same
problem that you are trying to avoid ...

Okay I thought you were referring to the general case but maybe you meant the special case of a Boolean.
 

Posts:441
Registered: 2/25/04
Re: Boolean hashCode  
Aug 2, 2004 10:02 AM (reply 26 of 30)



 
Generics have been retro-fitted to many of the existing public APIs and doesn't break them as far as I know. Do you have a specific example in mind ?

JSR-84, all over the place passes Map<Object, Object> to initialise service providers. Any retro-fit to anything more specific will probably break something somewhere.

I've worked on a lot of projects where they've been an issue, and few where they have not.
The few tended to be projects where the existing infrastructure precluded the use of collection classes and fencepost errors predominated (after the usual NPEs).

Well, can't say I get many fencepost errors either, but then most of that sort of code is generated from metamodels rather than typing it in each time.

With the exception of the use as named parameter
sets, collections are not exposed publicly

I don't have much time for your argument here, which I
would characterise as "we test to make sure the right
stuff goes in the API, so the internals won't break".

I'd say that the right API has stronger compile time safety than anything generics offers:
public class Foo {  private List foo_;   public void addFoo (String foo) {    if (foo == null) { throw new NullPointerException(); }    if (foo.length() == 0) { throw new InvalidInputException(STRING_NOT_EMPTY); }    foo_.add(foo);  }   public String getFoo (int index) {    return (String)foo_.get(index);  }}
Is more likely to result in fewer errors than
class Foo {  public List<String> foo;}
Via an API you get type safety, fine grained control of mutation methods (you can have queries public but mutators package-private for example), and whatever runtime validation you want on top.

You also could plug in an array or whatever container implementation you want behind the API.

Wishful thinking.

No, 15+ years OOD experience. Encapsulation is a good thing. Expose as little as possible.

If writing library code (all code ends up being used as library code one way or another) what gets passed in is out of your control.

All the more reason to validate the inputs; and to separate the interface and implementation- expressing a multivalued property via an API instead of a collection.

Better to whinge with a compiler error than trust the user ot pass you the right thing.

I'm not winging about compiler errors. The generic ones just don't give me anything other than catching typos, which are just as likely to result in syntax errors as go against the weak generic safety rules.

Unit tests are a Good Thing, but they do not catch all errors. Compiletime errors are massively preferable to runtime errors.

When developing, I use Ant to run the tests on the unit I'm working on as part of the build. The difference between compile and runtime is half a second.

I do not consider a "side benefit" as sufficient reason for a change in the language. Type safety, on the other hand, certainly is.
How much type safety have you gained? You'd need to either forget what type foo was, or make the same typo twice (on the method declaration and the cast on the return) for there to be a problem the compiler won't catch without generics. What you've mainly gained is the erasure of the runtime cast check, and the reduced code size (both good things).

Powerful, but limited to runtime.

Based on the description of the above example, 'class Foo has a list foo of non-null, non-empty Strings', give one error that exposing a generic container will prevent that exposing the container as an API doesn't. The client can't put anything of the wrong type in, or get anything of the wrong type out. Moreover, the remaining code can assume that there won't be any null or empty strings in the list when processing it.

The only thing that isn't trapped is the case where you have forgotten what the type of the elements in the collection are whilst implementing other methods in the Foo class, which isn't a problem I find I have often- if it will compile with such an error (eg you're calling a method on every element of a list and you've accidently cast something to a type that has a method of the same signature, which really isn't that likely), then they show up straight away on the unit test for the method I'm working on.

Pete

 

Posts:6,487
Registered: 5/5/04
Re: Boolean hashCode  
Aug 2, 2004 10:07 AM (reply 27 of 30)



 
I think that assumes that you're not putting anything
but Boolean objects into your map. There's no reason
why you shouldn't be sticking Integer and String
objects in as well.
In theory you are right. In reality, I have never come a practical example for using Boolean type as key. Actually, I have never come a across a good example for having mixed classes for keys. This using ends being more trouble than it is worth.
 

Posts:5,904
Registered: 04/03/99
Re: Boolean hashCode  
Aug 2, 2004 10:25 AM (reply 28 of 30)



 

JSR-84, all over the place passes Map<Object, Object>
to initialise service providers. Any retro-fit to
anything more specific will probably break something
somewhere.

Again, you haven't really given me a specific example; where will it break, what is the code that breaks it. As far as I know, generics won't break client code in the way you seem to be describing. To clarify which one of us is misunderstanding, could you give a specific example please.

I'd say that the right API has stronger compile
time safety than anything generics offers

<Snip foo example>

Sure, that's a better API if that's what you want to do. So ? List<String> is for when you want a (subclass of) List of strings, not when you want a Foo of Strings ! Generics allow you to write generic code to handle specific types. Your example is specific code to handle a specific type.

Intentionally or not, your Foo example is a straw man at best.

I'm not winging about compiler errors. The generic
ones just don't give me anything other than catching
typos

This has nothing to do with typographical errors. Passing a String to a collection of Integers can (and does) happen as a result of poor documentation. I think that typing "String" when you mean "Integer" is unusual.

which are just as likely to result in syntax
errors as go against the weak generic safety rules.

I don't think that has anything to do with it, but since you raise the issue, your foo example is harder to enter correctly than your list example. But I repeat, this has nothing to do with typograhic errors.

When developing, I use Ant to run the tests on the
unit I'm working on as part of the build. The
difference between compile and runtime is half a
second.

No it isn't. The difference is that you are guaranteed to catch all compile-time errors before the application is deployed. Only runtime errors occur after the application is deployed.

<More "Foo" related discussion snipped>

Dave.
 

Posts:441
Registered: 2/25/04
Re: Boolean hashCode  
Aug 2, 2004 11:45 AM (reply 29 of 30)



 
As far as I know, generics won't break client code in the way you seem to be describing. To clarify which
one of us is misunderstanding, could you give a specific example please.

a Map is normally used to store key/item pairs where all keys are the same class and all items are the same class.

jsr-84 passes a map to the service provider for implementation specific properties. Say you implement jsr-84 and publish the list of your implementation dependent properties such that the type of the value with the key 'myorg.debug' is Boolean. Any attempt to change the API to give any stronger type safety will either prevent that property being set, or prevent properties of any other type being set, breaking the code. Now, I'm not saying anyone would make a change that breaks the existing contract, only that most of the cases where I've seen Map being passed around an API it's used that way, and so the initial statement would break those APIs.

In most cases I've seen maps being passed across APIs, they are used in this manner. You don't know what the type in the map is, and enforcing the requirement that you know would break existing code.

Sure, that's a better API if that's what you want to do. So ?
I'm in the habit of writing software that does what I want it to do. Give an example of something you want to do.

List<String> is for when you want a (subclass of) List of strings, not when you want a Foo of Strings !

I've never had a user ask for something to operate on a list of strings, and can't think of a reason you'd want to expose one. Give a practical example of something that might really exist in a program, and explain how generics add to the quality of the code.

If you have something that provides a sequence of names, then it's better a interface with appropriate methods- allowing flexibility and adaptability (can more easily be extended to be title and name), and self documenting (an interface can be created whose name 'NameSequence' and methods 'nextName' indicate purpose, rather than implementation detail). Internally to classes, I would want to use generics, as it reduces typing and typos. But I wouldn't expose them in leiu of something that conveys intent.

Generics allow you to write generic code to handle specific types. Your example is specific code to handle a specific type.
Yes. That is typical of most software in my experience. An NameSequence will hold a sequence of names. If you want to sort it, either it knows how to sort itself (an would implement the sortNames() method by calling Collections.sort on its internal list, maybe with a comparator of its creation- both local and so easy to ensure are correctly typed, but hardly a problem to maintain as they are local to the same implementation), or the client creates its own collection by getting all the names and sort that (as you generally don't want external algorithms modifying the state of an object).

Intentionally or not, your Foo example is a straw man at best.
No. Software is mainly specific to a task. The types should reflect that (otherwise you may as well download something someone has already written). It's not a good example as to where you'd use generics, because it's intentionally an example of the type of class the people write all the time. Provide a different example if you like that typical of your experience.

This has nothing to do with typographical errors.
Passing a String to a collection of Integers can (and does) happen as a result of poor documentation. I
think that typing "String" when you mean "Integer" is unusual.

OK, assuming OO, class Foo has a property that is a collection of String. There are two ways of setting the values of this collection- through the public API, or internally inside the class. If you haven't read enough of the documentation on the class to understand the types of its properties, then you shouldn't be altering its internals. Outside of the class, you only have the API and cannot make this error. Assuming you have read and understood the class you're editing, then the only cause is a typo, or 'brain ****'. If people start messing round with code they haven't bothered to understand, then nothing is going to save you (though preventing such code compiling may well be an improvement, I'll grant you that, but it would also fail its unit tests).

I don't think that has anything to do with it, but since you raise the issue, your foo example is harder
to enter correctly than your list example. But I repeat, this has nothing to do with typograhic errors.

1/ the list example doesn't give the same level of validation and will result in runtime errors if you put in null but something else expects none of the elements to be null.
2/ I use a macro facility to generate such code. Typically I'd write
class Foo {  /**   * @accessor.members   * @constraint elt != null   * @constraint elt.length() > 0   */  private List /*<String>*/ foo_;}
Then pass it through a macro expander. Which saves a lot of time (especially once you have property validators and change listeners, which can also be added), and means that (once you've got the macros right once) you just don't get the sorts of errors you're concerned with.

No it isn't. The difference is that you are guaranteed to catch all compile-time errors before the
application is deployed. Only runtime errors occur after the application is deployed.

In my experience, by using a code generator and encapsulating the collection behind an API, the runtime errors due to class casts occur in unit tests if anywhere. I have not had one post deployment using this approach that would have be solved by generics. Generics in interfaces seem to be an attempt to increase the coupling between client and service providers in APIs; this is generally a bad thing- you want cohesion within the class, and flexibility between them.

You can get the same compile time safety without generics for clients, and internally to classes I don't find it a problem. Nothing I've said has stopped you using generics in implementing the internals of your classes- if I was targeting 1.5 I would use them for that, but make the API express the purpose of the class, not its implementation. If you want to use generics, fair enough. But, as I said at first, in my experience any type safety it adds is not solving any problem I suffer from, and it presents an illusion of compile time safety that may encourage people to use it as the only validation mechanism.

Pete

 
This topic has 30 replies on 3 pages.    « Previous | 1 | 2 | 3 | Next »