How to distinguish different objects in the same struct using Symbol in Julia?

97 Views Asked by At

As mentioned in the title, I want to use multiple-dispatch to assign different behaviors of the same struct, distinguished by Symbol. The struct can be constructed as follows:

struct AbstractAlgorithm
    algorithmName::String
    algorithmSymbol::Symbol

    function AbstractAlgorithm(algorithmName::String)
        if algorithmName ∉ ("Value Iteration", "Policy Iteration")
            error("Given algorithm $algorithmName not defined yet.")
        elseif algorithmName=="Value Iteration"
            new(algorithmName, Symbol("vIter"))
        elseif algorithmName=="Policy Iteration"
            new(algorithmName, Symbol("pIter"))
        end
    end  
end

And I wanted to distinguish the same struct using different symbols in a function, such as:

function A(a::AbstractAlgorithm with Symbol vIter) = do A1
function A(a::AbstractAlgorithm with Symbol pIter) = do A2

How should I design function A using multiple-dispatch?

3

There are 3 best solutions below

0
On BEST ANSWER

I am adding as an answer a small comment to what @Giovanni proposed since it is too long (+ some minor changes to your code).

If you want to use a parametric type (and not, as @DNF proposed a type hierarchy) you can just write:

struct Algorithm{T}
    algorithmName::String

    function Algorithm(algorithmName::AbstractString)
        algorithmName == "Value Iteration" && return new{:vIter}(algorithmName)
        algorithmName == "Policy Iteration" && return new{:pIter}(algorithmName)
        error("Given algorithm $algorithmName not defined yet.")
    end
end

function A(a::Algorithm{:pIter})
    # ...
end

function A(a::Algorithm{:vIter})
    # ...
end

The point is that Symbol can be used as type parameter, so you do not have to wrap it in Val.

2
On

This seems like a highly unusual and un-idiomatic approach, since Julia natively supports multiple dispatch. Also, AbstractNN is a naming convention for abstract types, while you are using it for a concrete type.

Why not instead use dispatch:

abstract type AbstractAlgorithm end

struct ValueIteration <: AbstractAlgorithm end

struct PolicyIteration <: AbstractAlgorithm end

and then implement your wanted behaviors based on the types of your algorithm objects:

A(::ValueIteration) = A1() 
A(::PolicyIteration) = A2() 
0
On

One solution could be using Val

struct AbstractAlgorithm{T}
    algorithmName::String

    function AbstractAlgorithm(algorithmName::String)
        if algorithmName ∉ ("Value Iteration", "Policy Iteration")
            error("Given algorithm $algorithmName not defined yet.")
        elseif algorithmName=="Value Iteration"
            new{Val{:vIter}}(algorithmName)
        elseif algorithmName=="Policy Iteration"
            new{Val{:pIter}}(algorithmName)
        end
    end
end

function A(a::AbstractAlgorithm{Val{:pIter}})
    A1
end

function A(a::AbstractAlgorithm{Val{:vIter}})
    A2
end