How to overload the ==?

I defined the Base.isequal function, but it do not work.

               _       
   _       _ _(_)_     |  A fresh approach to technical computing            
  (_)     | (_) (_)    |  Documentation: https://docs.julialang.org          
   _ _   _| |_  __ _   |  Type "?help" for help.                             
  | | | | | | |/ _` |  |                      
  | | |_| | | | (_| |  |  Version 0.5.2 (2017-05-06 16:34 UTC)               
 _/ |\__'_|_|_|\__'_|  |  Official http://julialang.org/ release             
|__/                   |  x86_64-pc-linux-gnu 

julia> type Foo foo::Int end                  

julia> type Bar bar::Float64 end              

julia> f = Foo(4)      
Foo(4)                 

julia> b = Bar(4.0)    
Bar(4.0)               

julia> function Base.isequal(a::Foo, b::Bar)  
           Float64(a.foo) == b.bar            
       end             

julia> isequal(f, b)   
true                   

julia> f == b          
false                  

isequal falls back to ==

julia> @code_lowered isequal(f, b)
CodeInfo(:(begin 
        nothing
        return x == y
    end))

you can do Base.:(==)(a::Foo, b::Bar) = ...

see https://docs.julialang.org/en/stable/stdlib/base/#Base.isequal-Tuple{Any,Any} for more info

1 Like

Thanks, this works.

I need to redefine Base.:(==) separately to make == work.

you likely don’t have to touch isequal at all, unless you want it to behave differently from ==.

1 Like

Hello - I realize that I am resurrecting a long dead post, but I tried to follow the documentation link … and it was dead.

I had been trying to understand this method declaration in Clang.jl, and landed on this question from a web search. Can someone explain why the function needed to have the prefix “Base.:”?

Thx

If you define an unspecified == method, what you’re actually defining is CURRENTMODULE.:(==). This is not the == used except in CURRENTMODULE or modules that explicitly import this version. If you want to affect the behavior of == in other modules, you need to modify the version of == used in those places. In most cases, this is Base.:(==).

This is to avoid method conflicts. It may not appear to make much sense for operators like ==, but it this is very important for other functions. If there was only one shared namespace, method collisions would happen and it would be very difficult to compose functionality from different modules.

1 Like

@mikmoore, thanks for the reply - and forgive the obtuseness of the question (I am rather new to Julia), but why is the : necessary? From the documentation on modules, I would have figured that it would have been something like CURRENTMODULE.==, rather than CURRENTMODULE.:(==)?

I believe the :() is required for operators for syntactic reasons. Otherwise it parses Base.==(1,2) as Base .== (1,2). Then it gets upset about trying to broadcast a module Base. Even if we defined broadcasting on modules, it would then try to evaluate (Base == 1, Base == 2) which still isn’t what you were trying to do.

To avoid this syntax ambiguity, it’s necessary to use MODULE.:(==) for operators.

Since it’s very tedious to specify modules for operators, it’s not very common to make module-local versions. Rather, people mostly add methods to the Base versions (e.g., Base.:(==)) instead. Just be careful to only define external module (like Base) functions on types you have created in the current module you’re working in, or else you can run into the problems of type piracy.

3 Likes

For anyone looking for a complete example, here’s an example showing the full syntax.

mutable struct MyStruct
    df::DataFrame
end

function Base.:(==)(left:MyStruct, right:MyStruct)
    return left.df == right.df
end

Someone already mentioned something about this, but perhaps useful to add something.

The alternative syntax for the function might have been this:

function Base.==(left, right)
    ...
end

But it isn’t, and this doesn’t work.

Remember that :(thing) is equivalent (approximately) to

quote
    thing
end

This is related to metaprogramming, or at least disambiguating between writing something which is supposed to be interpreted in a metaprogramming context. (Sorry, this isn’t really a very good explanation.) But it’s perhaps useful to show something…

julia> Base.:(==)
== (generic function with 223 methods)

julia> typeof(Base.:(==))
typeof(==) (singleton type of function ==, subtype of Function)

julia> Base.==
       ^C

julia> Base.unique
unique (generic function with 7 methods)

julia> typeof(Base.unique)
typeof(unique) (singleton type of function unique, subtype of Function)

julia> typeof(Base.:(unique))
typeof(unique) (singleton type of function unique, subtype of Function)

Sorry I can’t say more about this, or provide a more clear or detailed explaination. Base.== seems to be interpreted as something a bit different to Base.functionName, such as Base.unique.

The reason is that .<operator> is parsed as a vectorized “dot operator”, so that Base.==(x) is parsed as Base .== x:

julia> Foo = x = [1,2,3];

julia> Foo.==(x)
3-element BitVector:
 1
 1
 1

julia> Foo .== x
3-element BitVector:
 1
 1
 1

So, an alternative “quoted” syntax is required, e.g. Base.:+, Base.:(==), etcetera.

1 Like

Yeah, that will be it. Couldn’t tell if that was what was happening or not. Thanks