Welcome to a new episode of BambooTalk, this time I’m going to talk about the basic bricks of the language: comments, expressions, control structures, the assignment operator and cascading messages. I will talk about types in the next articles.
Comments
There are, like in ObjC, two kinds of comments, block comments (like in ANSI-C) and line comments (like in BCPL/ObjC/C99…) :
- Line comments start with two colons ‘
##‘ and runs until the end of the line,
- Block comments start with colon and hash signs ‘
#:‘ and finish with hash and colon signs ‘:#‘, comments can be nested and distributed over multiple lines.
All commented text is, obviously, ignored by the compiler. I chose not to use C-like // and /* */ because they represent valid binary messages, colon and hash signs aren’t valid binary message characters. For your information, SmallTalk uses double-quoted strings as comments: "this is a comment", though I prefer keeping this syntax for normal strings.
Expressions
In BambooTalk, every time you use a semicolon in C-like languages you will use a period ‘.’. Periods end a statement in BambooTalk just like they do in SmallTalk, this is because it’s closer to human languages and also because I find it nice. The semicolon, on the other hand is used for cascading messages, another nice feature from SmallTalk which I will talk about later.
Control structures
BambooTalk retains most construction from C-like languages:
- Conditions:
if(condition)
#: statements :#
else if(condition)
## statements
else
## statements
- Loops:
while(condition)
{ #: statements :# }
do
{ #: statements :# }
while(condition).
for(initialize . condition . increment)
{ #: statements :# }
- Switch (for now it’s defined like in C, but might change in the future):
switch(expression)
{
case value : ##statements
case value : #: statements :# break.
default : #: statements :# break.
}
- Collection iterations:
foreach(variable in collection)
{ #: statements :# }
- Keyed/Indexed collection iterations:
foreach(value_variable at key_or_index_variable in collection)
{ #: statements :# }
Other control structure can be added in the future. BambooTalk being a whole new language nothing prevents it from defining new keywords, I take advantage of this fact to introduce C#’s “foreach” construction and improve it a little bit. ObjC 2.0 defines the same construction, but uses the already existing “for” keyword from C to avoid the need of reserving an ugly “__foreach” keyword, like they did for “__block“.
So, BambooTalk defines “foreach(variable in collection) { #: statements :# }” which can iterate through any collection conforming to the fast enumeration protocol (yet to be defined) equivalent to ObjC 2.0′s.
It also defines the “foreach(value_variable at key_or_index_variable in collection) { #: statements :# }” construction equivalent to PHP’s “foreach (array_expression as $key => $value)“, which can iterate in any indexed or keyed collections, so it excludes set iterations. Any object conforming to the fast keyed enumeration protocol can be used with this foreach.
Along with those control structures, BambooTalk defines, like C-like languages, “break” to stop the execution of a loop or the flow of instruction in a switch, “continue” to go to the next iteration of a loop and “return” to stop the execution of a method and return control to the caller.
The sole actual operator of BambooTalk
As seen before, in BambooTalk “operators” aren’t operators but actual messages, in fact, BambooTalk only defines one operator. This operator is the assignment operator and is represented as a colon followed by an equal sign: “:=“. It is NOT inspired from Pascal (which I never touched) but from SmallTalk, which defines two operators, this one, and the return operator “^“.
This operator is evaluated from right to left, the value of the expression on the right is assigned to the variable defined on the left:
Example: a := b := c. ## the value of c is assigned to b and the value of b is assigned to a.
As I was thinking about the language design, a major C-user problem hit me: C reassign operators (like +=) are still valid messages in BambooTalk! The receiver of the message is passed as a reference to the message, so I wouldn’t be able to transform this statement “a += b;” into this “a = a + b;” without breaking the language coherence: the reference doesn’t allow the “variable” receiver to be changed from within the call (in ObjC, reassigning self does not affect the caller’s code), and enforcing special cases in the compiler is not an option (it’s ugly, error-prone and uselessly complex for nothing). So, to solve this problem, I thought about a new syntax for the language that would add more flexibility than normal reassign operators, and keep coherence of the language:
The reassignment syntax is as follow, “variable assign_op binary_message expression”.
For example: a := + b. is equivalent to a := a + b., the left operand is required to be a variable. Although the binary message represents a message, it will be evaluated last, for example “a := * b + c” would be transformed into “a := a * (b + c)” and not “a := (a * b) + c” as the messaging syntax usually suggests.
And last, but not least, due to right-to-left evaluation of (re)assignment operator, expressions containing multiple assignment operators are also evaluated from right to left.
Example: a := + b - c := * d + e. the first expression being evaluated is “d + e” then “c * (d + e)” reassigned to “c“, and then “a := + b - c” is evaluated.
Cascading messages
To finish with this article, I will talk about a nice feature from SmallTalk that I absolutely wanted in BambooTalk: cascading messages. The principle of cascading messages is about sending multiple messages to one receiver in the same expression. Only the first message of the cascading list has an explicit receiver, and all the other messages that follow uses the same receiver. The result of a cascading message is the result of the last message in the cascade: if previous messages return a value, this value is simply ignored, only the last return value counts. Cascaded messages are separated by semicolons.
Example: “a b; c; d; e; f.” this expression contains 5 messages and one receiver. The first message is “b” and its receiver is “a”, then each messages are sent to the same receiver. So, “a” receives sequentially the messages “b”, “c”, “d”, “e” and “f”, also the whole expression evaluates to the last message’s return value: on the caller’s point of view, the whole expression is equivalent to “a f.”, that is the message “f” sent to receiver “a”. Of course, if intermediate “b”, “c”, “d” and “e” messages were not doing anything, it would be useless to chain them.
Any kind of message can be used in cascading messages, for example: “a := 10. b := a + 5; * 4; - 1.” would assign the value 9 to “b” because “a – 1″ equals 9 and the return values of messages “+ 5″ and “* 4″ are simply ignored.
This construction is very useful as an alternative to big constructors, for example instead of “r := Rect newWithX: 0 y: 0 width: 10 height: 100.“, you can use the cascading messages as follow: “r := Rect new setWidth: 10; setHeight: 100; self.“. Note that the last message in the cascade is “self”, as I said before, the result of the whole cascading expression is the result of the last message: without self, the last message would be “setHeight:” which, like any setter, returns void, the result of the whole expression would be void, which is not suitable for an assignment. This is why “self”, that simply returns the receiver, is the last message in the cascade, so the result of the whole expression is the object we allocated at the beginning, namely the result of “Rect new”, and thanks to cascading messages, this instance also received “setWidth:” and “setHeight:” messages with 10 and 100 as arguments.
Some of those features might be difficult to understand, some of them might look weird, and some others are still in thinking process. Any comment, question or suggestion is welcomed. Thank you for reading.