One thing that confused me a little while learning Nimrod, is I asked myself: Can you get a reference from an object (that was not declared as ref)?
I read the tutorial and manual but I couldn't find an explicit answer. While playing around my impression is:
No. An object is allocated on the stack (?). You can pass an object to a proc, where you can read, but not modify the object unless the parameter is declared "var" (but if there's a reference in the object you can modify what it references). You can not get a reference from it because it would be unsafe: If the reference is left behind after the stack is popped it would point at garbage. You can of course get a pointer (ptr) of an object by using "obj.addr", but you've made it very clear that pointers are unsafe.
I'm guessing that passing an object to a proc is not copying (unless you assign it to some other var), unlike pass-by-value structs in C...
Other questions I haven't found the answer to:
var x = TPerson(name: "Araq")
var y = PPerson(x)
proc PPerson(x: TPerson): PPerson =
PPerson(name: x.name)
Nimrod reserves the right to use pointers when you pass objects by value to a proc. This is an implementation detail the compiler is presumed to choose correctly. You should only worry about the parameter being mutable inside a proc or not.
To create a new ref of a plain object you need to write yourself a duplication proc because the language can't figure out for you what you want to do with the object's fields (duplicate their contents or point to them? Is the duplication a shallow or deep copy if they are complex objects?).
The automatic conversion should be possible with a converter, using the converter keyword.
The ref shouldn't just point at the plain object or its fields, that would be unsafe, right? But the language figures out what to do when you do:
var x = TPerson(...)
var y = x
(Shallow copy as far as I can see)
So with my limited understanding it seems plausible to me that it should be able to figure out how to make a ref object from an object (allocate and make a shallow copy).
But given that the manual states that you should only use T(..)/P(..) object constructors internally in a module, I can see how having an implicit conversion from T to P could be bad. It might cause users of a module to do things the writer of the module had not intended. It could perhaps have been a useful feature within a module, but I haven't written enough Nimrod to know, and since it has not been added yet I trust nobody has felt a need for it.
There's probably no issue with the language here, but maybe the tutorial could make things like this a bit clearer.
Btw, I can't see that it's ever stated explicitly in the documentation that newFoobar is the idiomatic naming of a constructor. In the tutorial, after mentioning that a constructor should be created, maybe give a typical example.
Thanks for pointing me to converter.
What you want is easily done:
proc box[T](x: T): ref T =
new(result); result[] = x
Why does the stdlib lack such a useful thing then? Because I never need it.
Aha! I didn't think of putting the dereference operator on the left hand side. It's obvious in retrospect.
Coming from C (among others) I keep getting thrown off.. oh, it's not like C, oh wait, this part is a bit like C, but this part is not.. heh. Maybe I should write a guide on the Git wiki.. Nimrod for C programmers. Do you encourage use of the Git Wiki? Have you considered linking to it from the Documentation page on the website?
There would probably be no point in adding the box procedure to stdlib.. If it's needed, just typing new(y); y[] = x is clear and short.
Maybe I should write a guide on the Git wiki.. Nimrod for C programmers. Do you encourage use of the Git Wiki? Have you considered linking to it from the Documentation page on the website?
You write that guide on the Git wiki and we link to it. Deal? ;-)
> What you want is easily done: > > proc box[T](x: T): ref T = > new(result); result[] = x
Just a follow up question about this. If I understand correctly the above code will allocate memory for the result type and then immediately free it up when the ref is reassigned to point to a different memory location. Is there a more efficient way to tackle this without the unnecessary alloc/dealloc?