With this code (echoed in this playground link)
type Bar[N: Natural, T] = object
bar1: int
bar2: N
bar3: array[N, T]
var b0: Bar[3, uint8]
b0.bar1 = 1
b0.bar2 = 2
b0.bar3 = [3, 4, 5]
var b1 = Bar[3, uint8]()
b1.bar1 = 1
b1.bar2 = 2
b1.bar3 = [3, 4, 5]
var b2: Bar[3.Natural, uint8]
b2.bar1 = 1
b2.bar2 = 2
b2.bar3 = [3, 4, 5]
echo b0
echo b1
echo b2
I thought all three forms b0, b1 and b2 should work. Object b0 compiles, but b1 and b2 give compiler errors and I'd like to know why. Am I misunderstanding or should I report as a github issue?
type Bar[N: static Natural, T] = object
bar1: int
bar2: Natural
bar3: array[N, T]
var b0: Bar[3, uint8]
b0.bar1 = 1
b0.bar2 = 2
b0.bar3 = [3, 4, 5]
var b1 = Bar[3, uint8]()
b1.bar1 = 1
b1.bar2 = 2
b1.bar3 = [3, 4, 5]
var b2: Bar[3.Natural, uint8]
b2.bar1 = 1
b2.bar2 = 2
b2.bar3 = [3, 4, 5]
echo b0
echo b1
echo b2
Please correct me if I'm wrong 😅
On my machine N: static Natural doesn't compile (Nim 2.2.2). I get Error: type expected for line 4.
I've also experimented with these:
type
A3 = array[3, int]
A4 = array[0..3, int]
# Works
var x3: A3
var x4: A4
echo x3 # [0, 0, 0]
echo x4 # [0, 0, 0, 0]
# # Doesn't work
let a3 = A3()
let a4 = A4()
echo a3
echo a4
IMHO this shouldn't be allowed by the language, but, alas, issue here is that when you pass value to array length it could be read as type, essentially:
type A[N, T] = array[N, T]
var a: A[3'i8, int32]
var b: A[int8, int32] # equivalent to `a` above
echo a.len # 256
echo b.len # 256
Try it on Nim Playground
You could use static Natural as @doongjohnto suggested to avoid this, but then N is a literal and doesn't have a type.
One solution is to add 1 extra generic argument and a template for convenience:
type Bar[N: static Natural, NT: SomeInteger | Natural, T] = object
bar1: int
bar2: NT
bar3: array[N, T]
template SomeBar(a: typed, b: typedesc): typedesc = Bar[a, typeof(a), b]
var b0: SomeBar(3, uint8)
b0.bar1 = 1
b0.bar2 = 2
b0.bar3 = [3, 4, 5]
var b1 = SomeBar(3, uint8)()
b1.bar1 = 1
b1.bar2 = 2
b1.bar3 = [3, 4, 5]
var b2: SomeBar(3.Natural, uint8)
b2.bar1 = 1
b2.bar2 = 2
b2.bar3 = [3, 4, 5]
echo b0
echo b1
echo b2
Try it on Nim Playground Oh, I didn't know that the range type can be used as both a concrete type and a generic constraint.
var a: Natrual
echo typeof(a) # Natrual
type A[N: Natural] = object
n: N
echo typeof(A[10]().n) # int (I thought it would print Natural)
However, this is unintuitive to me because int can contain negative numbers, while A.n looks like it should only hold natural numbers.
Thanks for explaining the details. My takeaway (and summary for future search results) is that this code:
type Bar[N: Natural, T] = object
bar1: int
bar2: N
bar3: array[N, T]
is a problem because N is used as a type for bar2, but I'm also trying to use N's literal numeric value as the length of the array for bar3.