This makes them very easy to use and discover. After typing my_class( we get a suggestion list of all possible constructors. Additionally it’s possible to make default constructor private and inaccessible, forcing us to use custom constructor.
Verse constructors seem to not differ much from functions? Other then a weird syntax with let, blocks and specific rules when multiple constructors are called.
I thought maybe they can be used for initializing values for variables but no:
The major value of Verse constructor functions is their ability to delegate construction to some other constructor function. They are similar to C++'s member initializer list syntax and delegating constructors, but many different constructor functions can be defined for a class external to the class and with arbitrary names. For example,
class1 := class:
X:int
Y:int
Z:int
MakeSomeClass1<constructor>(Arg1:int, Arg2:int) := class1:
X := Arg1
Y := Arg2
Z := Arg1 + Arg2
MakeSomeOtherClass1(Arg1:int) := class1:
MakeSomeClass1<constructor>(Arg1, Arg1) # delegate to another constructor
Z := Arg1 # except override what the other constructor did for Z
This delegating applies to inherited classes, as well, with similar syntax.
class1 := class:
X:int
Y:int
ZeroClass1<constructor>() := class1:
X := 0
Y := 0
class2 := class(class1):
Z:int
ZeroClass2<constructor>() := class2:
ZeroClass1<constructor>()
Z := 0
If you don’t intend to use a constructor function with other constructor functions, you may be better served with a plain function.
There is also another use: easy partial updates of a class without using a var field. For example,
class1 := class:
X:int
Y:int
CopyClass1<constructor>(Arg:class1) := class1:
X := Arg.X
Y := Arg.Y
var X:class1 = class1{X := 1, Y := 2}
set X = class1:
CopyClass1<constructor>(X)
Y := X.Y + 1
Whenever a field is added to class1, only CopyClass1 needs updating, and not all the partial updates. This mimics deep mutation available to structs.