In Halunke, Classes are objects. They consist of a dictionary that maps message names to functions. Objects are a wrapper around a dictionary. The dictionary contains the attributes of the object. The object knows its class, and when messages are send to the object, it will look up the according function in its class and call it.
Classes are created by sending a message to the Class object. One
of these messages is new attributes methods. Let’s create a
class:
(Class new 'Counter
attributes ["value"]
methods @[
"value" { |'self|
(self @ "value" else 0)
}
]
)
To create an instance of the class, we send the new message to
the class with a dictionary that represents the attributes:
('counter = (Counter new @["value" 0]))
Now we can send the value message to our counter, and we will
receive 0:
(counter value)
In our class definition, we first gave an array of attributes. You can imagine it as kind of whitelist for attributes: The attribute dictionary you pass to new can only have keys that are on this list. Now let’s look at the function that is called when you send the value message:
{ |'self| (self @ "value" else 0) }
Every function that is used as a method receives the object itself
as its first argument. This can be used to send messages to the
object itself. Each object can receive the @ else message. This
is used to look up attributes in the dictionary. Our function
therefore returns the value attribute or 0, if it was not set.
Now let’s add a method to increase the counter. Remember that objects are immutable. So we need to return a new counter with the value that is one higher than our current value:
"increase" { |'self|
(Counter new @["value" ((self value) + 1)])
}
We can use it like this:
('counter = (Counter new @["value" 0]))
('increased_counter = (counter increase))
The 'increased_counter will return 1 as its value.
Now you might want to have a custom constructor that needs less typing and is
more expressive. You can do that by introducing a class method that calls the
new method. Class methods receive the class as the first parameter.
(Class new 'Counter
attributes ["value"]
methods @[
"value" { |'self|
(self @ "value" else 0)
}
"increase" { |'self|
(Counter new @["value" ((self value) + 1)])
}
]
class_methods @[
"from" { |'self 'value|
(self new @["value" value])
}
]
)
Now we can create a counter like this:
('counter = (Counter from 5))