On Aug 3, 5:54 pm, Brian Marick <[email protected]> wrote:
> In Midje, I have reason to create a type Metaconstant whose instances are 
> "equal" to a symbol with the same name. Here's the relevant bits of the 
> definition:
>
>     (deftype Metaconstant [name storage]
>       Object
>       (equals [this that]
>              (if (instance? (class this) that)
>                (= (.name this) (.name that))
>                (= (.name this) that)))
>
>       clojure.lang.IPersistentCollection
>       (equiv [this that]
>              (println "equiv is called with" (type this) (type that))
>              (.equals this that)))
>
> That's fine when a Metaconstant is compared to a symbol, but I thought I'd 
> have to engage in hackery when a symbol is compared to a Metaconstant. That 
> is:
>
>     (println "= symbol metaconstant?")
>     (println (= '...name... (Metaconstant. '...name... {}))) ; expect false
>     (println "= metaconstant symbol?")
>     (println (= (Metaconstant. '...name... {}) '...name... )) ; expect true
>
> Surprisingly, both directions produce true. That's because the order in which 
> `.equiv` is called doesn't seem to depend on the order of arguments to `=`:
>
>     = symbol metaconstant?
>     equiv is called with midje.ideas.t-m.Metaconstant clojure.lang.Symbol
>     true
>     = metaconstant symbol?
>     equiv is called with midje.ideas.t-m.Metaconstant clojure.lang.Symbol
>    true
>
> Why is .equiv called with reordered arguments? And can I depend on that 
> behavior going forward?
>
> I see this behavior with 1.2.0, 1.2.1, and 1.3.0-beta1.

clojure.lang.Util:

static public boolean equiv(Object k1, Object k2){
        if(k1 == k2)
                return true;
        if(k1 != null)
                {
                if(k1 instanceof Number && k2 instanceof Number)
                        return Numbers.equal((Number)k1, (Number)k2);
                else if(k1 instanceof IPersistentCollection || k2 instanceof
IPersistentCollection)
                        return pcequiv(k1,k2);
                return k1.equals(k2);
                }
        return false;
}

static public boolean pcequiv(Object k1, Object k2){
        if(k1 instanceof IPersistentCollection)
                return ((IPersistentCollection)k1).equiv(k2);
        return ((IPersistentCollection)k2).equiv(k1);
}

It strives to make sure that, if only one operand is a
PersistentCollection, then that thing's .equiv method is called when
testing with =. This makes sense, because all objects have a .equals
method, but only PCs have .equiv.

But if you wanted to compare a MetaConstant with, say, a hashmap (or
another MC), the runtime would not mess with the argument order.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to