Hello nim community! I'm pretty new to programming in nim and so far I pretty much enjoy it.
Yesterday I ran into a newbie problem and I bet someone here can help me out.
I'm tying to allow a type Baz to accept for attribute myAttribute all types and subtypes of Foo.
type
Foo = object of RootObj
Bar = object of Foo
Baz[T: Foo] = object
myAttribute: T
let baz = Baz[Foo]() # compiles
let baz2 = Baz[Bar]() # Error: object constructor needs an object type
I naively believed that the type constraint [T: Foo] would work, but it seems that it only allows types of Foo, not subtypes.
What am I missing?
I got your code working by creating a constructor method
type
Foo = ref object of RootObj
Bar = ref object of Foo
Baz[T: Foo] = ref object
myAttribute: Foo
proc newBaz[T: Foo](): Baz[T] =
new(result)
let baz = Baz[Foo]() # compiles
let baz2 = newBaz[Bar]() # compiles
The following should work. It may not be what you want though, which I believe is 'subtyping in the generic constraints', right?
type
Foo = object of RootObj
Bar = object of Foo
Baz[T: Foo | Bar] = object
myAttribute: T
let baz = Baz[Foo]() # compiles
let baz2 = Baz[Bar]()
If you remove all ref keywords, you cannot use new anymore to construct the object, as that requires a ref object. Without the new keyword, I could not get the object to construct properly as a generic.
At a minimum, you need to define Baz as a ref object and that will work fine.
Here's a working example without refs:
type
Foo = object of RootObj
Bar = object of Foo
Baz[T: Foo] = object
myAttribute: T
# define your own initializer
proc initBaz[T: Foo](attr: T): Baz[T] =
result.myAttribute = attr
let baz1 = Baz[Foo]() # compiles
let baz2 = initBaz(Bar()) # also compiles
Thank you all for your help, very much appreciated.
As you proposed, the init proc helped. However, I had a weird compiler error somewhere else down the road with this approach, so I looked for another solution.
Bpr pointed out that I might actually be better off using concepts instead of inheritance. I tried that and so far it seems that concepts work better than inheritance in generic procs.
where this breaks down is if Baz is also inheritable
type Baz[T:Foo] = object of RootObj
myAttribute: T
let baz1 = Baz[Bar]() #Error: object constructor needs an object type
This is a bug, (maybe https://github.com/nim-lang/Nim/issues/7713 ?) but concepts work
type
Foo = object of RootObj
Bar = object of Foo
IsFoo = concept type t
t is Foo
Baz[T: IsFoo] = object of RootObj
myAttribute: T
let x = Baz[Bar]()#fine.