Hi there, What is the best way to store different objects in a sequence? For instance I'd like to mix int and seq[int] types. Right now I'm trying to achieve this through inheritance and generics but I'm not sure if this is the right approach here. The following example compiles but crashes at runtime with "Illegal storage access". I believe the sequence type (my Base class) is not correct. I much appreciate if somebody could point me out what is wrong here?
type Base = ref object of RootObj
name:string
type BBB[T] = ref object of Base
data:T
var x1 = BBB[int](data:1)
var s = @[1,2,3]
var x2 = BBB[seq[int]](data:s)
echo x1.data
echo x2.data
var mySeq : seq[Base]
mySeq.add(x1)
Thank you.You need to initialize the sequence first, otherwise it'll segfault as you noticed.
type Base = ref object of RootObj
name:string
type BBB[T] = ref object of Base
data:T
var x1 = BBB[int](data:1)
var s = @[1,2,3]
var x2 = BBB[seq[int]](data:s)
echo x1.data
echo x2.data
var mySeq : seq[Base] = @[] # initialize the sequence
mySeq.add(x1)
Thanks, I totaly forgot about that. I still have a problem to get the value back. Am I expected to use a cast?
var mySeq : seq[Base] = @[]
mySeq.add(x1)
var e = cast[BBB[int]](mySeq[0])
echo e.data # this return some bogus data
var e: Base = mySeq[0]
echo e.name
if e of BBB[int]:
var i:int = BBB[int](e).data
echo i
I think this generates a test for the of operator and after this a type conversion. Maybe not the fastest solution, because after test with of operator it is clear that type conversion is successful. There may exist a better/faster solution.
Here is a crude version:
type Base = ref object of RootObj
name:string
type BBB[T] = ref object of Base
data:T
var x1 = BBB[int](data:1)
var s = @[1,2,3]
var x2 = BBB[seq[int]](data:s)
echo x1.data
echo x2.data
var mySeq : seq[Base] = @[]
mySeq.add(x1)
mySeq.add(x2)
for item in mySeq:
if item of BBB[int]:
echo BBB[int](item).data
elif item of BBB[seq[int]]:
echo BBB[seq[int]](item).data
cast is unsafe, that's reason of the bogus data.
Hakand, you are also applying first the test with of operator and after that a type conversion. I just looked into the manual if there is something like a shortcut for that, but can not find something. I think there existed languages in the past which tried to avoid such double effort? Can not really remember.
[EDIT]
Oberon used the WITH statement. (Which is different from WITH in Modula2) http://en.wikipedia.org/wiki/Oberon-2_(programming_language)#WITH_statement
match item
x is BBB[int] => echo x.data
x is BBB[seq[int]] => echo x.data
_ => echo "bogus item type"
The catchall could be eliminated by using a discriminated union, which is available in Nim.
In my case I will know the type upfront so this could also be done with generics.
proc getVal[T](mySeq:seq[Base], index:int)=
echo BBB[T](mySeq[index]).data
getVal[int](mySeq,0)
getVal[seq[int]](mySeq,1)
Now... initially I would wonder why not just have a seq[int] all the time? But let's say this is just an example, then one can also use methods - although I couldn't make that play nice with generics:
type Base = ref object of RootObj
name:string
type BBB = ref object of Base
data: int
type BBB2 = ref object of Base
data: seq[int]
var x1 = BBB(data:1)
var s = @[1,2,3]
var x2 = BBB2(data:s)
var mySeq : seq[Base] = @[]
mySeq.add(x1)
mySeq.add(x2)
# A base implementation is needed to make
# the compiler happy since the seq has instances
# of Base
method getData(self: Base): seq[int] =
@[]
# This one just returns the seq
method getData(self: BBB2): seq[int] =
self.data
# Here we wrap the int in a seq
method getData(self: BBB): seq[int] =
@[self.data]
# Then we can happily iterate
for item in mySeq:
echo item.getData
@Varriount: jibal: One might be able to implement a pattern matching macro...
I'd really like to see that in the future module.