Skip to main content

Adding ~ operator as alternative to equals()

40 replies [Last post]
denisw
Offline
Joined: 2005-01-03

Like in the topic "Add === operator for a.equals(b)", I think a operator for equals() would be useful. I prefer ~. So

if (a.equals(b)) {
...
}

would become

if (a ~ b) {
...
}

To be compatible, equals() could be called also normally.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
sjasja
Offline
Joined: 2004-08-15

> So, you're writing a special static utility method
> to check for null before calling equals, and then
> check AGAIN for null inside your equals method?

I use the little static utility to implement the "normal" equals. To wit (pseudocode, details stripped):
[code]
class Person
{
private String name;
private Address address

boolean equals(Object otherObject)
{
if (otherObject == null) return false;
if (otherObject.getClass() != this.getClass()) return false;
Person other = (Person) otherObject;
return Util.equals(name, other.name) &&
Util.equals(address, other.address);
}
}
[/code]
The first null check in the static utility is needed because "this.name.equals(other.name)" would NPE if this.name is null.

The second null check is indeed redundant. I put it in for extra safety in case someone wrote a borked equals(). I hope the redundant check does not cause anyone any undue distress. I wonder if my programs would be amazingly faster or something if I removed it.

I would like to take this opportunity to assure you that there is no "serious trouble" or "error in my program logic" related to NPEs.

There are, however, places where I perform redundant checks, or check for invalid parameters even in cases where I know nobody is passing bad parameters, or have "default" labels on switches that cannot possibly ever be reached, etc. These are not "serious trouble", they are just me being (possibly overly) cautious.

sjasja
Offline
Joined: 2004-08-15

> The whole discussion about new operators or keywords
> wouldn't have arisen if there was a static equality method
> in class java.lang.System or maybe java.lang.Object that
> does the null-check and then calls Object.equals.

I just keep this in my static "Util" class:
[code]
public static boolean equals(Object a, Object b)
{
if (a == null)
return b == null;
if (b == null)
return false;
return a.equals(b);
}
[/code]
...along with 190 other small static utility functions. Doesn't everyone do that? :[i][/i]-)

I don't need to request Sun to write all those little helper functions for me. I just write what I figure I need.

jwenting
Offline
Joined: 2003-12-02

no, I don't.
Would require an extra function call whenever I want to do a comparison...

Simply having a line "if (o==null) return false;" on the top of every equals method does the trick just fine.

Your method doesn't work on anything you don't write yourself either.
You've just broken the equals contract in fact, by not checking for null inside your equals method as you're supposed to.
Now whenever someone calls the equals method on one of your objects with a null argument he gets a NullPointerException instead of the expected false.

Had there been a static equals method like yours in the standard libraries the same thing would happen.

So keep to the published contract and check for null inside your equals method (which you'll need anyway).

sjasja
Offline
Joined: 2004-08-15

> Would require an extra function call whenever
> I want to do a comparison...

So? Is there a problem with that?

> You've just broken the equals contract in fact, by not checking for
> null inside your equals method as you're supposed to.

No I have not.

In all my years of existence on this planet, I have written exactly zero Java equals methods that do not check for null in equals() as per the "equals contract".

Have you actually seen a single one the equals() methods I have written?????

> You've just broken the equals contract in fact, by not checking
> for null inside your equals method as you're supposed to.

How do you deduce how my equals() methods handle null?

I can assure you they work extremely well - just as they are supposed to - with null.

The existence (and usefulness) of a static "Util.equals()" helper function affects my equals() methods in exactly no way at all. It breaks exactly zero of the contracts of my equals() methods.

jwenting
Offline
Joined: 2003-12-02

So, you're writing a special static utility method to check for null before calling equals, and then check AGAIN for null inside your equals method?

Makes the entire purpose of that utility method rather dubious, which is why I assumed you were using it in lue of checking for null inside your equals methods...

Why check for null twice on the same object after all in a single operation?

Or if you're trying to check whether the object you want to call equals ON is null, why bother?
If it is you're in more serious trouble as such indicates an error in your program logic, a clear case where you want that NPE to be thrown.

podlesh
Offline
Joined: 2004-07-26

> Or if you're trying to check whether the object you
> want to call equals ON is null, why bother?
Isn't that obvious?

> If it is you're in more serious trouble as such
> indicates an error in your program logic, a clear
> case where you want that NPE to be thrown.
Comparing two objects which can be null (both of them) is no design error "per se". It can be avoided in many cases by carefull design, but it's still very common operation.

hlovatt
Offline
Joined: 2003-11-18

You can write an equals method and use it yorself if you want one, so perhaps the request could simply to be to add to 'System' say some equals methods. EG:
[code]
public class System {
...
public static boolean equals( final Object lhs, final Object rhs ) {
if ( lhs == null ) return rhs == null; /* The call rhs.equals( lhs ) is incorrect - equals should return false for a null argument - see javadoc for equals */
return lhs.equals( rhs );
}
public static boolean equals( final boolen lhs, final boolean rhs ) { ... }
// equals for other primitives and arrays
...
}
[/code]
Then in your code you can write:
[code]
import static System.*;
...
if ( equals( x, y ) ) ...
...
public boolean equals( final Object other ) {
if ( other instanceof ThisClass ) return equals( (ThisClass) other );
return false;
}
public boolean equals( final ThisClass other ) {
return equals( field1, other.field1 ) &&
equals( field2, other.field2 );
}
[/code]
Note that the call 'equals( x, y )' is not that much longer than the call 'x equals y' and avoids the issue of binding, i.e. what does 'x equals y equals z' do in general and in particular when 'y' is 'null'.

I have in the back of my mind that jakata commons have already written something similar to what I propose, so there is the possibility that no code need be written at all.

There also seems to be an undercurrent in this thread that shorter syntax is good, this is not my experiance. My experiance would suggest that short syntax in general leads to programs that no one, including the original programmer, can understand. Therefore I would be wary about clever bits of syntax. Probably the best examples of this are APL and LISP that have had troubled histories because their syntax was so brief that no one could read the code.

mcnepp
Offline
Joined: 2005-06-22

> You can write an equals method and use it yorself if
> you want one, so perhaps the request could simply to
> be to add to 'System' say some equals methods. EG:

I agree. The whole discussion about new operators or keywords wouldn't have arisen if there was a static equality method in class [b]java.lang.System[/b] or maybe [b]java.lang.Object[/b] that does the null-check and then calls [b]Object.equals[/b].

Maybe we should simply agree on requesting such a method for the next Java version?!

jwenting
Offline
Joined: 2003-12-02

You'd still have to have an equals method in each class to decide what algorithm to use...

And what's the advantage anyway of using
[code]
if (System.isEqual(a, b)) {
}
[code]

over
[code]
if (a.equals(b)) {
}
[/code

or (the suggested idiocy)
[code]
if (a === b) {
}
[/code]

In all cases there needs to be something in the classes of which a and b are instances that determines what equality actually MEANS for those classes.
You can't just go ahead and compare all fields, as that's often not needed (or can even fail).
For example in case of DAOs that have a primary key and a record id only those need to be checked.
In fact, checking anything else will cause trouble as it can lead to duplicate key errors.

hlovatt
Offline
Joined: 2003-11-18

I think the advantages of a static equals method are three fold:

1. It checks for null on the first argument

2. It can be overloaded so that it works for objects, primitives, and arrays, i.e. one method call no matter what kind of type

3. The == test for float and double have some limitations, e.g. see Double.equals( double d1, double d2 ), and these tests can be replaced with a static equals that calls equals in Double and Float

But I agree with jwenting's sentiment that it isn't that hard to do it yourself, hence I think it is overboard to ask for a new keyword or symbol. The solution of adding some static methods to System (or Object) would seem to be sufficient. Whilst you were at it you might as well add some hashCode methods since if you are writing your own equals you should be writing your own hashCode :)

alexanderschunk
Offline
Joined: 2005-03-24

I don't see why using === is much more clearer?

I am still confused with = and ==, the first being an assignment and the latter a comparison.

And finally, where does this lead us to? And think of the compiler who has to be aware of to distuingish == and === which may not be trivial to implement.

I rather would prefer [b]equals[/b] as a keyword like [b]instanecof[/b].

For example, if you are using [b]equals[/b] as a keyword in the meaning of a.equals(b), so this being a shortcut version of the method call.

Since the a.equals(b) simply returns a boolean value if the condition is true or not, you may implement this keyword having the same behaviour, so if your write:

if(a equals b)

this would mean: if a equals b, return true, else return false.

Message was edited by: alexanderschunk

jwenting
Offline
Joined: 2003-12-02

and ==== for even deeper comparison?
Maybe !!!! if we want to be really sure something's not the same?

If you can't be bothered to learn the difference between == and .equals how in hell would you be bothered to learn the difference between ==, .equals, and ===?

laurapiersol
Offline
Joined: 2003-06-13

I don't understand why you think this would be horrible. Is it the part of "a == b or (a != null && a.equals(b))"? This is how you need to compare if you can't assure that a or b is not null. Is it the syntax "~"? I agree there. Don't call the proposal "horrible" unless you can state a reason.

There is currently NO SIMPLE / READABLE way to compare 2 value objects where one might be null. Since this is needed by %99.9 of programs every java programmer (2 million by last count) must create his own method for doing this. Thats a whole lot of bugs floating around. A library routine might be viable, however ugly it is, but Sun has not added that library routine. Either Sun needs to add the library routine:
equals(Object a, Object b)
or add the appropriate operator "=., ===, =?, ..ect";

This is an important problem thats not going to go away by just calling it names (operator overloading and operator overloading sucks).

monika_krug
Offline
Joined: 2004-10-14

> I don't understand why you think this would be
> horrible. Is it the part of "a == b or (a != null &&
> a.equals(b))"? This is how you need to compare if you
> can't assure that a or b is not null. Is it the
> syntax "~"? I agree there. Don't call the proposal
> "horrible" unless you can state a reason.

I am all for an operator that returns true if a and b are equal or both null and does not have the danger of a NullPointerException. In the other thread about this topic I suggested either using === or ~ for this.

If you read closely what I quoted, you will see that I called the suggestion to use = for this purpose horrible. = should exclusively be used for assignment.

Monika.

laurapiersol
Offline
Joined: 2003-06-13

My bad. I misunderstood Monika. Sorry.

monika_krug
Offline
Joined: 2004-10-14

No problem. :-)

Monika.

monika_krug
Offline
Joined: 2004-10-14

> My favourite candidate for operator to replace
> a==null ? b==null : a.equals(b)/a == b || (a != null
> && a.equals(b)) is just plain old =.

Waaah! No, you can't be serious about this. This would be horrible!

Monika.

denisw
Offline
Joined: 2005-01-03

I think writing

a [b]equals[/b] b

would be a great idea, for that this reminds me of the existing binary [b]instanceof[/b] operator in Java. Great, lucretius2!

sksamuel
Offline
Joined: 2005-01-15

It's a ridiculous idea to save typing two parenthesis, a variable name and a dot.

jwenting
Offline
Joined: 2003-12-02

> > I think that's a horrible syntax. If you're going
> to
> > do that kind of thing then you may as well go full
> > hog and offer operator overloading a la C++...
> which
> > I can't say I'm overly fond of either, as
> experience
> > has shown me that the tendency is for developers
> to
> > try to pigeon-hole every operation into a
> convenient
> > operator overload, leading to awkward code.
>
> Er, sorry, I don't see the connection between this
> proposal and C++'s operator overloading. I am merely
> suggesting that in a method call with 1 parameter you
> are allowed to omit the following 3 unnecessary
> characters: . ( )
>
They aren't unnecessary, they're there because you're calling a function on an object.
You're replacing a function call with an operator, defining that EVERY function that takes a single parameter is in fact an operator by definition.
That's not light operator overloading, it's in fact far heavier than anything I've ever seen.

Going all the way and include complete C++ style operator overloading would be light in comparison.

>
> There's no suggestion that this syntax would be
> restricted to certain keywords. You could use it with
> any suitable method name. It's merely a simpler
> method-calling syntax.
>
Indeed, and that's the core problem. You're redefining what an operator is and changing it to mean anything that does anything to anything using any one other thing...

Exceedingly bad idea and one that's sure to make the obfuscated C programming contest look seriously to switch to Java.

> > not to mention that it in no way
> > simplifies the look or readability of the code.
>
> I'm sorry but I refuse to accept, and I think most
> programmers would agree, that (say)
>
> a append b
>
> is not simpler and more readable than
>
> a.append(b)
>

It is indeed NO simpler at all. In fact it's far more complex.
1) a append b would need to yield the same result as b append a for all a and b. This is not the case with your idea at all.
2) you're missing that a append b is not what you'd need to type to do things properly. You'd have to make it a = a append b which is even more of an abomination as well being longer.

Finally your statement that "most would agree with me" is simply a cheap lie to get what you want which seems to be the destruction of the Java platform by making it impossible to use.

> Methinks my mentioning the unmentionable words
> 'operator overloading' provoked a certain (kneejerk?)
> reaction.

No kneejerk reaction at all. We've all been there and seen what it (operator overloading) does and none of it is good.
Any proposal to add operator overloading (and especially if that proposal is designed in such a way as to look like something else, sneaking it in so to say) must be shot down quickly.

pete_kirkham
Offline
Joined: 2003-06-20

I don't like the proposal, both for the operator overloading reasons and that I like having ( ) * as the expression pattern, but..

> It is indeed NO simpler at all. In fact it's far more
> complex.
> 1) a append b would need to yield the same result as
> b append a for all a and b. This is not the case with
> your idea at all.

Why? does a - b yield the same result as b - a for all a and b?

> 2) you're missing that a append b is not what you'd
> need to type to do things properly. You'd have to
> make it a = a append b which is even more of an
> abomination as well being longer.

Operators do not need to have immutable operands; you don't have to write a = a++ for example. (though generally it's better practice for immutability to be respected)

Pete

tackline
Offline
Joined: 2003-06-19

I've seen proposals for infix syntax as:

a (equals) b

Just dropping .(,) for method calls causes ambiguities with statements such as:

A b;

Does that mean call method b on object A or declare a local variable b of type A? Ideally Java's syntax would be completely replaced dropping all the {.(,);} (see http://jroller.com/page/tackline/20040325#too_much_punctuation), but best not hold our collective breaths on that one.

My favourite candidate for operator to replace a==null ? b==null : a.equals(b)/a == b || (a != null && a.equals(b)) is just plain old =. Obviously there is a problem in that = already does something. However, I claim using the existing = in an expression is evil. If the assignment expressions were of void type (or recast as a statement), then the only ambiguity in existing code would be for booleans and Booleans.

lucretius2
Offline
Joined: 2004-12-19

> Just dropping .(,) for method calls causes
> ambiguities with statements such as:
>
> A b;
>
> Does that mean call method b on object A or declare a
> local variable b of type A?

But A b; wouldn't be allowed on my proposal, since I'm proposing this syntax would only be legal for methods which have 1 parameter, e.g.

A b c; // same as A.b(c)

There may be other ambiguities, but I can't think of serious ones right now, ones which couldn't be avoided by suitable rules.

The various objections above that a method isn't an operator are, IMHO, wrong. A operator (with 2 operands) is just alternative syntax for a method call with 1 parameter. OK, an 'operator' typically has no side-effects (doesn't modify the operands or anything else). But this is just a convention which can't currently be enforced by Java. This does not count as an objection, because no alternative syntax for equals(), such as ~ , could prevent equals() from modifying objects either.

In short, I haven't read any serious objections to the following elegant and generalizable syntax:

if (a equals b); // same as if (a.equals(b))

markf
Offline
Joined: 2005-01-20

Someone in the java.sun.com forums made that astute observation that any new operators in this vein probably shouldn't apply to primites, which are well served by ==.

I envision the following:
[code]
int a = 10;
int b = 10;
int c = 11;
assert a == b; /* This is just like normal. */
assert a != c; /* Nothing changes for primitives. */
assert a <= c; /* == fits in well with the comparison operators. */

String x = "Foo";
String y = x;
String z = "Foo";
String w = "Bar";
assert x is y; /* This is equivalent to x == y. */
assert x eq z; /* This is equivalent to x.equals(y). */
assert !(x is z); /* I doubt we need a "nis" operator. */
assert !(x eq w); /* Or a "neq" operator. */

Object m = null;
Object n = null;
assert m eq n; /* Both operators should handle null gracefully. */
assert m is n; /* Both operators should handle null gracefully. */
[/code]

I hope Sun takes the idea discussed here seriously.

jwenting
Offline
Joined: 2003-12-02

and how would you define it when someone tries to use your equals operator on 2 arguments, one an object and one a primitive?

Just learn to use .equals for heaven's sake. It's not hard.

markf
Offline
Joined: 2005-01-20

> and how would you define it when someone tries to use
> your equals operator on 2 arguments, one an object
> and one a primitive?
>
> Just learn to use .equals for heaven's sake. It's not
> hard.

It wouldn't be defined at all for primitives.

Using equals(Object) isn't exactly easy. You have to check for null, and you may need that the converse equality is true as well. Just look at the jiggery-pokery that goes into writing a well-defined equals(Object) method, or look at Jakarta's EqualsBuilder class.

[code]
/* Traditional equals method. */
public boolean equals(Object o) {
if (!(o instanceof MyClass)) return false;
if (this == o) return true;

MyClass other = (MyClass) o;

if (null == this.field1 && this.field1 != other.field1) return false;
if (null != this.field1 && !this.field1.equals(other.field1) return false;

if (null == this.field2 && this.field2 != other.field2) return false;
if (null != this.field2 && !this.field2.equals(other.field2) return false;

if (null == this.field3 && this.field3 != other.field3) return false;
if (null != this.field3 && !this.field3.equals(other.field3) return false;

return true;
}

/* equals method using new operator notation. */
public boolean equals(Object o) {
if (!(o instanceof MyClass)) return false;
if (o is this) return true;

MyClass other = (MyClass) o;

return (this.field1 eq other.field1)
&& (this.field2 eq other.field2)
&& (this.field3 eq other.field3);
}
[/code]

Which one is clearer? Which one makes more sense? I guess the first method could have been written more compactly by using the ternary choice operator, but that presents its own nightmarish problems and is generally regarded as harmful to program maintainability.

The architects of the Python language have the right idea -- brevity and conciseness are the hallmarks of a good programming language. The language shouldn't bog the programmer down with needless typing, with the burden writing unnecessary checks and conversions, with wasteful idioms.

ppolsinelli
Offline
Joined: 2004-01-20

a equals b

would be just great. but its practical, and hence disliked by many.

not introducing new symbols makes it easier to adopt it, and makes it hard to confuse it with == or =

jwenting
Offline
Joined: 2003-12-02

Let's simplify the language even more.
[code]
PROGRAM CALCINTEREST
INPUT AMOUNT
INPUT INTERESTRATE
OUTPUT TOTALINTEREST
PROGRAM END
[/code]

The compiler should be smart enough to determine the functionality of the program from the program and parameter names and do everything for you.

sksamuel
Offline
Joined: 2005-01-15

=== is much clearer for identity.

kcpeppe
Offline
Joined: 2003-06-15

and we could use ==== for deep comparisons

monika_krug
Offline
Joined: 2004-10-14

What do you suppose "deep equals" would constitute? Comparing member variables with equals() instead of with ==? But you don't know whether they are compared with == in the first place. They are compared whatever way it is defined in the equals() method of the class.

a === b would translate to a == b || (a!=null && a.equals(b)) (or maybe a symmetric version which adds && b!=null && b.equals(a)). But what should ==== translate to?

Monika.

markf
Offline
Joined: 2005-01-20

If the way equality works is going to be changed, it really ought to be changed completely. A half-assed approach would serve no purpose.

I'd have designed Java so that there were three forms of equality:

The 'is' operator -- checks referential equality.
The '==' operator -- checks semantic equality.
The 'eq' operator -- checks value equality.

Referential equality, of course, means that two variables refer to exactly the same object.

Value equality means that all of their fields are the same (this is also called deep equality).

Semantic equality is just whichever of the previous two is most appropriate for the class in question, and is what is used most of the time. For instance, two distinct int variables with the same value would be semantically equal, while two arrays with the same contents would probably not be considered semantically equal.

The fact is though, a serious change to how equality works is unlikely, and a halfway solution wouldn't solve anything.

monika_krug
Offline
Joined: 2004-10-14

The "halfway" solution would solve a lot: It would prevent NullPointerExceptions and having to write a==b || (a!=null && a.equals(b)).

With your solution of three operators, one could not define ones own .equals() method!

Monika.

markf
Offline
Joined: 2005-01-20

Well, the point of the idea would be that the == and eq operators would both be overloadable. But nevermind that, it's too big an overhaul for any reasonable update to Java.

Getting back to your idea, why not do something like the following:

[code]
a eq b;
/* equivalent to: */
a==b || (a!=null && b!=null && a.equals(b) && b.equals(a));

a is b;
/* equivalent to: */
a == b;
[/code]

It makes it more clear what each of the two does. The standard == operator would be left in place for backwards compatibility.

I think the idea of using '===' is too ambiguous, and 'equals' as an operator is too verbose. Terseness should be what we're after.

wingetr
Offline
Joined: 2004-01-19

~ is already used as "binary not". Using the same symbol for two very different things can be confusing.

lucretius2
Offline
Joined: 2004-12-19

Someone suggested the following good idea (or this is my version of it anyway):

instead of
a.equals(b)
you can write
a equals b

Similary for any method call with a single parameter:
a = b add c; // b.add(c)

This is a kind of a lite form of operator overloading. IMHO it's just the kind of syntax de-cluttering Java needs to give it the simplicity of scripting languages (like Python) but without their lack of rigor.

There need to be rules about precedence when chaining method calls like a add b add c, but these could either work left to right, i.e. (a.add(b)).add(c), or be disallowed without parentheses, i.e. you have to write (a add b) add c.

ianl
Offline
Joined: 2003-06-11

I think that's a horrible syntax. If you're going to do that kind of thing then you may as well go full hog and offer operator overloading a la C++... which I can't say I'm overly fond of either, as experience has shown me that the tendency is for developers to try to pigeon-hole every operation into a convenient operator overload, leading to awkward code.

Your proposed syntax would "Fortran-ify" Java... something I think the language can live without.

Based on the current syntax of Java, I'd expect "add" to be a keyword and I don't think the language benefits in any way from the addition of the whole set of overly specific keywords (add, subtract, multiply, divide, root, square, powerof, etc... the list goes on and on and on) you would need to cover a broad set of cases, not to mention that it in no way simplifies the look or readability of the code.

lucretius2
Offline
Joined: 2004-12-19

> I think that's a horrible syntax. If you're going to
> do that kind of thing then you may as well go full
> hog and offer operator overloading a la C++... which
> I can't say I'm overly fond of either, as experience
> has shown me that the tendency is for developers to
> try to pigeon-hole every operation into a convenient
> operator overload, leading to awkward code.

Er, sorry, I don't see the connection between this proposal and C++'s operator overloading. I am merely suggesting that in a method call with 1 parameter you are allowed to omit the following 3 unnecessary characters: . ( )

> Your proposed syntax would "Fortran-ify" Java...
> something I think the language can live without.
>
> Based on the current syntax of Java, I'd expect "add"
> to be a keyword and I don't think the language
> benefits in any way from the addition of the whole
> set of overly specific keywords (add, subtract,
> multiply, divide, root, square, powerof, etc... the
> list goes on and on and on) you would need to cover a
> broad set of cases,

There's no suggestion that this syntax would be restricted to certain keywords. You could use it with any suitable method name. It's merely a simpler method-calling syntax.

> not to mention that it in no way
> simplifies the look or readability of the code.

I'm sorry but I refuse to accept, and I think most programmers would agree, that (say)

a append b

is not simpler and more readable than

a.append(b)

Methinks my mentioning the unmentionable words 'operator overloading' provoked a certain (kneejerk?) reaction.

ianl
Offline
Joined: 2003-06-11

Call it what you will... I think the syntax is horrible and would be a detriment to the language.

darrenix
Offline
Joined: 2004-11-27

is this function readily available in Tiger or earlier? or is it still under dev?