I was very pleased to discover that this is a thing that's been carved out from Flux, but was slightly surprised by the following performance:
using Functors, BenchmarkTools
using Functors: functor
struct Bar{T}
x::T
end
@functor Bar
bar = Bar(5.0)
julia> @benchmark fmap(Float32, bar)
BenchmarkTools.Trial:
memory estimate: 608 bytes
allocs estimate: 16
--------------
minimum time: 952.304 ns (0.00% GC)
median time: 984.652 ns (0.00% GC)
mean time: 1.040 μs (1.92% GC)
maximum time: 76.549 μs (96.27% GC)
--------------
samples: 10000
evals/sample: 23
Digging down a little, functor seems to be performant:
julia> @benchmark functor($bar)
BenchmarkTools.Trial:
memory estimate: 0 bytes
allocs estimate: 0
--------------
minimum time: 1.455 ns (0.00% GC)
median time: 1.470 ns (0.00% GC)
mean time: 1.589 ns (0.00% GC)
maximum time: 39.906 ns (0.00% GC)
--------------
samples: 10000
evals/sample: 1000
👍
Similarly, isleaf seems to be fine:
using Functors: isleaf
julia> @benchmark isleaf($bar)
BenchmarkTools.Trial:
memory estimate: 0 bytes
allocs estimate: 0
--------------
minimum time: 0.020 ns (0.00% GC)
median time: 0.032 ns (0.00% GC)
mean time: 0.030 ns (0.00% GC)
maximum time: 0.050 ns (0.00% GC)
--------------
samples: 10000
evals/sample: 1000
👍
So there's something else going on in fmap and fmap1 that I assume has something to do with the IdDict that's being used. So, I would be interested to know a) what the need for the cache is (it's kind of un-obvious to me) and b) whether there's a way to get rid of all of this overhead as it seems kind of unnecessary in this simple case?
edit: I realised while out on a walk that it's probably something to do with diamonds in the dependency graph for any particular data structure. Is this the case?
I was very pleased to discover that this is a thing that's been carved out from Flux, but was slightly surprised by the following performance:
Digging down a little,
functorseems to be performant:👍
Similarly,
isleafseems to be fine:👍
So there's something else going on in
fmapandfmap1that I assume has something to do with theIdDictthat's being used. So, I would be interested to know a) what the need for the cache is (it's kind of un-obvious to me) and b) whether there's a way to get rid of all of this overhead as it seems kind of unnecessary in this simple case?edit: I realised while out on a walk that it's probably something to do with diamonds in the dependency graph for any particular data structure. Is this the case?