Classes and Objects
From Plasmaworks
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".
Contents |
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:
"[include <filename>]"
You will, of course, remove the parenthesis in your code. Following that you will also replace "<filename>" with your actual .slag file name.
Basics
Name Example
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
Name Analysis
class Test
- 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.
METHODS
- 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).
method init
- 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.
endClass
- 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
Distance Example
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
Distance Analysis
- 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
Operator Methods
- 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".
Time Example
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[0].to_Int32
minutes = values[1].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