Constructors and destructors
Sometimes you want to initialize the field of a struct or execute some action right after creating an instance of it. Spice enables you doing that, by supporting constructors. To clean up a struct instance, destructors can be used.
Constructors¶
Whenever you create a struct instance like this, Spice will automatically call the ctor method of this struct:
Constructors can also have arguments to pass some information from the caller to the constructor of the struct:
| Spice | |
|---|---|
The ctor method can also be called manually like calling other methods.
Constructor overloading¶
A struct can have multiple constructors with different parameter lists, just like function overloading:
| Spice | |
|---|---|
A constructor can delegate to another constructor of the same struct, by starting its body with a this.ctor(...) call:
The called constructor then initializes the fields, i.e. it calls the constructors of struct fields and stores the
default field values. The delegating constructor does not do this itself, so every field is constructed exactly once.
If the this.ctor(...) call is not the first statement, or its arguments access this (e.g. this.ctor(this.size)),
the fields are initialized by both constructors.
Copy constructors¶
When a struct value is copied (passed by value, returned by value, or assigned), Spice calls the copy constructor
if one is defined. The copy constructor takes a const reference to an instance of the same type:
| Spice | |
|---|---|
If no copy constructor is defined, Spice generates a default one that copies each field.
Destructors¶
You have the option to create a destructor by providing a dtor method on a struct. It does not allow any arguments and has no
return type, since it is a procedure. Destructors can be especially useful for de-allocating objects in heap memory, that were
allocated via malloc(). Whenever a struct variable goes out of scope somewhere in the program, the compiler searches for a
destructor and calls it if available.
Here is an example for a custom destructor:
| Spice | |
|---|---|
By-value parameters¶
A function, that takes a struct with a copy constructor by value, gets its own copy of the argument, even if the argument is a reference. The function owns this copy: it is destructed when the parameter goes out of scope at the end of the function, not when the caller's scope ends. Changes to the parameter therefore never affect the caller's value. A temporary, like the result of a constructor or function call, is moved into the parameter instead of copied, since the caller has no further use for it.
| Spice | |
|---|---|
Structs without a copy constructor, whose fields are all trivially copyable (e.g. a struct holding a handle), are passed as
bitwise copies instead. Those stay owned by the caller and are not destructed by the called function. Functions declared with
ext never destruct their parameters, so the caller destructs the copies it passes to them.
Visibility¶
Constructors and destructors follow the same visibility rules as other methods. A non-public constructor or destructor can only be called from the source file that defines it. This also applies to the calls, that the compiler inserts implicitly: copying a value of an imported struct requires a public copy constructor, and a local variable or field of an imported struct requires a public destructor, if the struct defines one. Otherwise, the compiler reports an insufficient visibility error.
| Spice | |
|---|---|