julia> @btime subtypes(Integer)
11.106 ms (3959 allocations: 1.71 MiB)
3-element Array{Any,1}:
Bool
Signed
Unsigned
It seems to strange to return an unstable return type. And why does it do anything at runtime at all? I would have assumed that this was known at compile time and would be optimised out. What am I missing here?
I’m calling subtypes() to build interface widgets from abstract types for fields of large nested structs. But it’s really slow.
Ok that makes sense… I guess this is a downside dynamic-ness that I hadn’t really got my head around. The compiler doesn’t actually “know” the type hierarchies of anything in a structured way.
Note that there is a good reason for subtypes being in the InteractiveUtils module: it is for interactive inspection of the type hierarchy, not for runtime use.
If you are using it repeatedly in runtime code so that performance matter, you are probably doing something wrong. Perhaps if you explained your problem, it could be replaced by a more appropriate solution.
I don’t think its wrong, maybe novel… But subtypes does have useful runtime applications, whatever it’s intended for.
I need a list of all the concrete types at the leaves of a abstract type hierarchies. Then I can specify the top abstract type, and get all the concrete types available beneath it. Or I can automate the process for all marked fields (with FieldMetadata.jl) of a large nested composite type.
These lists of potential concrete types can be used to construct a model in an interface or for a run of parametrisation etc. automatically. If you add a concrete type to the hierarchy anywhere, it shows up without adding any other code.
The idea is to make it easier to explore models with lots of alternate formulations visually by having all of the options in drop-downs - selecting them rebuilds the model and all the sliders, plots, whatever on the fly. Also to just parametrise all possible model combinations without doing the arduous chore of actually coding them all.
It works great. It’s just really slow to load, and this is one of the reasons. Are there other functions that would achieve the same thing??
But I don’t have known sets of concrete types, and even when I do I don’t want to type them out and get locked into pages of setup code - when it’s all discoverable with the type system anyway.
Maybe you could loop over all names in all modules, similar to how InteractiveUtils._subtypes works. Collect a list of all types, then build the hierarchy from the bottom up,
I’ve just found that subtypes has a very long compilation time in Julia 1.1. In particular, it take ages to show the subtypes of Function the first time:
In fact, there’s something could be cached/staged, like @generated function.
julia> using BenchmarkTools
julia> @btime subtypes(Number)
4.556 ms (997 allocations: 580.91 KiB)
2-element Array{Any,1}:
Complex
Real
julia> @generated mysubtypes(::Type{T}) where T = subtypes(T)
mysubtypes (generic function with 1 method)
julia> @btime mysubtypes(Number)
1.596 ns (0 allocations: 0 bytes)
2-element Array{Any,1}:
Complex
Real
The problem is that there’s no way to trigger new abstract typing relationships:
julia> struct MyNum <: Number
end
julia> subtypes(Number)
3-element Array{Any,1}:
Complex
MyNum
Real
julia> mysubtypes(Number)
2-element Array{Any,1}:
Complex
Real
I wonder if we could dispatch from something like the number of World Age? Like this way:
mysubtypes(::Type{T}) where T = mysubtypes(T, Val(getcurrentage()))
@generated mysubtypes(::Type{T}, ::Val{Age}) where {T, Age} = subtypes(T)
If we could dispatch through world age number, we could cache/stage many stuffs correctly and efficiently.