Computed supertypes

I am wondering if supertypes that are computed are explicitly supported. Eg consider

using Enzyme
struct MockEnzymeMode <: supertype(typeof(Enzyme.Reverse)) end

where I construct an Enzyme.jl mode for testing an API (it should error as unimplemented), because the type params of Enzyme.Mode are not part of its API so I have to resort to these kind of tricks.

Empirically, these things work, eg

struct Foo <: supertype(typeof([1.0, 2.0, 3.0])) end

will be <:Vector{Float64}. But I am wondering if they are explicitly supported. I could not find a mention in the manual. I am implicitly assuming that the value used is that obtained the time the expression was lowered, eg

gimmetype() = Vector{Float64}
struct Bar <: supertype(gimmetype()) end
gimmetype() = Vector{Int}       # overwrite

will not change the type definition.

2 Likes

Hard to say about “explicitly supported”, but the documented semantics are that a struct definition is just an expression that is required to be top-level, and is computed in the order it appears in a file, and is definitely allowed to have computed parts to it.

So I’d say yes this is fine, and you appear to have the correct mental model for how it works.

2 Likes

I realized that this is not very different from another common use case: computed types in method signatures. ::typeof(...) is a common example, but in theory any function could be there.

I think it would make sense to write up a short note in some corner of the manual, about this application, good practices, caveats. I would make a PR but I am not sure where this belongs; I will wait for comments.

2 Likes