Automatically generating methods for a specialised struct

Suppose I have the following struct

struct Foo
    a::Float64
    b::Float64
end

that I have defined many methods for.

This is the most general representation, but most of the time I only care about a specialised version where b = 0.0 (or more generally b is any fixed value).

I represent this as a

struct SpecialFoo
    a::Float64
end

I have re-implemented optimised versions for a few of the methods of Foo for SpecialFoo, but not all methods.

Whenever a method that is defined for Foo but not SpecialFoo is called, I would like this to automatically be called with a Foo(SpecialFoo.a, 0.0), in a way that has minimal overhead.

I am aware I can manually define this behaviour for a specific function but since I have many methods, I would like it to occur automatically.

I am also aware that I could achieve this by defining an AbstractFoo with methods get_a, get_b which retrieve a and b for Foo, and a and 0.0 for SpecialFoo, and define all AbstractFoo methods in terms of get_a and get_b but I worry this will quickly become quite messy.

Any thoughts on how I can achieve this would be greatly appreciated.

I’d avoid making a SpecialFoo if you need to bounce back and forth from it. Writing one method with defaults for all positional arguments does make multiple methods with trailing default values, if that’s all you need. @kwdef transforms a modified struct expression to include methods with default arguments, but those are keyword arguments, not the positional arguments you described. However, keyword arguments allow defaults to not be all trailing arguments, which is why the macro works on them.

Otherwise, I’d try to make convert work from SpecialFoo to Foo. Or if a specialized method for such a conversion if you prefer.

It sounds like something you can achieve with an @eval loop, cf. the manual section on code generation.

If it’s just the spelling of the getters that would make things messy, you could consider getproperty overloading.

Thank you for the reply!

I might not be understanding you correctly or maybe I didn’t explain myself clearly enough, so I will clarify. I need SpecialFoo for dispatching versions of the usual methods that are optimised for the b=0.0 case.

I think (again, I might not be following) you’re are suggesting have kwarg constructors for Foo so that I can set b=0.0 but then I can’t dispatch on this fact.

This sounds much closer to what I’m after. I can see what this convert method would look like and how to use it in a one-off case:

f(x::SpecialFoo) = f(convert(Foo, x))

but not how I could make that automatically apply for all possible functions.

This sounds like a good approach if no “built-in” approach exists. I will look into this. Thanks!

Yes, I think the added getter calls cluttering up the code was my concern. The getproperty overloading is a nice workaround, though I think I recall reading elsewhere that it isn’t often considered best practice—I’m sure how seriously I should be taking that warning.

Thanks for sharing your ideas!

I’ve had a similar problem once. I solved it with such an AbstractFoo, but not with get_a and get_b, but by defining a b property on SpecialFoo.

function Base.getproperty(obj::SpecialFoo, s::Symbol) 
   (s==:b) ? zero(obj.a) : getfield(obj, s)
end

It’s a somewhat dirty hack which can be used in simple cases.