Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define default method on abstract type in Julia

How can I provide a default implementation of a method in Julia in a separate module? If the abstract type lives in the same module I have no problem, for example, this works just as I expect:

abstract type Foo end

howdy(x::Foo)::Union{String, Nothing} = nothing

struct Bar <: Foo end

function howdy(x::Bar)::Union{String, Nothing}
    "I'm a Bar!"
end

struct Baz <: Foo end

if abspath(PROGRAM_FILE) == @__FILE__
    bar = Bar()
    s = howdy(bar)
    if isa(s, String)
        println(s)
    end
    baz = Baz()
    t = howdy(baz)
    if isa(t, String)
        println(t)
    end
end

However, once I put the abstract type in its own module, it no longer works:

In src/qux.jl, I put:

module qux

abstract type Foo end

howdy(x::Foo)::Union{String, Nothing} = nothing

export Foo, howdy
end # module

and then in reproduce.jl I put:

using qux

struct Bar <: Foo end

function howdy(x::Bar)::Union{String, Nothing}
    "I'm a Bar!"
end

struct Baz <: Foo end

if abspath(PROGRAM_FILE) == @__FILE__
    bar = Bar()
    s = howdy(bar)
    if isa(s, String)
        println(s)
    end
    baz = Baz()
    t = howdy(baz)
    if isa(t, String)
        println(t)
    end
end

Then I get:

julia --project=. reproduce.jl
I'm a Bar!
ERROR: LoadError: MethodError: no method matching howdy(::Baz)
Closest candidates are:
  howdy(::Bar) at ~/qux/reproduce.jl:5
Stacktrace:
 [1] top-level scope
   @ ~/qux/reproduce.jl:18
in expression starting at ~/qux/reproduce.jl:11
like image 909
user14717 Avatar asked Oct 30 '21 20:10

user14717


People also ask

What are abstract types in Julia?

Abstract types allow the construction of a hierarchy of types, providing a context into which concrete types can fit. This allows you, for example, to easily program to any type that is an integer, without restricting an algorithm to a specific type of integer.

Does Julia have methods?

Method TablesEvery function in Julia is a generic function. A generic function is conceptually a single function, but consists of many definitions, or methods. The methods of a generic function are stored in a method table.

What is mutable struct in Julia?

type and immutable are valid up to julia 0.6, mutable struct and struct are the names of the same objects in julia 0.6 and forward. mutable in mutable struct means that the fields can change - which is actually fairly rarely used so being immutable is the default. mutable struct 's are slower than struct s.

Does Julia have inheritance?

Julia is not an object-oriented language in the traditional sense in that there is no inheritance of structure. If multiple types need to share structure, you have several options: Write out the common fields manually.

What are the abstract types in Julia?

Julia also has a predefined abstract "bottom" type, at the nadir of the type graph, which is written as Union {}. It is the exact opposite of Any: no object is an instance of Union {} and all types are supertypes of Union {}. Let's consider some of the abstract types that make up Julia's numerical hierarchy:

What are method type parameters in Julia?

This kind of definition of function behavior by dispatch is quite common – idiomatic, even – in Julia. Method type parameters are not restricted to being used as the types of arguments: they can be used anywhere a value would be in the signature of the function or body of the function.

What are the properties of a datatype in Julia?

They have names. They have explicitly declared supertypes. They may have parameters. Because of these shared properties, these types are internally represented as instances of the same concept, DataType, which is the type of any of these types: julia> typeof (Real) DataType julia> typeof (Int) DataType

How to type-annotate variables in Julia?

Type-annotating variables in Julia can be done using the ::operator. This operator confirms that the value on the left is the same type as the value on the right. Syntax: <expr>::<type> where, expr:It can be an expression for computing a value or an assignment statement for a variable or an declaration of a variable.


1 Answers

Your problem is explained here in the Julia manual.

The issue is that in your code, as you can see here:

julia> module qux

       abstract type Foo end

       howdy(x::Foo)::Union{String, Nothing} = nothing

       export Foo, howdy
       end # module
Main.qux

julia> using .qux

julia> struct Bar <: Foo end

julia> function howdy(x::Bar)::Union{String, Nothing}
           "I'm a Bar!"
       end
howdy (generic function with 1 method)

julia> methods(howdy)
# 1 method for generic function "howdy":
[1] howdy(x::Bar) in Main at REPL[4]:1

julia> methods(qux.howdy)
# 1 method for generic function "howdy":
[1] howdy(x::Foo) in Main.qux at REPL[1]:5

You have two distinct howdy functions each having one method. One is deifned in qux module, and the other in the Main module.

What you want to do is to add a method to howdy function defined in qux module. I would typically do it by qualifying the exported function name with module name, as this is a clear way to signal what you want to do:

julia> module qux

       abstract type Foo end

       howdy(x::Foo)::Union{String, Nothing} = nothing

       export Foo, howdy
       end # module
Main.qux

julia> using .qux

julia> struct Bar <: Foo end

julia> function qux.howdy(x::Bar)::Union{String, Nothing}
           "I'm a Bar!"
       end

julia> methods(qux)
# 0 methods:

julia> methods(howdy)
# 2 methods for generic function "howdy":
[1] howdy(x::Bar) in Main at REPL[4]:1
[2] howdy(x::Foo) in Main.qux at REPL[1]:5

as you can see now you have a single howdy function having two methods and all will work as you want.

like image 112
Bogumił Kamiński Avatar answered Oct 23 '22 18:10

Bogumił Kamiński