Why doesn't it compile?
type Foo[options: static tuple] = object # ok
const foo = Foo[(name: "hello", value: 10)]() # ok
func name[options](foo: Foo[options]): string = options.name # Error: cannot instantiate: 'foo:type'
echo foo.name
Note that this code compiles successfully.
type Options = tuple
name: string
value: int
type Foo[options: static Options] = object
const foo = Foo[(name: "hello", value: 10)]()
func name[options](foo: Foo[options]): string = options.name
echo foo.name
i'm impressed any of that compiles. mindbending stuff.
in func name[options] options could be any tuple, not necessarily containing a field 'name' so Foo[T] is still underspecified.
anyway, macros are a better tool for abusing the type system:
import macros
type Foo[T:static tuple] = object
const foo = Foo[(name: "hello", value: 10)]()
macro vomit(f:Foo):untyped = f.getTypeInst[1]
let insides = foo.vomit
assert insides.name == "hello"
assert insides.val == 10
The first one doesn't work because the options generic is instantiated with the type tuple and that type doesn't contain a value for name.
You can fix this by specifying the tuple's fields:
type Foo[options: static tuple[name: string, value: int]] = object
This full example compiles:
type Foo[options: static tuple[name: string, value: int]] = object
const foo = Foo[(name: "hello", value: 10)]()
func name[options](foo: Foo[options]): string = options.name
echo foo.name
in func name[options] options could be any tuple, not necessarily containing a field 'name' so Foo[T] is still underspecified.
No, that's not the reason, because this doesn't compile either:
func name[options](foo: Foo[options]): string = "hello"
You can fix this by specifying the tuple's fields
This is actually what is done in my second example.
No, that's not the reason, because this doesn't compile either:
hmm, so i guess generics with generic type specifiers dont work. Is there a motivating reason for why you need them to?
Is there a motivating reason for why you need them to?
These are just experiments. I'm thinking of a convenient implementation of the MMIO library for MCUs. And I need to tie several compile-time known values with a type. Something like custom compile-time known properties of a certain type.
so it looks as though you can use getTypeInst or specify the static type.
you might also consider attaching values to a type with custom pragmas:
import macros
template values(vals:tuple){.pragma.}
type
Foo{.values:("hello",10)} = object
let f = Foo()
if f.hasCustomPragma(values):
echo f.getcustomPragmaVal(values) #(vals:("hello",10))
Why doesn't it compile?
Maybe compiler bug.
I found 2 different ways to fix your example code:
type Foo[options: static tuple] = object # ok
const foo = Foo[(name: "hello", value: 10)]() # ok
#func name[options](foo: Foo[options]): string = options.name # Error: cannot instantiate: 'foo:type'
#Use type class automatically created by generic type
func name(arg: Foo): string = arg.options.name
echo foo.name
# Wrap static tuple with generic type
type
Bar[options: static tuple] = object
Foo[T] = object
const foo = Foo[Bar[(name: "hello", value: 10)]]()
func name[T](foo: Foo[T]): string = T.options.name
echo foo.name
type Foo[options: static tuple] = object # ok
const foo = Foo[(name: "hello", value: 10)]() # ok
#func name[options](foo: Foo[options]): string = options.name # Error: cannot instantiate: 'foo:type'
#Use type class automatically created by generic type
func name(arg: Foo): string = arg.options.name
echo foo.name
WAT?
Type classes have nothing to do with this. I found that this also works:
type Foo[options: static tuple] = object
const foo = Foo[(name: "hello", value: 10)]()
assert foo.options.name == "hello"
It is extremely strange.