# Wrapper types function passthrough

**URL:** <https://discourse.julialang.org/t/wrapper-types-function-passthrough/23250>\
**Category:** General Usage\
**Created:** [April 17, 2019, 4:27pm UTC](https://discourse.julialang.org/t/wrapper-types-function-passthrough/23250 "2019-04-17T16:27:17Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [April 17, 2019, 4:27pm UTC](https://discourse.julialang.org/t/wrapper-types-function-passthrough/23250/1 "2019-04-17T16:27:17Z")

</div>

Hi All,  
I’m trying out something in an attempt to make an as unintrusive as possible threadsafe cache type.  
The basic idea is that upon creation it will generate as many caches with the initial value as there are threads. Then whenever anything acts on the cache, it will automatically act on the cache with the respective `Threads.threadid()`, thus making actions on it completely threadsafe.

It looks something like:

```julia
struct ThreadCache{T}
	caches::Vector{T}
	ThreadCache(orig::T) where {T} = new{T}([deepcopy(orig) for i = 1:nthreads()])
end

```

then currently I defined manually the functions I was often performing on the caches inside the threaded loops along the lines of:

```julia
@inline cache(t::ThreadCache) = t.caches[threadid()]
+(t::ThreadCache{T}, v::T) where T = cache(t) + v 
-(t::ThreadCache{T}, v::T) where T = cache(t) - v 
*(t::ThreadCache{T}, v::T) where T = cache(t) * v 
/(t::ThreadCache{T}, v::T) where T = cache(t) / v
etc

```

Now for what I’m currently using this works fine, but I can’t help but feel that this could be extended very easily to accomodate anything if only I am able to specify that anything (like `methodswith`) that would act on cached type `T` like `f(...., cached::T,....)` would work on the cache like `f(...., th::ThreadCache{T}, ....) = f(...., cache(th), ....)` calling the previous function.

This feels like something that shouldn’t be too hard but I can’t seem to figure it out in a versatile way.

Thanks!

---

<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:** [April 17, 2019, 6:06pm UTC](https://discourse.julialang.org/t/wrapper-types-function-passthrough/23250/2 "2019-04-17T18:06:36Z")

</div>

If I understand you correctly, you would like to have that

```julia
f(t::ThreadCache, args...; kw...) = f(cache(t), args...; kw...)

```

for any function `f` automatically. This is not possible in julia. You have to list the functions `f` you want to support explicitly.

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [April 17, 2019, 6:10pm UTC](https://discourse.julialang.org/t/wrapper-types-function-passthrough/23250/3 "2019-04-17T18:10:03Z")

</div>

Yes something like that, but with t being at any place in the arguments. Anyway indeed I think it would need some metaprogramming magic but Idk if it’s even at all possible with that.

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [April 17, 2019, 6:16pm UTC](https://discourse.julialang.org/t/wrapper-types-function-passthrough/23250/4 "2019-04-17T18:16:15Z")

</div>

Yeah, this is basically [https://github.com/JuliaLang/julia/issues/14919](https://github.com/JuliaLang/julia/issues/14919)

```julia
julia> (f::Any)(x::ThreadCache, args...; kwargs...) = 1
ERROR: cannot add methods to an abstract type
Stacktrace:
 [1] top-level scope at none:0

```

You can definitely work around this with a pretty simple macro though.

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [April 17, 2019, 7:45pm UTC](https://discourse.julialang.org/t/wrapper-types-function-passthrough/23250/5 "2019-04-17T19:45:31Z")

</div>

Would the macro be something along the lines of an @generated in front of the constructor that also evals all `methodswith` of `T`?

Edit: I had a quick look through the issue and there might be some other suggestions I could try.

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [April 17, 2019, 7:59pm UTC](https://discourse.julialang.org/t/wrapper-types-function-passthrough/23250/6 "2019-04-17T19:59:46Z")

</div>

No, I was thinking more along the lines of this:

```julia
using Base.Threads: nthreads, threadid

struct ThreadCache{T}
	caches::Vector{T}
	ThreadCache(orig::T) where {T} = new{T}([deepcopy(orig) for i = 1:nthreads()])
end
@inline cache(t::ThreadCache) = t.caches[threadid()]

threadlocal(x) = x
threadlocal(x::ThreadCache) = cache(x)

macro threadlocal(expr)
    @assert expr.head == :call
    f = esc(expr.args[1])
    args = map(esc, expr.args[2 : end])
    quote
        $f($([:(threadlocal($arg)) for arg in args]...))
    end
end

```

so that you can use it as

```julia
julia> t = ThreadCache(1)
ThreadCache{Int64}([1])

julia> @threadlocal t + 2
3

```

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [April 17, 2019, 8:55pm UTC](https://discourse.julialang.org/t/wrapper-types-function-passthrough/23250/7 "2019-04-17T20:55:20Z")

</div>

That works, but almost defeats the purpose of having this. I basically did it to avoid having to do  
`reduction_storage[threadid()] ...` inside loops 24/7. I hoped that multiple dispatch could be really nice here but it seems hard.

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [April 17, 2019, 9:18pm UTC](https://discourse.julialang.org/t/wrapper-types-function-passthrough/23250/8 "2019-04-17T21:18:42Z")

</div>

Yeah, it’s unfortunate.

Using `methodswith` in a generated constructor isn’t really a solution either though. It would use non-constant global state (the method table) in the function generator, which is a no-no. At the very least, the behavior of the program could depend on the order in which packages are loaded, as packages may add additional methods and there’s no guarantee on when the generator is run. `methodswith` would also be a very inaccurate way of finding methods that should be overloaded, since it doesn’t include applicable methods overloaded for a supertype of `T`, just those overloaded for exactly `T`.

Perhaps a more advanced macro could walk through a compound (multi-line) expression, find all the function calls (e.g. using MacroTools), and apply the transformation I suggested. That way you wouldn’t have to annotate each line separately. Cassette could also be used to implement (a more advanced version of) this.

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [April 17, 2019, 9:21pm UTC](https://discourse.julialang.org/t/wrapper-types-function-passthrough/23250/9 "2019-04-17T21:21:23Z")

</div>

Right, changing `@threads` to a different macro would be a reasonable solution. I will have a go at that with either macro tools or cassette, I’ve been wanting to have a look into cassette anyway !
