equal? and primitive arrays
Jamison Hope
jrh@theptrgroup.com
Sat Oct 8 02:33:00 GMT 2011
On Oct 7, 2011, at 8:02 PM, Per Bothner wrote:
> On 10/07/2011 04:06 PM, Jamison Hope wrote:
>> I was a little surprised today to discover that
>> (equal? (byte[] 1 2) (byte[] 1 2))
>> returns #f. Obviously Java arrays are outside the scope of the
>> Scheme report, but it would seem to be in the spirit of equal?
>> for that to return true. Would it be worthwhile to write a patch
>> for IsEqual.java to defer to java.util.Arrays#equals() and
>> java.util.Arrays#deepEquals() in the case of arrays?
>
> Well, it's reasonable but not correct. Using Arrays#equals is fine
> for primitive array types, but not object arrays. The main problem
> with Arrays#deepEqual is the "base case" is Object#equals, but for
> us the base case should be IsEqual#apply. However, doing deepEqual
> by hand is easy enough - just use the same logic as FVector.
Ah, of course.
> A bigger (but unrelated) problem is that R6RS (and draft R7RS) require
> that equals "must always terminate, even if its arguments contain
> cycles."
Indeed. That's a problem for any containers (arrays, lists, vectors,
etc)
that can directly or indirectly contain themselves.
> The basic cycle-safe equal? implementation is as follows:
> Maintain a mapping (Object,Object)->boolean for previously-seen calls.
> (This mapping uses the System.identityHashCode on both operands.)
>
> recursiveEquals(Object arg1, Object arg2, Map2 seen) {
> if (arg1 == arg2)
> return true;
> if (arg1 == null || arg2 == null)
> return false;
> Boolean wasSeen = seen.lookup(arg1, arg2);
> if (wasSeen != null)
> return wasSeen.booleanValue();
> seen.set(arg1, arg2, Boolean.TRUE); // protect against cycles
> boolean r = coreEquals(arg1, arg2, seen);
> seen.set(arg1, arg2, Boolean.valueOf(r));
> return r;
> }
>
> One might try to be clever so the seen table is only allocated
> if we recursing, in some way or other.
>
> The Map2 data structure is somewhat unusual. One possibility is
> to just use an
> IdentityHashMap<Object,IdnetityHashMap<Object,Boolean>>.
> A custom hash table has hash is calculated as
> (System.identityHashCode(arg1) ^ System.identityHashCode(arg2))
> could be more efficient.
I'll tackle the primitive arrays for now and think about how to handle
cycles as a separate patch.
--
Jamison Hope
The PTR Group
www.theptrgroup.com
More information about the Kawa
mailing list