proc newCurveLoop*( curves:seq[Curve]; tag:int = -1 ):Loop
On the other hand I have:
Curve* = ref object of Tag
Line* = ref object of Curve
ini*, fin*:Point
The type safety makes seq[Curve] is different to seq[Line].
Is there a way to make it accept all the instances inheriting from Curve?
It should just work.
type
A = ref object of RootObj
B = ref object of A
C = ref object of B
proc foo(xs: openarray[B]) =
for x in xs:
if x of C: echo "C"
elif x of B: echo "B"
elif x of A: echo "A"
foo([C(), B(), C()])
output
C
B
C
Is there a way to make it accept all the instances inheriting from Curve?
As that question arises often, I tried to explain that in my book (with geometric shapes).
http://ssalewski.de/nimprogramming.html#_object_orientated_programming_and_inheritance
It is still not clear enough?
Thank both. It is clear. In fact I just realised that the problem was cause by something different (that I still don't understand), but probably it has something to do with the stack and the heap.
I have something like the following:
let points = newPoint( @[ pt(0,0,0),
pt(0.1, 0, 0),
pt(0.1, 0.3, 0),
pt(0, 0.3, 0) ],
lc )
let lines = newLine(points, close = true)
echo repr points #<---- This works
But the problem is that newLine has echo repr points as well and displays:
0x7f11d1f36048@[nil, nil, nil, nil]
Why is that?
I am still struggling with the type system .
For instance:
type
A = ref object of RootObj
B = ref object of A
val:int
proc example*(x:seq[A]) =
for i in x:
echo repr i
var a:seq[A] = @[B(val:1), B(val:2)] #<--- This fails, but why?: Error: type mismatch: got <seq[B]> but expected 'seq[A]'
echo repr a
example(a)
On the other hand, the following works:
type
A = ref object of RootObj
B = ref object of A
val:int
proc example*(x:seq[A]) =
for i in x:
echo repr i
var a:seq[A] # I can create `seq[A]` like this. But why it failed like a one liner?
a &= B(val:1)
a &= B(val:2)
echo repr a
example(a)
Finally, the following fails:
type
A = ref object of RootObj
B = ref object of A
val:int
proc example*(x:seq[A]) =
for i in x:
echo repr i
var a:seq[B] # But `seq[A]` worked
a &= B(val:1)
a &= B(val:2)
echo repr a
example(a) # <-- Now this fails because I send `seq[B]` instead of `seq[A]`.
I got the same problem as in the first post:
Error: type mismatch: got <seq[B]> but expected one of: proc example(x: seq[A]) first type mismatch at position: 1 required type for x: seq[A] but expression 'a' is of type: seq[B] expression: example(a)
I’m a Nim newbie, haven’t used seq much, and I’m making the assumption that seq is a reference type, ie. passed by reference not by value. If that’s wrong, ignore this!)
You can’t assign an instance of seq[B] to a variable of type seq[A], because you could then use that variable to add a non-B object to the seq. Basically, seq[A] has looser constraints about what it can contain than seq[B] does.
By analogy: I make a scrapbook of photos of cats. You come over while I’m out, pick up the book and say “oh, it’s a book of animal pictures! I’ll add this cute photo of my pet snake.” Then I find the photo later and am all “WTF is this snake doing with my cat pictures?!”
Incidentally, this is only a problem if seq assignment is by-reference — otherwise it’s like you made a copy of my cat-photos book. Now you have your own animal-photos book and can paste snakes into it with no problem.
It’s also only an issue if the variable assigned to is mutable — otherwise it’s like you pick up my book but have the courtesy to understand that you aren’t allowed to change it.
(In type theory this kind of issue is referred to as contravariance.)
snej, seq is in modern Nim a value object, not a ref. In old Nimrod we could assign nil to a seq, but that is not possible today.
mantielero,
var a:seq[A] = @[B(val:1), B(val:2)]
can not work as Nim is a statically typed language, seq[A] and seq[B] are different types, so assignment is not allowed.
I understand the rationale of seq[Animal] being a different type than seq[Cat]. But I believe this is counter-intuitive when Cat it is actually an animal.
In fact, it looks strange to me the following behaviour:
type
Animal = ref object of RootObj
Cat = ref object of Animal
proc example1(x: Animal) =
echo "meaw"
let kitty = Cat()
example1(kitty) #<---Works
proc example2(x:seq[Animal]) =
echo "meaws"
let kitties = @[Cat(), Cat()]
example2(kitties) #<---Doesn't work
Try this.
type
A = ref object of RootObj
B = ref object of A
val:int
proc example*(x:seq[A]) =
for i in x:
echo repr i
var a:seq[A] = @[B(val:1).A, B(val:2),A()] #B(val:1).A instead of #B(val:1)
echo repr a
example(a)
for item in a:
if item of B:
echo repr B(item)
Now you've created a seq[A] instead of seq[B].
The of operator here is used to check if an item is of type B at runtime.
You might want to look into methods. It's under the header multi-methods in the manual.
The thing is that in example1 case there is an implicit conversion from Cat to Animal, while in example2 that conversion has to be explicit.
I would expect the implicit conversion happening in both cases. Probably there is a rationale for that no happening.
with the conversion of first element in the seq B(val:1).A you tell the compiler, that you create a seq[A]. For the remaining elements you don't need the conversion:
var a:seq[A] = @[B(val:1).A, B(val:2)]
and you can even omit the type declaration for a:
var a = @[B(val:1).A, B(val:2)]
var a:seq[A] = @[B(val:1), B(val:2)] > can not work as Nim is a statically typed language, seq[A] and seq[B] are different types, so assignment is not allowed.
There's nothing about static typing that forbids this; the collection class just needs the appropriate generic assignment operator. I thought C++'s vector allowed it, but I just tried it and it doesn't. But Swift's Array does, so this compiles:
// This is Swift 5.2
class A { }
class B : A { }
var a: [A] = []
var b: [B] = []
a = b
In Nim I think you could write a generic proc to assign a seq[B] to a seq[A], using the restriction when B is A.