5

I have heard julia has dispatch on values for symbols, and so I use Val{:MySymbol}.

But this doesn't seem to work:

julia> foo(x) = "other"
foo (generic function with 1 method)

julia> foo(x::Val{:zinger}) = "It was zinger"
foo (generic function with 2 methods)

julia> foo(:zinger)
"other"

Why isn't it outputting "It was zinger"?

Frames Catherine White
  • 27,368
  • 21
  • 87
  • 137

1 Answers1

12

See the Docs

Dispatching on values isn't magic. It uses the exact same mechanics as for dispatching on parametric types. So you need to pass in a instance parametric type which has that value as a type parameter if you want to dispatch on it.

In your question Val is the parametric type -- and it exists just for this kind of thing.

So you need to have written:

julia> foo(Val{:zinger}())
"It was zinger"

If you wanted you could write an overload of foo to automatically wrap up its arguments into a type parameter

julia> foo(x::Symbol) = foo(Val{x}())
foo (generic function with 3 methods)

julia> foo(:zinger)
"It was zinger"

However, this will cause a dynamic dispatch.

julia> @code_lowered foo(:zinger)
CodeInfo(:(begin
        nothing
        return (Main.foo)(((Core.apply_type)(Main.Val, x))())
    end))

vs the fully realized at compile-time solution:

julia> @code_lowered foo(Val{:zinger}())
CodeInfo(:(begin
        nothing
        return "It was zinger"
    end))
Frames Catherine White
  • 27,368
  • 21
  • 87
  • 137
  • So at compile time there will be no runtime dynamic dispatch overhead? Is this the recommended way of implementing a `getproperty`? – a06e Oct 03 '18 at 21:49
  • Which version of Julia are you referring here? Since after version 1.0.0, `Val{:zinger}()` can be simplified by `Val(:zinger)` since `Val(c)` returns `Val{c}()`. – Jadim Nov 24 '18 at 07:58
  • @nix `Val(:zinger)` is not type-stable. In 1.0 it might though constant propergation be optimised into something type stable (namely `Val{:zinger}()`) But I personally prefer to write `Val{:zinger}()` which is only 2 more characters and is obviously type-stable. I wouldn't myself considering saving 2 characters and depending on compiler optimisations to be a simplification. – Frames Catherine White Nov 24 '18 at 18:39
  • @LyndonWhite Hi, could you have a word more on why you think `Val(:zinger)` is not type-stable? Is it not type-stable in an older Julia version? – Jadim Nov 25 '18 at 07:54
  • 1
    It isn't type-stable. It logically can not be type stable. By definition to be type-stable the output type (`Val{:zinger}`) must depend only on the input type (in this case `Symbol`). Since different inputs (still with type `Symbol` give output types that are different (in their type-parameter)), is is thus not type-stable. You can check this in the REPL too, `@code_warntype Val{:zinger}()`, vs `@code_warntype Val(:zinger)`. But as I said, I think in practice the constant propergation will result in this being optimised away. So it becomes a matter of preference/style. – Frames Catherine White Nov 25 '18 at 21:46