NOTE: I am not asking about difference between pointer and reference, and for this question it is completely irrelevant.
One thing I couldn't find explicitly stated -- what model does Nim use?
Like C++ -- where you have values and with new
you create pointers to data (in such case the variable could hold pointer to a pointer to a pointer to... to data)?
Or like C# -- where you have POD types as values, but user defined objects with referenced (implicitly)?
I spotted only dereferencing is automatic, like in Go.
Rephrase. You define your new type, let's say Student
(with name, university, address). You write:
var student ...?
student
hold actual data (of Student
type/class)student
hold a pointer to the datastudent
hold a pointer to a pointer to the dataOr some from those points are impossible?
By default the model is of passing data by value. When you create a var of a specific type, the compiler will allocate on the stack the required space for the variable. Which is expected, as Nim compiles to C, and complex types are just structures. But like in C or C++, you can have pointers too. There is the ptr
keyword to get an unsafe pointer, mostly for interfacing to C code, and there is a ref
to get a garbage collected safe reference (both documented in the References and pointer types section of the Nim manual).
However, note that even when you specify a proc
to pass a variable by value, the compiler is free to decide to pass it internally by reference if it considers it can speed execution and is safe at the same time. In practice the only time I've used references is when I was exporting Nim types to C and had to make sure both C and Nim pointed to the same memory. Remember that you can always check the generated C code in the nimcache
directory. You will see then that a var
parameter in a proc is just a pointer to its C structure.
Here is an example of a type with constructors to be created on the stack and passed in by value, and the corresponding pointer like version:
type
Person = object
age: int
name: string
proc initPerson(age: int, name: string): Person =
result.age = age
result.name = name
proc newPerson(age: int, name: string): ref Person =
new(result)
result.age = age
result.name = name
when isMainModule:
var
a = initPerson(3, "foo")
b = newPerson(4, "bar")
echo a.name & " " & $a.age
echo b.name & " " & $b.age
As you can see the code is essentially the same, but there are some differences:
ref
version allows you to return a nil
value, which you can treat as an error, while the value constructor forces you to raise an exception or change the constructor to use the var form mentioned below so you can return a bool indicating success. Failure tends to be treated in different ways.In C-like languages theres is an explicit syntax to access either the memory value of a pointer or the memory value pointed by it (dereferencing). In Nim there is as well, and it is the empty subscript notation ([]
). However, the compiler will attempt to automatically put those to avoid cluttering the code. Hence, the example doesn't use them. To prove this you can change the code to read:
echo b[].name & " " & $b[].age
Which will work and compile as expected. But the following change will yield a compiler error because you can't dereference a non reference type:
echo a[].name & " " & $a[].age
The current trend in the Nim community is to get rid of single letter prefixes to differentiate value vs reference types. In the old convention you would have a TPerson
and an alias for the reference value as PPerson = ref TPerson
. You can find a lot of code still using this convention.
initPerson
returning the value you could also have a init(x: var Person, ...)
. But the use of the implicit result
variable allows the compiler to optimise this, so it is much more a taste preference or requirements of passing a bool
to the caller.It can be either.
type Student = object ...
is roughly equivalent to
typedef struct { ... } Student;
in C, while
type Student = ref object ...
or
type Student = ptr object ...
is roughly equivalent to
typedef struct { ... } *Student;
in C (with ref
denoting a reference that is traced by the garbage collector, while ptr
is not traced).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With