JaroslavTulach: /* Knowing More */ - 2013-09-06 09:08:27

Knowing More

←Older revision Revision as of 09:08, 6 September 2013
Line 40: Line 40:
==== Knowing More ====
==== Knowing More ====
-
Then it comes to question: ''Who knows more?'' As discussed in [[SuperVsInner]] essay in [[Java]] it is safe to assume that ''subclasses know more'' - as such it should be the subclass who handles the ''equals'' call:
+
Then it comes to question: ''Who knows more?'' As discussed in [[SuperVsInner]] essay in [[Java]] it is safe to assume that ''subclasses know more'' - as such it should be the subclass who handles the ''equals'' call. Here is the solution:
<source lang="java">
<source lang="java">

JaroslavTulach at 09:08, 6 September 2013 - 2013-09-06 09:08:05

←Older revision Revision as of 09:08, 6 September 2013
Line 37: Line 37:
This is approach suitable for [[wikipedia:Algebraic_types|algebraic types]], but in [[OOP]] we might want some subclasses of ''Date'' to still be equal to plain ''Date'' instances. For example intervals of length zero may need to be equal to the ''Date'' object with the same beginning ''time''.
This is approach suitable for [[wikipedia:Algebraic_types|algebraic types]], but in [[OOP]] we might want some subclasses of ''Date'' to still be equal to plain ''Date'' instances. For example intervals of length zero may need to be equal to the ''Date'' object with the same beginning ''time''.
 +
 +
==== Knowing More ====
Then it comes to question: ''Who knows more?'' As discussed in [[SuperVsInner]] essay in [[Java]] it is safe to assume that ''subclasses know more'' - as such it should be the subclass who handles the ''equals'' call:
Then it comes to question: ''Who knows more?'' As discussed in [[SuperVsInner]] essay in [[Java]] it is safe to assume that ''subclasses know more'' - as such it should be the subclass who handles the ''equals'' call:
Line 42: Line 44:
<source lang="java">
<source lang="java">
class Date {
class Date {
-
private long time;
+
private final long time;
-
public boolean equals(Object o) {
+
public Date(long time) {
-
if (o instanceof Date) {
+
this.time = time;
-
if (o.getClass() != getClass() && getClass().isAssignableFrom(o.getClass())) {
+
}
-
return o.equals(this); // [1]
+
 
-
} else {
+
@Override
-
return time == ((Date)o).time;
+
public boolean equals(Object o) {
-
}
+
if (o instanceof Date) {
 +
if (o.getClass() != getClass() && getClass().isAssignableFrom(o.getClass())) {
 +
return o.equals(this); // [1]
 +
} else {
 +
return time == ((Date) o).time;
 +
}
 +
}
 +
return false;
}
}
-
return false;
 
-
}
 
}
}
class Interval extends Date {
class Interval extends Date {
-
private int length;
+
private final int length;
-
public boolean equals(Object o) {
+
public Interval(long time, int length) {
-
if (o instanceof Interval) {
+
super(time);
-
if (o.getClass() != getClass() && getClass().isAssignableFrom(o.getClass())) {
+
this.length = length;
-
return o.equals(this); // [1]
+
}
-
} else {
+
 
-
return time == ((Interval)o).time && length == ((Interval)o).length;
+
@Override
-
}
+
public boolean equals(Object o) {
 +
if (o instanceof Interval) {
 +
if (o.getClass() != getClass() && getClass().isAssignableFrom(o.getClass())) {
 +
return o.equals(this); // [1]
 +
} else {
 +
return super.equals(o) && length == ((Interval) o).length;
 +
}
 +
}
 +
return length == 0 && super.equals(o); // [2]
}
}
-
return length == 0 && super.equals(o); // [2]
 
-
}
 
}
}
class SerializableDate extends Date implements java.io.Serializable {
class SerializableDate extends Date implements java.io.Serializable {
 +
public SerializableDate(long time) {
 +
super(time);
 +
}
}
}
-
assert !new Date(323).equals(new Interval(323, 10));
+
assertFalse(new Date(323).equals(new Interval(323, 10)));
-
assert new Date(323).equals(new Interval(323, 0));
+
assertTrue(new Date(323).equals(new Interval(323, 0)));
-
assert new Date(323).equals(new SerializableDate(323));
+
assertTrue(new Date(323).equals(new SerializableDate(323)));
</source>
</source>
The check ''[1]'' makes sure the comparing is always done by subclass. Then the subclass can either do nothing (like the ''SerializableDate'') and inherits working equals from the superclass, or the subclass can use its special knowledge (like ''Interval'' at line ''[2]'') and be equal to super class in some special conditions (here when the ''length'' is zero).
The check ''[1]'' makes sure the comparing is always done by subclass. Then the subclass can either do nothing (like the ''SerializableDate'') and inherits working equals from the superclass, or the subclass can use its special knowledge (like ''Interval'' at line ''[2]'') and be equal to super class in some special conditions (here when the ''length'' is zero).

JaroslavTulach at 08:49, 6 September 2013 - 2013-09-06 08:49:44

←Older revision Revision as of 08:49, 6 September 2013
Line 1: Line 1:
-
Writing equals method in [[OOP]] languages can be tricky. The {{JDK|java/lang|Object}}.equals documentation suggest that the relation should be [[wikipedia:Symmetric_relation|symetric]] but that is hard to enforce. Anyway implementation should at least try. However how should one get ready for subclasses? E.g. make sure instance of following class:
+
Writing [[equals]] method in [[OOP]] languages can be tricky. The {{JDK|java/lang|Object}}.[[equals]] documentation suggests that the relation should be [[wikipedia:Symmetric_relation|symetric]] but that is hard to enforce. Anyway implementation should at least try. However how should one handle (potentially unknown) subclasses? E.g. make sure instance of following class:
<source lang="java">
<source lang="java">
Line 36: Line 36:
</source>
</source>
-
This is approach suitable for [[wikipedia:Algebraic_types|algebraic types]], but in [[OOP]] we might want intervals of length zero to be equal to the ''Date'' object with the same beginning. Then it comes to question: ''Who knows more?'' (also discussed in [[SuperVsInner]] essay). In [[Java]] it is safe to assume that ''subclasses know more'' - as such it should be the subclass who handles the ''equals'':
+
This is approach suitable for [[wikipedia:Algebraic_types|algebraic types]], but in [[OOP]] we might want some subclasses of ''Date'' to still be equal to plain ''Date'' instances. For example intervals of length zero may need to be equal to the ''Date'' object with the same beginning ''time''.
 +
 
 +
Then it comes to question: ''Who knows more?'' As discussed in [[SuperVsInner]] essay in [[Java]] it is safe to assume that ''subclasses know more'' - as such it should be the subclass who handles the ''equals'' call:
<source lang="java">
<source lang="java">
class Date {
class Date {
-
long time;
+
private long time;
public boolean equals(Object o) {
public boolean equals(Object o) {
Line 55: Line 57:
class Interval extends Date {
class Interval extends Date {
-
int length;
+
private int length;
public boolean equals(Object o) {
public boolean equals(Object o) {

JaroslavTulach at 08:43, 6 September 2013 - 2013-09-06 08:43:31

←Older revision Revision as of 08:43, 6 September 2013
Line 44: Line 44:
public boolean equals(Object o) {
public boolean equals(Object o) {
if (o instanceof Date) {
if (o instanceof Date) {
-
if (o.getClass() == Date.class) {
+
if (o.getClass() != getClass() && getClass().isAssignableFrom(o.getClass())) {
-
return ((Date)o).time == time;
+
return o.equals(this); // [1]
} else {
} else {
-
return o.equals(this);
+
return time == ((Date)o).time;
}
}
}
}
Line 59: Line 59:
public boolean equals(Object o) {
public boolean equals(Object o) {
if (o instanceof Interval) {
if (o instanceof Interval) {
-
if (o.getClass() == Interval.class) {
+
if (o.getClass() != getClass() && getClass().isAssignableFrom(o.getClass())) {
-
return length == ((Interval)o).length;
+
return o.equals(this); // [1]
} else {
} else {
-
return o.equals(this);
+
return time == ((Interval)o).time && length == ((Interval)o).length;
}
}
-
} else {
 
-
return length == 0 && super.equals(o);
 
}
}
 +
return length == 0 && super.equals(o); // [2]
}
}
}
}
Line 77: Line 76:
assert new Date(323).equals(new SerializableDate(323));
assert new Date(323).equals(new SerializableDate(323));
</source>
</source>
 +
 +
The check ''[1]'' makes sure the comparing is always done by subclass. Then the subclass can either do nothing (like the ''SerializableDate'') and inherits working equals from the superclass, or the subclass can use its special knowledge (like ''Interval'' at line ''[2]'') and be equal to super class in some special conditions (here when the ''length'' is zero).

JaroslavTulach: New page: Writing equals method in OOP languages can be tricky. The {{JDK|java/lang|Object}}.equals documentation suggest that the relation should be symetric bu... - 2013-09-06 08:30:18

New page: Writing equals method in OOP languages can be tricky. The {{JDK|java/lang|Object}}.equals documentation suggest that the relation should be symetric bu...

New page

Writing equals method in [[OOP]] languages can be tricky. The {{JDK|java/lang|Object}}.equals documentation suggest that the relation should be [[wikipedia:Symmetric_relation|symetric]] but that is hard to enforce. Anyway implementation should at least try. However how should one get ready for subclasses? E.g. make sure instance of following class:

<source lang="java">
class Date {
long time;

public boolean equals(Object o) {
if (o instanceof Date) {
return ((Date)o).time == time;
}
return false;
}
}
</source>

does not return true when compared to a subclass like:

<source lang="java">
class Interval extends Date {
int length;
}

assert !new Date(323).equals(new Interval(323, 10));
</source>

One way to do it is to restrict the equals only to own type. E.g.:

<source lang="java">
public boolean equals(Object o) {
if (o != null && o.getClass() == Date.class) {
return ((Date)o).time == time;
}
return false;
}
}
</source>

This is approach suitable for [[wikipedia:Algebraic_types|algebraic types]], but in [[OOP]] we might want intervals of length zero to be equal to the ''Date'' object with the same beginning. Then it comes to question: ''Who knows more?'' (also discussed in [[SuperVsInner]] essay). In [[Java]] it is safe to assume that ''subclasses know more'' - as such it should be the subclass who handles the ''equals'':

<source lang="java">
class Date {
long time;

public boolean equals(Object o) {
if (o instanceof Date) {
if (o.getClass() == Date.class) {
return ((Date)o).time == time;
} else {
return o.equals(this);
}
}
return false;
}
}

class Interval extends Date {
int length;

public boolean equals(Object o) {
if (o instanceof Interval) {
if (o.getClass() == Interval.class) {
return length == ((Interval)o).length;
} else {
return o.equals(this);
}
} else {
return length == 0 && super.equals(o);
}
}
}

class SerializableDate extends Date implements java.io.Serializable {
}

assert !new Date(323).equals(new Interval(323, 10));
assert new Date(323).equals(new Interval(323, 0));
assert new Date(323).equals(new SerializableDate(323));
</source>