Your exploration is really good, and there are in fact some things you can 
reason about. I don't want you to walk away thinking that the compiler is just 
completely fickle.

Your `alt13` is actually a good illustration of it making sense.

Even though I've seen confusion on the issue tracker as to whether `D` contains 
a type or a value, it is a type variable, and it contains a type. That type is 
`123`, which is a type that only has one possible value, a bit like `void` or 
`nil`, or `range[123,123]`

But, unlike `range[123,123]`, `D` and the value of a variable of type D can be 
treated as the same thing, which is confusing, but convenient.

On the same lines, I find it easier to reason about `ix.D` as being sugar for 
`ix.typeof.D`, because in my mental model, type parameters belong to the type, 
not the instance.

Going back to your first idea
    
    
    macro foo(ix:static int) = newLit(X)
    func idea1(ix:Ix):int = ix.D
    var z:Ix[123]
    echo foo(idea1(z))
    
    
    Run

why doesn't this work? well, because you can't return a static int from a proc. 
An instance of `static int` is a type, and procs can't return a type.

(This is if we think of static T as a higher order type, yes it sometimes makes 
more sense to think of it just as a T whose value is known at compile time, 
like `proc regex(s:static string):Regex` or something. But I would argue, if 
you can implicitly convert a static T to a value of type T, you can do the 
reverse **if you 're in a static context**)

Aha, so how to get our int into a static context?

You could assign it to a const, maybe?
    
    
    const tmp = idea1(z) # 😞
    
    
    Run

Oh no this is never going to compile, because z doesn't exist at compile time. 
The compiler isn't smart enough to know that `idea1` is only using 
statically-known properties of z.

One way to express that we don't need any run-time information about z is:
    
    
    const tmp = idea1(z.typeof.default) #😊
    
    
    Run

And indeed this is enough.
    
    
    echo foo(idea1(z.typeof.default))
    
    
    Run

here I'm explicitly converting from the value, to type, and back to value, 
which I'm arguing is what's happening implicitly in `alt13`

To reiterate, having that mental model of static type parameters being _types_ 
and not values is crucial.

* * *

Bearing that in mind, what's going on here:
    
    
    Test2[X] = object
        when X.typ == ftA:
          prefix: string
        other: int
        view: array[X.N, int]
    
    
    Run

This shouldn't instantiate, because 0.typ doesn't exist, so please file a bug, 
and maybe your commented out version should? Maybe? or maybe it shouldn't 
compile, because in `type Test3[X: static Bar]` X is a variable of the 
_typeclass_ Bar, not a specific Bar[N], so it doesn't have access to N, because 
you didn't say `type Test3[N: static int; X: static Bar[N]]`

Here are two ways to make it work:
    
    
    type
      Foo = object
        typ: FooType
        N: int
      Bar[N:static int] = object
        typ: FooType
    type
      Test2[X: static Foo] = object
        when X.typ == ftA:
          prefix: string
        other: int
        view: array[X.typeof.default.N, int]
        ## yup, got that old 'couldn't instantiate X' message,
    
    template Test3Impl[N:static int](b:Bar[N]):type =
      type Impl = object
        when b.typ == ftA:
         prefex: string
        other: int
        virw: array[N,int]
      Impl
    type
      Test3[X:static Bar] = Test3Impl(X)
    
    
    Run

here's that template pattern again it let's us reify Bar[N] along with it's typ 
field so we can actually use them

Reply via email to