Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make isequal compare identity by default #90

Closed
JeffBezanson opened this issue Jun 29, 2011 · 6 comments
Closed

make isequal compare identity by default #90

JeffBezanson opened this issue Jun 29, 2011 · 6 comments
Assignees

Comments

@JeffBezanson
Copy link
Member

See this discussion:

http://groups.google.com/group/julia-math/browse_thread/thread/d9b27f68ffe6e85a/bdf8c3662affd183

We want hash tables to hash by object identity by default. In general, these definitions don't seem quite right:

isequal{T}(x::T, y::T) = (x==y)
isequal(x, y) = isequal(promote(x,y)...)
@StefanKarpinski
Copy link
Member

Another, related issue I just though of is comparison of mutable types by == vs. isequal. Lets say you have

type Foo; x; end

a = Foo(1)
b = Foo(1)

Based on what we've discussed before, we should have:

julia> isequal(a,b)
false

since mutable objects are by default compared by identity because you can change a.x or b.x or both after hashing, e.g. However, shouldn't we at the same time have a == b, actually recursively comparing their values? So you could have neither == nor === be stricter than the other. Maybe a different name for isequal would be good.

@JeffBezanson
Copy link
Member Author

I've come to the conclusion that isequal is the more fundamental predicate: it always returns boolean, and should mean that two values "look similar" (e.g. they would print the same). Arguably isequal(2, 2.0) should be false. isequal defaults to is.

== then defaults to isequal, but has some extra behaviors for certain types: it does promotion for numbers, does IEEE comparison of floats, and gives boolean arrays for array arguments.

@StefanKarpinski
Copy link
Member

I had come to a similar conclusion regarding show and equality, but from the opposite direction: as a rule of thumb, show should satisfy the following identity:

eval(show(x)) == x

However, I don't think we can reasonably require the same thing with isequal — because of mutability. Take my Foo example. Do you agree that isequal(a,b) should be true?

But maybe we're not disagreeing after all. As I understand it, here are some reasonable implications:

is(a,b) ==>
isequal(a,b) ==>
show(a) == show(b) ==>
a == b

The question is which ones should "collapse" to equivalence. The isequal(a,b) ==> show(a) == show(b) implication, in particular, implies that 2 and 2.0 cannot hash the same since they don't show the same in the repl.

@JeffBezanson
Copy link
Member Author

They can actually hash the same; it would be valid for every value to have the same hash, just suboptimal.

One thing that hasn't been stated explicitly here is that we currently don't have a function that compares generic structs recursively (for arbitrary objects, we only have is and user-defined equality predicates). I'm not sure such a function ever makes sense.

isequal(a,b) ==> a==b is not true, since isequal(NaN,NaN) is true, but NaN==NaN is false.

One of the few constraints on == I can think of is that people will use it for numerical equality. This baggage prevents == from being a more "programmerish" thing satisfying identities like the show identity.

This is why we need to forget about ==, and design equality without it. Then at the last minute, we add == as a strange thing that is usually "reasonable" but adds in behaviors people want for numbers and arrays.

To answer your question, I don't think isequal(a,b) in the Foo case "ought" to be true. It's up to whoever defined Foo to define equality. For some types only is makes sense, and some types like Complex should be compared recursively. The only question for us is what the default should be.

@StefanKarpinski
Copy link
Member

To answer your question, I don't think isequal(a,b) in the Foo case "ought" to be true. It's up to whoever defined Foo to define equality. For some types only is makes sense, and some types like Complex should be compared recursively. The only question for us is what the default should be.

What I was getting at was that I think the default behavior should be this:

isequal(a,b) = is(a,b)
isequal(a::Immutable,b::Immutable) = # compare recursively.

@JeffBezanson
Copy link
Member Author

Oh, ok, I totally agree with that. And in the meantime, until we have actual immutable objects, types like Complex that should be immutable can define their own isequal as appropriate.

I think what we need to do is change most of our == definitions to isequal, and change the top of operators.j to say

==(x, y) = isequal(x, y)
isequal(a,b) = is(a,b)

@ghost ghost assigned JeffBezanson Jul 1, 2011
JeffBezanson added a commit that referenced this issue Jul 1, 2011
isequal() is the primitive comparison function.
  . it defaults to is()
  . is generally only true for arguments of the same type

types with "value type" semantics should define isequal and hash appropriately

subtypes of Number may define == instead of isequal for aesthetics

== defaults to isequal(). only define it for number-like things where
  some special behavior is needed (e.g. type promotion, IEEE-754, etc.)
MichaelHatherly added a commit to MichaelHatherly/julia that referenced this issue May 12, 2016
The docstring for `llvmcall` was bound to a keyword rather than
the actual intrinsic `Core.Intrinsics.llvmcall`.

This produced the following odd behaviour when trying to find the docs:

    help?> llvmcall

    ... docs ...

    julia> llvmcall
    ERROR: UndefVarError: llvmcall not defined

    help?> Base.llvmcall

    ... no docs ...

    julia> Base.llvmcall
    (intrinsic function JuliaLang#90)
MichaelHatherly added a commit to MichaelHatherly/julia that referenced this issue May 13, 2016
The docstring for `llvmcall` was bound to a keyword rather than
the actual intrinsic `Core.Intrinsics.llvmcall`.

This produced the following odd behaviour when trying to find the docs:

    help?> llvmcall

    ... docs ...

    julia> llvmcall
    ERROR: UndefVarError: llvmcall not defined

    help?> Base.llvmcall

    ... no docs ...

    julia> Base.llvmcall
    (intrinsic function JuliaLang#90)
StefanKarpinski pushed a commit that referenced this issue Feb 8, 2018
LilithHafner pushed a commit to LilithHafner/julia that referenced this issue Oct 11, 2021
Added weighted median function and tests
Keno pushed a commit that referenced this issue Oct 9, 2023
Small fixes to breakpoint operation
udesou pushed a commit to udesou/julia that referenced this issue Oct 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants