Static variant types: infinite recursion?

sometimes you have a type that you want to occur in several static variants:

protocol AnimationCurve 
{
    static 
    func f(_:Double) -> Double
}
struct Animation<Curve> where Curve:AnimationCurve
{
    enum Linear:AnimationCurve 
    {
        static 
        func f(_ x:Double) -> Double 
        {
            return x 
        }
    }
    enum Quadratic:AnimationCurve
    {
        static 
        func f(_ x:Double) -> Double 
        {
            return x * x
        }
    }
}

it would make sense then, to nest the variant cases inside the variant type’s namespace, so Linear would live in Animation.Linear, etc.

However, then you get this problem where it becomes impossible to reference any of the actual cases because of generic parameter recursion:

let animation = Animation<Animation.Linear>()
// error: generic parameter 'Curve' could not be inferred
let animation = Animation<Animation<Animation.Linear>.Linear>()
//error: generic parameter 'Curve' could not be inferred
let animation = Animation<Animation<Animation<Animation.Linear>.Linear>.Linear>()
//error: generic parameter 'Curve' could not be inferred

it should be possible to nest types for the purposes of namespacing without having them depend on generic parameters in the outer type which they may not care about. i believe this is also the issue preventing protocols from being nestable. can we make it so specifying the generic parameter is not required if the inner type never accesses it?

Not really. That would keep it from being a source-compatible change to start referencing the parent type. You'd have to explicitly promise it in some way.

what about leading dot syntax?

Animation<.Quadratic>

and either way, the issue is the recursion in the type parameter, so in theory this ought to be possible too:

Animation<Animation.Quadratic>

It has to be a promise on the definition side, not on the use side.

would an attribute fix it?

struct Animation<Curve> where Curve:AnimationCurve
{
    @namespaced
    enum Linear:AnimationCurve 
    {

IIRC @anandabits pitched something similar via an extension.

extension any Animation {
  enum Linear: AnimationCurve { ... }
}

I could be wrong though.

Yeah, here is the initial sketch writeup and current sketch after a bit of discussion happened.

that seems a lot more complicated than what I’m suggesting. I don’t think it’s necessary to talk about expanding the type system just to achieve namespacing

I don’t think what you’re suggesting is viable. It requires inspecting the implementations of all members of the type to determine whether they reference surrounding type arguments or not. I think we need a way to specify intent when declaring the type. If you have ideas about how to do this that are different from what I sketched out I would love to hear them.

my idea was just introduce a simple attribute @namespaced that makes it so the type it’s attached to can only reference declarations as if it were at the top level, and just takes the names of its encapsulating types (minus type parameters) as a prefix. A direct solution to the problem and easy to understand,, no metatyping concepts needed.

Oh, sorry I missed that. I think it would be fine to go in that direction for now. It it’s compatible with a more fleshed out direction in the future. If we add those features later, @namespaced just becomes syntactic sugar for them. It also works inside the declaration of the containing generic type, which my pitch wouldn’t.

Terms of Service

Privacy Policy

Cookie Policy