How to extract the Type of a generic struct and use it for pattern matching?

I’m a novice, someone could help?
here’s the demo code I want:

struct Foo{T <: Real}
	cont::String    
end

bar = Foo{Int}("test")

typeof(bar) == Foo{Int} # true

# is there a package can do pattern match like this?
@match typeof(bar) begin
    Foo{T} => @match T begin
        Float => # do something
        Int => # do something
    end

    Foo1{T} => ...
end

May be I should convert Foo{T} to string then extract the substring T ! I can use string for pattern match! This may make sense!

You can access the T field within a function using a where clause:

function do_stuff(foo::Foo{T}) where {T}
  println("The parameter type is: $T")
end

and you can directly compare T in an if statement to choose different behaviors based on the particular type.

However, it’s more common in Julia to use multiple dispatch to implement this kind of type-based switching. For example, you might do:

function do_stuff(foo::Foo{Float64})  # only applies to exactly Foo{Float64}
  do_something()
end

function do_stuff(foo::Foo{T}) where {T <: Integer} # applies for any kind of integer
  do_something()
end

function do_stuff(foo::Foo) # applies to any `Foo`
  do_something()
end

Julia will always pick the most specific matching method, so do_stuff(Foo{Int}()) will call the T <: Integer version, while do_stuff(Foo{String}()) will call the generic do_stuff(foo::Foo) method.

2 Likes

No, don’t do that :slightly_smiling_face:

Converting types to strings is almost never useful or necessary in Julia. You can easily get the actual type T with a where clause:

julia> function get_parameter(foo::Foo{T}) where {T}
        T
      end
get_parameter (generic function with 1 method)

julia> f = Foo{Int}()
Foo{Int64}()

julia> get_parameter(f)
Int64

julia> g = Foo{Float64}()
Foo{Float64}()

julia> get_parameter(g)
Float64
2 Likes

Thank you very much sir! Your solution is really help. But I’m in a situation:

abstract type Term end

abstract type AbstractStatement <: Term end
abstract type S1 <: AbstractStatement end
abstract type S2 <: AbstractStatement end

abstract type AbstractCompound <: Term end
abstract type C1 <: AbstractCompound end
abstract type C2 <: AbstractCompound end

struct Statement{T <: AbstractStatement} <: Term
    cont::String
end

struct Compound{T <: AbstractCompound} <: Term
    cont::String
end

function foo(t::Term)
	# t could be Statement or Compound
    @match typeof(t) begin
    	# T could be S1,S2 or C1,C2
        Statement{T} => @match T begin
            S1 => # do something
            S2 => # do something
        end
        Compound{T} => @match T begin
            C1 => # do something
            C2 => # do something
        end
    end
end

forgive me for my lazy and greedy. I want to do more things but less code. :joy:

If you don’t want to write separate methods, you are free to test if t isa S1; #stuff; elseif t isa C1 inside foo. The branches should compile away.

1 Like

You can just use dispatch here too, i.e:

foo(x::S1) = ...
foo(x::S2) = ...
foo(x::C1) = ...
foo(x::C2) = ...

(FYI, it’s generally preferred to post code as text inside triple quotes (```) instead of as screenshots, because it saves a lot of bandwidth and it’s also much easier to copy your code in order to help you.)

2 Likes

yes, I should write separate functions!

yeah, I should practice more to get used to Multiple Dispatch!

and, I will use markdown to post my questions.

Thank you all very much! This may be a stupid question, but you are really nice people!