I’m not a super fan of inheritance-based polymorphism. I tend to like interface-based polymorphism like Go’s interfaces and Haskell’s type classes, et al.
I realize retrofitting these features in Julia is thought to be problematic because Julia’s dispatch resolver goes by specificity and it’s not clear how type classes could be seen as more or less specific than other abstract types. Anyway, I’ve been playing with Holy traits as a poor-man’s alternative, and I thought I’d try to generate some trait code based on interfaces, so I just need to do the (presumably) expensive method checks the first time it’s run with a given type.
struct HasPlus end
struct NoPlus end
@generated HasPlus(T) =
hasmethod((+), (T,)) ? :(HasPlus()) : :(NoPlus())
This seems to work properly, but I’m not sure if there is a penalty for doing this. I’m paranoid because of this blog post, which contains these words:
Generated (aka staged) functions cannot be statically compiled. These functions are equivalent to calling
eval
on a new anonymous function computed as a function of the input types (a JIT-parsed lambda, if you will), and optionally memoizing the result. Therefore, it is possible to statically compile the memoization cache. This makes them, in this regard, superior to an unadornedeval
call. But in the general case, generated functions are black boxes to the compiler and thus cannot be analyzed statically.
The words “cannot be statically analyzed” are what’s troubling me here. My assumption is that once the method is generated, it goes into dispatch tables in the normal way and the compiler handles things efficiently, but I’m not totally sure how all that works.
The other thing that bugs me about this solution for interface dispatches is that, as the blog post indicates, it can’t be used with AOT compilation.
The Julia compiler has enough type information that calls to hasmethod
could theoretically be resolved at compile time an things like dead branch elimination could be applied, but I don’t know enough about Julia to know if this actually happens. Compile-time hasmethod
would be really helpful for implementing interface polymorphism on top of Holy traits.