Classes
NOTE - Everything listed on this page DOES work even tho there are not examples for everything they do indeed work if you wish to try it out.
Rather unconventionally Sputnik requires a ; to end a class statement although not a limitation of the parser but I just thought it looked cool.
Regular class :
Class <name> { statements ... functions ... operator overloads ... casting overloads ... }
Extender class that adds functions and features to an existing class :
Class extends <name> { statements ... functions ... operator overloads ... casting overloads ... }
Inheritance class that inherits functions and features from an existing class :
Class <name> extends <parentname> { statements ... functions ... operator overloads ... casting overloads ... }
Inheritance class that inherits functions and features from multiple existing classes :
Class <name> extends <parentname>, <parentname>, <parentname>... { statements ... functions ... operator overloads ... casting overloads ... }
Description
Features
Statements
Variables
Static Variables
Properties
A property works like a normal variable however instead of returning or setting a variable it executes code when you try get/set the variable take the example below
Class cat { # Define a new property my $Test { # Rquired block for it get # Define the GET accessor { # Its block and code to execute say "Getting the value"; return $Test; } set # Define the SET accessor { # Its block and code to execute say "Setting to $value"; $Test = $value; } } } $a = new cat(); $a->$Test = 77; say "Value: " . $a->$Test; # Prints # Setting to 77 # Getting the value # Value: 77
Inside the GET or SET block the property name becomes a variable so $Test is a property but inside the GET or SET it is a variable like any other and you can get/set to it of course you can choose to ignore the variable entirely and do anything you want inside the GET/SET.
Of note :
- All properties are public and cannot be private however you could restrict the property to only the GET accessor if you wish.
- You can have only one GET accessor.
- You can have only one SET accessor.
- You may have one of each
- If you somehow create a normal variable with the same name as the property it will override the property.
Abstract/Override Properties
Works exactly same as property above but this time it will be marked as abstract so any class inheriting our class must implement a property by the same name as this one.
To implement it you must use the override keyword as shown in the example below.
Class cat { Abstract my $ID { } } Class foo extends cat { my $_id; override my $ID { get { return ++$_id; } } } $a = new foo(); say "UniqueID: " . $a->$ID; say "UniqueID: " . $a->$ID; say "UniqueID: " . $a->$ID; say "UniqueID: " . $a->$ID; say "UniqueID: " . $a->$ID; # Prints # UniqueID: 1 # UniqueID: 2 # UniqueID: 3 # UniqueID: 4
Of note :
- Since this is an abstract class you do not define a GET or SET accessor or else you will get an error.
Functions
Public Functions
By default all functions are public and there is no *Public* keyword since they are automatically public.
Private Functions
By default all functions are public and there is no *Public* keyword since they are automatically public however if you want a function to be private you must insert the "Private" keyword before the function.
Once private is defined you can call the function by name inside the class and by using $this-> but you can't call the function from outside the class this will prevent people from using functions that could cause functions such as internal functions that must only be used by the class itself.
Class Test { Function __Construct() { say "Made..."; } Function Testy() { say "Testy"; Foo("Called from class"); $this->Foo("Called from class THIS"); } Private Function Foo($value) { say "Foo: $value"; } } $a = new Test(); $a->Testy(); $a->Foo("called from pointer"); # Fails cannot access private function # Prints # Made... # Testy # Foo: Called from class # Foo: Called from class THIS # then throws an exception
Abstract/Override Functions
Works exactly same as functions above but this time it will be marked as abstract so any class inheriting our class must implement a function by the same name as this one.
To implement it you must use the override keyword as shown in the example below.
// Define a class we will inherit Class EngineInfo { // define an abstract function abstract Function Engine() { } // define two abstract properties Abstract my $GearVer { } Abstract my $GearBox { } } // Define the final class Class Car extends EngineInfo { // override the abstract function Engine() override Function Engine() { return "V8"; } // streamlined property override my $GearVer { get { return "1.0"; } } // expanded property override my $GearBox { get { return "12Gears"; } } } my $c = new Car(); say "Engine: " . $c->Engine(); say "GearVer: " . $c->$GearVer; say "GearBox: " . $c->$GearBox; // PRINTS // Engine: V8 // GearVer: 1.0 // GearBox: 12Gears
Of note :
- Since this is an abstract class you do not define any statements in the { } block of the abstract function or else you will get an error.
Static Functions
Static functions can't be private.
Magic Functions
A magic function is basically a function that starts with __ and gets executed when a specific core function is used with the class variable in its context here is an example
Class Test { my $data = array(); # A simple array to hold our data Function __Construct() # Is called when you do new ClassName() { say "__Construct() called"; } Function __Destruct() # Is called when you do unset($class) { say "__Destruct() called"; } Function __Set($key, $value) # Is called when you do $class['key'] = { say "__Set() called with key '$key' and value '$value'"; $data[$key] = $value; return true; } Function __Get($key) # Is called when you do $class['key'] { say "__Get() called with key '$key'"; return $data[$key]; } Function __Unset($key) # Is called when you do unset($class['key']) { say "__Unset() called with key '$key'"; unset($data[$key]); return true; } Function __IsSet($key) # Is called when you do isset($class['key']) or isset($class) { # The key will be NULL if this was called using isset($class) say "__IsSet() called with key '$key'"; return isset($data[$key]); } Function __Call() # Is called when you do $class() and try use it as a function { say "Hello from _Call"; # we could use params and return a value } Function PrintAll() # Just print the current data the class holds { printr $data; } } $a = new Test(); $a(); # Treat the class as a function $a['Foo'] = "Bar"; # Set key 'Foo' to 'Bar' $a['Cat'] = "Meow"; # Set key 'Cat' to 'Meow' say "Foo is: " . $a['Foo']; # Get key 'Foo' say isset($a); # Check if the class itself is set say isset($a['Foo']); # Check if the key 'Foo' is set $a->PrintAll(); # Print what the class contains unset($a['Foo']); # Unset the key 'Foo' $a->PrintAll(); # Print what the class contains unset($a); # dispose of the class printr(vardump($a)); # NULL
Magic Functions/Properties (others)
These magic functions and properties are used by other core functions that are nothing to do with classes directly (usually)but will work classes in a special way if you extend or do something that it requires.
- Count( ) -- This lets you override what number count() will return when it is used against the class
- JsonEncode( ) -- This one lets you control what gets serialized and how
Operator Overloads
Cast Overloads
Embedding
A class can be embedded inside an IF statement (or any statement) so that it can be created on a conditional for example:
// Check if the class already exists and // if it does already exists don't create it if (!ClassExists("Cat")) { // Create the class using the Embedded keyword Embedded Class Cat { Function __construct() { say "testy!"; } }; // note ; is required here } $a = new cat(); // PRINTS // testy!
Remarks
Examples
Creating Classes
Using Classes
Inheriting Classes
Extending Classes
Multiple Inheritance Classes
Sputnik supports multiple inheritance in a rather unique and powerful way.
// Define a class we will inherit Class EngineInfo { // define an abstract function abstract Function Engine() { } // define two abstract properties Abstract my $GearVer { } Abstract my $GearBox { } // define a normal Function // the final class will inherit this // and since it is not an abstract it will // appear as if it was literally inside the // original Function EngineTest() { say "Testing engine..."; } } // Define another class we will inherit Class CarColour { // define an abstract property Abstract my $Colour { } // define a normal Function // the final class will inherit this // and since it is not an abstract it will // appear as if it was literally inside the // original Function ColourTest() { say "Testing colours..."; } } // Define the final class // We will multiple inherit both // EngineInfo AND CarColour Class Car extends EngineInfo, CarColour { // override the abstract function Engine() override Function Engine() { return "V8"; } // streamlined properties override my $GearVer { get { return "1.0"; } } override my $Colour { get { return "Red"; } } // expanded property override my $GearBox { get { return "12Gears"; } } } my $c = new Car(); say "Colour: " . $c->$Colour; say "Engine: " . $c->Engine(); say "GearVer: " . $c->$GearVer; say "GearBox: " . $c->$GearBox; $c->EngineTest(); $c->ColourTest(); // PRINTS // Colour: Red // Engine: V8 // GearVer: 1.0 // GearBox: 12Gears // Testing engine... // Testing colours...
Cast Overloading
Sputnik allows you to overload all the castings such as (int)value etc this is useful if you have a class that uses multiple variables and you would like them all added together each time you use (float)$myclass (or any cast you are doing such as (string) also it will run the cast if the function you are using wants to convert the variable into a string such as print()).
Overloading Cast: null
Overloading Cast: char
Overloading Cast: byte
Overloading Cast: sbyte
Overloading Cast: uint16
Overloading Cast: uint32
Overloading Cast: uint64
Overloading Cast: int16
Overloading Cast: int32
Overloading Cast: int64
Overloading Cast: intptr
Overloading Cast: uintptr
Overloading Cast: long
Overloading Cast: float
Overloading Cast: double
Overloading Cast: string
Class Account { my $Name; my $Credits; Function __construct($Name = "", $Credits = 0) { $this->$Name = $Name; $this->$Credits = $Credits; } Operator "string" // This will be done whenever somebody uses (string)$ourclass { return "Account '$Name' Credits '$Credits'"; } } $nacc = New Account("FoX", 777); println( (string)$nacc ); // Prints Account 'FoX' Credits '777'
Overloading Cast: binary
Operator Overloading
Sputnik allows you to overload a vast array of operators on your classes this is very helpful for all kinds of things example imagine you have a class that contains 3 varibles X Y and Z and you want to add another classes variables X Y Z onto yours creating a += operator you could quite simply do just that example:
Without overloads:
$vec1->$x += $vec2->$x; $vec1->$y += $vec2->$y; $vec1->$z += $vec2->$z;
As you can see we needed 3 lines of code to do that and doing this over and over in many places of the code will cause a lot of repeat code also what if later we decide we need to add a third variable after z? We would need to go back and change everything...
However if we overload the += operator we can do this:
$vec1 += $vec2;
See how much easier that was? And if we add a new variable or even several later we can just fix our single += overload function and it will automatically fix every single peice of += in your code that uses it.
See the examples below for what you can overload and exactly how to do just that.
Overloading =
You can overload the = such as $a = 10;
However you must remember once this is overloaded you cant change the variable by simply $a = null;
Since it will just use the overloaded function instead of setting the variable.
To delete a variable you have given = casting to you must use unset($a); instead.
Overloading +=
Overloading -=
Overloading *=
Overloading **=
Overloading /=
Overloading %=
Overloading .=
Overloading ..=
Overloading ^=
Overloading &=
Overloading |=
Overloading >>=
Overloading <<=
Overloading >>>=
Overloading <<<=
Overloading &&=
Overloading ||=
Overloading |
Overloading ^
Overloading &
Overloading +
Overloading -
Overloading *
Overloading **
Overloading /
Overloading %
Overloading .
Overloading <<
Overloading >>
Overloading <<<
Overloading >>>
Overloading ++
Class Vec3 { my $x = 0; my $y = 0; my $z = 0; Function __construct($x1 = 0, $y1 = 0, $z1 = 0) { $this->$x = $x1; $this->$y = $y1; $this->$z = $z1; } Operator "++" { $this->$x++; $this->$y++; $this->$z++; } } $cat1 = new Vec3(10, 20, 30); println("BEFORE ++"); println("Class variable X: " . $cat1->$x); println("Class variable Y: " . $cat1->$y); println("Class variable Z: " . $cat1->$z); $cat1++; println("AFTER ++"); println("Class variable X: " . $cat1->$x); println("Class variable Y: " . $cat1->$y); println("Class variable Z: " . $cat1->$z); // Prints // BEFORE ++ // Class variable X: 10 // Class variable Y: 20 // Class variable Z: 30 // AFTER ++ // Class variable X: 11 // Class variable Y: 21 // Class variable Z: 31
Overloading --
Class Vec3 { my $x = 0; my $y = 0; my $z = 0; Function __construct($x1 = 0, $y1 = 0, $z1 = 0) { $this->$x = $x1; $this->$y = $y1; $this->$z = $z1; } Operator "--" { $this->$x--; $this->$y--; $this->$z--; } } $cat1 = new Vec3(10, 20, 30); println("BEFORE --"); println("Class variable X: " . $cat1->$x); println("Class variable Y: " . $cat1->$y); println("Class variable Z: " . $cat1->$z); $cat1--; println("AFTER --"); println("Class variable X: " . $cat1->$x); println("Class variable Y: " . $cat1->$y); println("Class variable Z: " . $cat1->$z); // Prints // BEFORE -- // Class variable X: 10 // Class variable Y: 20 // Class variable Z: 30 // AFTER -- // Class variable X: 9 // Class variable Y: 19 // Class variable Z: 29
Overloading ==
Overloading ===
Overloading !=
Overloading !==
Overloading <
Overloading <=
Overloading >
Overloading >=
Overloading <>
Overloading eq
Overloading eqi
Overloading neq
Overloading neqi
Overloading cmp
Overloading cmpi
Overloading lt
Overloading gt
Overloading le
Overloading ge
Overloading lti
Overloading gei
Overloading lei
Overloading gei
Overloading lg
Overloading lgi
Overloading ||
Overloading &&
Overloading []
Class Testy { my $Values; Function __Construct() { $this->$Values = array(); println("A new Testy() class was made"); } Function __Deconstruct() { $this->$Values = array(); println("A Testy() class was destroyed"); } Function PrintMe() { println("Values BELOW"); printr($Values); println("Values ABOVE"); } // Overload the [] operator // Note that you don't get the value that is going to // to the [] this is because Sputnik doesn't yet know // what is going inside it however it knows the array // must be extended to allow something to go inside it. // So we simply extend the array and return a pointer to it // This will allow the array element to be set later Operator "[]" { // & means return a pointer to new index return &$this->$Values[]; } } my $Testy = new Testy(); // Now we use use the new index that was returned and place stuff in it // However it is being returned as a POINTER so to make use of it we // resolve it back into a variable using the * symbol. // * Causes a pointer to become as if it was the actual object. *$Testy[] = "One"; *$Testy[] = "Two"; *$Testy[] = "Three"; $Testy->PrintMe(); Unset($Testy);
Overloading []!
Class Testy { my $Values; Function __Construct() { $this->$Values = array(); println("A new Testy() class was made"); } Function __Deconstruct() { $this->$Values = array(); println("A Testy() class was destroyed"); } Function PrintMe() { println("Values BELOW"); printr($Values); println("Values ABOVE"); } // Overload the [] operator // Note that you don't get the value that is going to // to the [] this is because Sputnik doesn't yet know // what is going inside it however it knows the array // must be extended to allow something to go inside it. // So we simply extend the array and return a pointer to it // This will allow the array element to be set later Operator "[]" { // & means return a pointer to new index return &$this->$Values[]; } // Overload the []! operator // Same as above nothing special here Operator "[]!" { return &$this->$Values[]!; } } my $Testy = new Testy(); // Now we use use the new index that was returned and place stuff in it // However it is being returned as a POINTER so to make use of it we // resolve it back into a variable using the * symbol. // * Causes a pointer to become as if it was the actual object. *$Testy[] = "One"; *$Testy[] = "Two"; *$Testy[] = "Three"; *$Testy[]! = "Zero"; $Testy->PrintMe(); Unset($Testy);
Overloading [<>]
Class Testy { my $Values; Function __Construct() { $this->$Values = array(); println("A new Testy() class was made"); } Function __Deconstruct() { $this->$Values = array(); println("A Testy() class was destroyed"); } // Overload the [] operator // Note that you dont get the value that is going to // to the [] this is because Sputnik doesnt yet know // what is going inside it however it knows the array // must be extended to allow something to go inside it. // So we simply extend the array and return a pointer to it // This will allow the array element to be set later Operator "[]" { return &$this->$Values[]; } // Overload the []! operator // Same as above nothing special here Operator "[]!" { return &$this->$Values[]!; } // Overload the [<>] operator // Same as above nothing special here Operator "[<>]" { return VarDump($Values); } } my $Testy = new Testy(); *$Testy[] = "One"; *$Testy[] = "Two"; *$Testy[] = "Three"; *$Testy[]! = "Zero"; println( *$Testy[<>] ); Unset($Testy);
Overloading [<=>]
Class Testy { Operator "[<=>]" { return array("key" => "value"); } } my $Testy = new Testy(); printr $Testy[<=>];