Function to create concretetype for abstracttype

Advanced Question.

Background: For every abstract type in julia I can construct a respective concretetype like

struct MyConcreteType{A, B, C} <: MyAbstractType{A, B, C} end

This correspondence is always possible, i.e. for any abstract type I can build a canonical singleton concretetype.

Now I would like to do this automatically, i.e. given an arbitrary abstract type, I would like to construct a concretetype. The concretetype can be anonymous, i.e. a type family like GET_SINGLETON_CONCRETETYPE_FOR(MyAbstractType) would be perfect.

Is there something like this in Julia, or do I really need to define a custom type for every abstract type I encounter?

I tried to do this with a generated function, in order creating the singleton struct on the fly, kind of. However this fails with error message ERROR: syntax: "struct" expression not at top level.

Hence I can rephrase my question: Is there a possible to define a struct at a sub-level? E.g. within a generated function?

I only need the type of the singleton struct, no constructors or other things are needed for my usecase. This may make things simpler, don’t know

why do you want this?
What is it for?

you can probably do this via metaprogramming + reflection
but I suspect there is a better way of achieving your true goal.
Such as the use of Type{MyAbstractType{A, B, C}} to represent it.


thanks. Can you give a reference where I can read up about metapgroamming and reflection in Julia?
EDIT: I guess it is only about macros and inspection function, which won’t help here. I would really need a way to construct a new type programmatically.

My goal ist to check whether a function is defined for certain input types or not. For this I currently fall back to using Core.Compiler.return_type (and yes, I was reminded several times by now that one should not rely on this functionality, but still as long as there is no better alternative, I find this tool awesome).

Key is, that Core.Compiler.return_type deals with abstracttypes like they could in principle have the right type. I.e. if I ask it whether a function is defined for say Number it will not check whether the function is defined for all Number types, but only whether it is defined for one concrete type. (That makes sense so far that we may have lost typeinformation and the Number could indeed be the more concrete type)

For my goal this is just the wrong semantics and luckily I can get the alternative semantics i.e. check whether the function is defined for all Number types by just using a newtype like the singleton type I suggested.

Type{MyAbstractType{A,B,C}} is a singleton, however it is not subtype of MyAbstractType and hence it won’t work here.

ADDITION: I tried something with generated functions, but failed. Please see my addition to the original question for an update

Sounds like you want which (from the @which macro) rather than Core.Compiler.return_type :

help?> InteractiveUtils.which
which(f, types)

Returns the method of f (a Method object) that would be called for arguments of the given types.

If types is an abstract type, then the method that would be called by invoke is returned
1 Like

yes, via metaprogramming. (Not all metaprogramming is macros or generated functions, dispite what the headings in the manual might suggest)
using eval (or @eval).

julia> function declareFoo()
       isdefined(@__MODULE__, :Foo) && return
       @eval struct Foo end
declareFoo (generic function with 1 method)

julia> Foo()
ERROR: UndefVarError: Foo not defined
 [1] top-level scope at REPL[5]:1

julia> declareFoo
declareFoo (generic function with 1 method)

julia> declareFoo()

julia> Foo()

This is almost certainly a bad thing to do, but you can do it.

Thank you very much for your answer

The bad thing with eval here is that it pollutes my global namespace because there seems to be only top-level structs.

Hence my package would not be cleanly precompilable if I understood it correctly.

It is really a sub-level struct definition I am looking for (I need only the type, no constructors needed)

@which sounds like an alternative, however it fails quickly to accomplish the task.

You just need to add one wrapper function in-between like f(args…) = g(args…) And which will tell you the correct generic wrapper definition. What I would like to know instead is whether the function will throw a methodnotfounderror.

Return_type with custom singleton types does the trick