To modify a variable's type, change its properties. This will not affect new objects of the original type.
To modify a type directly, modify the properties on the type, not the variable.
obj v = # Declare a variable
type(v) #> obj; The variable is of type :obj;
v.prop = "abc" # Add a property to the variable
type(v) #> $v; The variable is now a new type
obj v2 = # Declare a new variable of the same original type
v2.prop #! UndefinedError: obj.prop has not been defined; The *base type* has not been modified to include the new property
type(v).prop #> abc; The type *of the variable* has been modified to include the new property
type(v).prop2 = "def" # Add another property, this time to the *type*, not the variable
type(newType) #> $newType; The type was modified, but a new type was not created
type(v) v3 = # Create a new variable of type :$v; (the modified type of the original variable)
v3.prop2 #> def; This new variable now has the new property, as the type was modified
As seen above, to create a class or type (exclusively called a type in Lang3), you must create a variable and modify its properties. You can then use its type (as given by the type() function) as a type like any other.
obj newVar = # Declare a variable of the base :obj; type with no value
type(newVar) #: obj ; The type of the variable is :obj;
newVar.prop = 1 # Add a property to the variable
type(newVar) #> $newVar; The type is no longer :obj;
newType = type(newVar) # Assign the type of the variable to a new variable
newType o = # You can now use the new type!
io.out(o.prop) #> 1
To avoid the need to assign the type of the modified variable to another variable, Lang3 has syntactic sugar that allows you to modify a type directly. Put a dollar sign $ in front of a variable when declaring it in order to directly declare and modify it as a type:
obj newType = # Declare a variable, with the base type :obj; and no value
$newType.prop = 1 # Add a property directly to the variable's type
newType o = # You can use the variable directly as a type for creating new objects/variables
o.prop #> 1
The above code is equivalent to:
obj newType =
type(newType).prop = 1
newType = type(newType)
newType o =
o.prop
In many languages, if you create an object from a given class, its value will be the object itself:
class A: # Create a class/type
prop = "abc" # Add a property to that class/type
a = A() # Create an object of that type
print(a) # <__main__.A object at 0x000001A2BC487550> - Accessing the object returns the object reference
print(a.prop) # "abc" - You can use the object to access its properties
However, in Lang3, every object has a root value in addition to the properties of an object:
A = # Declare a variable
A.prop = "abc" # Add a property to that variable
A a = 1 # Create an object of that type, with a root value of :1;
io.out(a) #> 1; Accessing the object returns the value of the object
io.out(a.prop) #> abc; You can use the object to access its properties
Any object (called the template object when used as a type) can be used as a type, and the new object (the target object) created of that type will inherit the children of the template object:
int target = # Declare a new variable with an explicit type and no value
type(target) #: int
target.prop = # Adding a property (in this case with no value) makes it different than the original type
newType = type(target) # Assign the new type to a variable
target t = 1 # Create an object of the new type
If a variable of an existing type with its children unchanged is used as a type, the target variable uses the original existing type:
int newType =
type($newType) #: int ; int is an existing type
$newType x =
type($x) #: int ; Since :newType; didn't modify the children of int in any way, it did not create a new type
If a type is changed twice identically, it still creates new types for both:
# Modify the :int; type once
int type1 =
$type1.prop = "abc"
type($type1) #: type1 ; a new type is created
# Modify the :int; type again identically
int type2 =
$type2.prop = "abc"
type($type2) #: type2 ; a second new type is created
type($type1) == type($type2) #: true ; the types are identical
type($type1) is type($type2) #: false ; the types are not the same object
Note that values cannot have their types modified:
loop newType = 1
type(newType) #: int
newType.prop = "abc" #! TypeError - The type of a variable's value cannot be modified (adding a property modifies the type)
a1 = A(1)
a2 = A(2)
A B = # Declare a new variable of type :A;
B.addThree = # Add a new child to the variable, creating a new type that inherits all the properties and methods of the previous type
A.prop1 = # :A.prop1; can be accessed and modified from anywhere
private A.prop2 = # :A.prop2; can only be accessed or modified within :A; or its children
readonly A.prop3 = # :A.prop3; cannot be modified after declaration, can be read or called from anywhere
private readonly A.prop4 = # :A.prop4; cannot be modified after declaration, can only be read or called within :A; or its children
A = # :A; can be accessed outside from anywhere, and properties and methods can be added or deleted
hidden A = # :A; can only be accessed from itself or its children, and appears undefined otherwise
locked A = # :A; can be accessed from anywhere, but properties and methods cannot be added or deleted
hidden locked A = # :A; can only be accessed from itself or its own children, and properties and methods cannot be added or deleted
Note that
privateandhiddenare similar in that they have the same effect on a variable's value or a variable's object reference respectively, and same goes forreadonlyandlocked