Classes and Objects
The code examples are given for command-line Slag programs. To test the following examples in Plasmacore, type "gogo build" in a new project, set it up with project name "Test" and then edit src/test.slag and insert the given example, changing "class Test" to be "class Test : Screen".
Using a Class in Another File
When you start to have large files of code it's easier to segment them into different .slag files. When a programmer starts to do this they'll still want access to their code in other sections of their program.
To access the contents of another slag file just add:
You will, of course, remove the parenthesis in your code. Following that you will also replace "<filename>" with your actual .slag file name.
class Test METHODS method init local Name abe("Abe","Pralle") local var ty = Name("Ty","Heath") println( "$ and $ incorporated Plasmaworks" (abe.first,ty.first) ) # Prints: # Abe and Ty incorporated Plasmaworks println( //My name is $ - that's "$" on the roster.// (abe,abe.roster_form) ) # Prints: # My name is Abe Pralle - that's "Pralle, Abe" on the roster. endClass class Name( String first, String last ) METHODS method to_String.String return "$ $" (first,last) method roster_form.String return "$, $" (last,first) endClass
- Any number of classes may be defined per file. By default an object of the topmost class is created and its init() method is called as the program starting point.
- Classes are defined by section, with the two primary sections being METHODS and PROPERTIES (aka instance variables or object variables). Other sections include CLASS_METHODS and CLASS_PROPERTIES (for static class members).
- Slag's "initializers" are the constructors" of other languages. They are named "init".
- By default a program starts at the init() method of the top class definition in a file.
local Name abe("Abe","Pralle") local var ty = Name("Ty","Heath")
- Local variables must be preceded by the keyword "local".
- The syntax "local Name abe(...)" is shorthand for "local Name abe = Name(...)".
- Writing the class name followed by an parenthesized argument list will create a new object. The new keyword is not used as it is in other languages.
- "local var ty = Name(...)" is shorthand for "local Name ty = Name(...)". "var" is just a placeholder for whatever type the compiler determines is on the right-hand side of the assignment.
- No semicolons are required.
println( "$ and $ incorporated Plasmaworks" (abe.first,ty.first) )
- Writing "$+$=$"(a,b,a+b) is the shorthand equivalent of writing a + "+" + b + "=" + (a+b). Formatted strings use the syntax: "string" (args). Any dollar signs in the string are format markers that are replaced by the to_String() versions of arguments in the following argument list. This is a compile-time replacement.
- Properties (instance variables) may generally be directly accessed ("abe.first"). The concepts of public and private do not matter much in Slag; one of the primary reasons for using them does not apply (more on that later).
println( //My name is $ - that's "$" on the roster.// (abe,abe.roster_form) )
- Writing //string// is an alternate way to specify a literal string.
- Methods do not need parentheses if there are no arguments.
- Slag's keywords are verbose camelCase: class/endClass, while/endWhile, if/elseIf/else/endIf, etcetera.
class Name( String first, String last )
- Writing "Name( String first, String last )" is shorthand for:
class Name PROPERTIES first, last : String METHODS method init( String f, String l ) first = f last = l ... endClass
METHODS method to_String.String return "$ $" (first,last) method roster_form.String return "$, $" (last,first) endClass
- Methods are declared in the form "method name(Type1 param1, Type2 param22, ...).ReturnType". The parentheses may be left off if there are no arguments. The ".ReturnType" is left off if there is no return type.
- A trailing ":" is allowed on the method declaration (e.g. "to_String.String:"; writing it allows the body to be written on the same line if you so desire.
- When a method name incorporates a specific data type, that data type is capitalized as it was originally written.
Methods as Properties
class Test METHODS method init local Distance ruler() ruler.inches = 12 println( "A ruler is $(.2) inches or $(.2) cm." (ruler.inches,ruler.cm) ) local Distance kilometer() kilometer.km = 1 println( "A kilometer is $ meters and $ miles." (kilometer.m,kilometer.miles) ) endClass class Distance() PROPERTIES m : Real64 # Distance is stored in meters and converted to all other # unit systems on the fly. METHODS method cm( Real64 n ): m = n / 100 method km( Real64 n ): m = n * 1000 method inches( Real64 n ): cm = n * 2.54 method feet( Real64 n ): inches = n * 12 method miles( Real64 n ): feet = n * 5280 method cm.Real64: return m * 100 method km.Real64: return m / 1000 method inches.Real64: return cm / 2.54 method feet.Real64: return inches / 12 method miles.Real64: return feet / 5280 endClass
- Primitives are named Real64, Real32, Int64, Int32, Char, Byte, and Logical. The first five are equivalent to types double, float, long, int, and char in Java. "Byte" is equivalent to "unsigned char" in C++. "Logical" may be used as a Java "boolean", but Logical is a ternary type that supports literal values true, false, and void.
- The string format "$(.2)" causes a real number to be displayed with exactly 2 digits after the decimal point.
- Writing "obj.x = 5.0" is shorthand for "obj.x(5.0)" if an x(Real64) method exists. Such a method is called a property-set method.
- Writing "y = obj.x" is shorthand for "y = obj.x()" if an x().Real64 method exists (the "Real64" could be any return type). Such a method is called a property-get method.
- Do not be concerned as to whether "obj.x" is accessing a property or calling a method. Think of x as just a property in either case.
- In short you can write methods that act like variables.
Transparent Access Methods
- If you define property access methods, they will be called when you read or write a property.
- These access methods are transparent - outside of a class you do not know or need to know whether the variable is being directly accessed or whether its going through a property-set or property-get method.
- For a property "x : Real64", the property-get method that just returns the value of x would be "method x.Real64: return &x".
- For "x : Real64", the property-set method that takes a new value and just set the property would be: "method x( Real64 new_x ): &x = new_x". There is a shorthand as well: "method x(x):".
- An ampersand (&) bypasses access methods to allow direct property access.
Treasure Chest Example
class Test METHODS method init local TreasureChest chest(5000) println( chest.gold ) # prints -1 since the chest is closed chest.open println( chest.gold ) # prints 1000, the max amount endClass class TreasureChest( Int32 gold ) PROPERTIES is_open : Logical METHODS method open: is_open = true method close: is_open = false method gold.Int32 # Returns -1 if the chest is closed. if (not is_open) # All logical operators are spelled out in word form: # and, or, xor, not. return -1 endIf # Use ampersand (&) to bypass any transparent access # methods and directly access a property. return &gold method gold( Int32 new_amount ) # 1000 gold pieces is the max if (new_amount > 1000) new_amount = 1000 &gold = new_amount endClass
- Almost all arithmetic and bitwise operators may be made to work with objects of a given class by defining operator methods for that class.
- The binary operator methods that may be defined are: + - * / ^ & |, of the form "method op+(SomeType rhs).SomeType".
- The unary operator methods that may be defined are: - !, of the form "op-.SomeType".
- The assignment operator cannot be defined in this way.
- Neither += nor ++ (etc.) may be defined in this way as underneath they are not distinct operators. "x++" is shorthand for "x = x + 1" and "x += y" is shorthand for "x = x + y".
class Test METHODS method init local Time now("10:58") local Time interval("2:03") local Time one("1:00") println( "The time is $." (now) ) println( "$ after $ is $." (interval,now,now+interval) ) println( "$ before $ is $." (interval,one,one-interval) ) # Prints: # The time is 10:58. # 2:03 after 10:58 is 1:01. # 2:03 before 1:00 is 11:57. endClass class Time( Int32 hours, Int32 minutes ) METHODS method init( String time ) local var values = time.split(':') hours = values.to_Int32 minutes = values.to_Int32 method to_String.String return "$:$(02)" (hours,minutes) method op+( Time other ).Time local Time result(hours,minutes) result.hours += other.hours result.minutes += other.minutes return result method op-( Time other ).Time local Time result(hours,minutes) result.hours -= other.hours result.minutes -= other.minutes return result method minutes(minutes) # Transparent property-set for 'minutes'. hours += minutes / 60 &minutes %= 60 method hours(hours) # Transparent property-set for 'hours'. &hours = hours.wrapped(1,12) endClass