# Base.getproperty via Val types

**URL:** https://discourse.julialang.org/t/base-getproperty-via-val-types/43195
**Category:** General Usage
**Created:** [July 16, 2020, 8:38pm UTC](https://discourse.julialang.org/t/base-getproperty-via-val-types/43195 "2020-07-16T20:38:41Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![jackf](https://avatars.discourse-cdn.com/v4/letter/j/b4bc9f/32.png) [@jackf](https://discourse.julialang.org/u/jackf)
#### Post date: [July 16, 2020, 8:38pm UTC](https://discourse.julialang.org/t/base-getproperty-via-val-types/43195/1 "2020-07-16T20:38:41Z")

</div>

I’m familiar with Base.getproperty, and often structure it as a big list of if statements, with a fallback to getfield. Sometimes, though, having to define all the behaviour in one place can be a bit annoying.

I thought of doing this instead:

```julia
Base.getproperty(x::MyType, s::Symbol) = Base.getproperty(x, Val(s))
Base.getproperty(x::MyType, ::Val{s}) where s = getfield(x, s)
Base.getproperty(x::MyType, ::Val{:foo}) = 123
Base.getproperty(x::MyType, ::Val{:bar}) = 342

```

It seems to work, and seems to be type-stable. Before I get carried away, are there any obvious drawbacks to this approach?

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [July 16, 2020, 9:14pm UTC](https://discourse.julialang.org/t/base-getproperty-via-val-types/43195/2 "2020-07-16T21:14:58Z")

</div>

The obvious drawback is that this will be super, super slow if a user does something like

```julia
[getproperty(x, s) for s in [:foo, :bar]]

```

That is, if the symbol value isn’t a compile time constant, you’re in for a bad time. But when you write things like `MyType().foo` or whatever, the symbol `:foo` is a compile time constant, so the literal syntax should almost always be fine.

---

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [July 16, 2020, 10:27pm UTC](https://discourse.julialang.org/t/base-getproperty-via-val-types/43195/3 "2020-07-16T22:27:38Z")

</div>

I do things like this all the time for high level performance non-critical code. My perspective is that type stability SHOULD be broken when convenient. Otherwise we might as well write C/C++ etc

---

<div class="post-metadata">

### Author: ![favba](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/favba/32/2735_2.png) [@favba](https://discourse.julialang.org/u/favba)
#### Post date: [July 17, 2020, 12:31am UTC](https://discourse.julialang.org/t/base-getproperty-via-val-types/43195/4 "2020-07-17T00:31:32Z")

</div>

Isn’t that also true when the “usual” way of defining `geproperty` is used?  
I mean, It will also be type unstable…

The only difference that I see is that in the OP’s method dynamic dispatch will be used to figure out which method to call, while with the “usual” way that is done thourgh if-else branches. (Both cases with type unstable results)

Is dynamic dispatch much more expensive than if-else branches? I don’t know…

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [July 17, 2020, 12:38am UTC](https://discourse.julialang.org/t/base-getproperty-via-val-types/43195/5 "2020-07-17T00:38:23Z")

</div>

> Is dynamic dispatch much more expensive than if-else branches? I don’t know…

big time. With the vals you’d be looking at microseconds for even the most trivial overloads.

```julia
struct MyType1 end
Base.getproperty(x::MyType1, s::Symbol) = Base.getproperty(x, Val(s))
Base.getproperty(x::MyType1, ::Val{s}) where s = getfield(x, s)
Base.getproperty(x::MyType1, ::Val{:foo}) = 123
Base.getproperty(x::MyType1, ::Val{:bar}) = 342

let s = Ref{Symbol}(:foo)
    @btime getproperty(MyType1(), $s[])
end

#+RESULTS:
: 2.836 μs (0 allocations: 0 bytes)
: 123

```

```julia
struct MyType2 end
Base.getproperty(x::MyType2, s::Symbol) = if s == :foo
    123
else
    342
end

let s = Ref{Symbol}(:foo)
    @btime getproperty(MyType2(), $s[])
end

#+RESULTS:
: 1.329 ns (0 allocations: 0 bytes)
: 123

```

2000x the performance cost.

But a lot of the time, a couple microseconds (in the edge case where constant prop fails) is peanuts to pay for convenience.

---

<div class="post-metadata">

### Author: ![jackf](https://avatars.discourse-cdn.com/v4/letter/j/b4bc9f/32.png) [@jackf](https://discourse.julialang.org/u/jackf)
#### Post date: [July 17, 2020, 8:58pm UTC](https://discourse.julialang.org/t/base-getproperty-via-val-types/43195/6 "2020-07-17T20:58:51Z")

</div>

That all makes sense, thanks for the help!

---

<div class="post-metadata">

### Author: ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)
#### Post date: [July 18, 2020, 6:01pm UTC](https://discourse.julialang.org/t/base-getproperty-via-val-types/43195/7 "2020-07-18T18:01:08Z")

</div>

Wow I knew that dynamic dispatch is to be avoided in hot loops, but I had no idea it is this expensive. I was expecting something on the order of 10ns-100ns. Any idea why it is so expensive?

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [July 19, 2020, 5:09am UTC](https://discourse.julialang.org/t/base-getproperty-via-val-types/43195/8 "2020-07-19T05:09:28Z")

</div>

It really depends. `Val` is usually a worst case for dynamic dispatch. Sometimes it can be basically the same as ifelse in certain situations (but not with Val).
