The goo spec (c)1999 Robey Pointer design influences, suggestions, and reality checks: Scott James Remnant, Greg Brown -- GOO stands for "Goo is Object Oriented". This is a quick tutorial and reference guide. It assumes you know a lot about programming, and is meant more as a reference for those of us writing and testing the goo compiler. 0. Miscellaneous 1. Variable Declarations 2. Expressions 3. Statements 4. Cheating 5. Classes 6. Class Variables 7. Function Declarations 8. Function Definitions and Calls 9. Interfaces 10. Creating Objects (Constructor) 11. Exceptions 40. Persistent Objects 41. Redefining a Class 99. OO Weirdness [more later?] (0) Miscellaneous Comments start at "//" and continue to the end of the line. Or, you can use C-style comments which are surrounded by "/*" and "*/". Backslash substitutions in strings: \ ignore linefeed \n LF \r CR \\ \ \" " \xHH char #HH, where HH is a hex number (ie, "\x3F") All strings are implicitly UTF-8 and 8-bit clean. This means they can store any character from 0 to 255. This also means that, unlike C, a zero character (\x00) does NOT delimit the end of a string. (1) Variable Declarations [ ] [ "[]" | "{}" ] [ "=" ] ";" * without a classname, the identifier is a scalar (float, int, or string) numCans; scalar * "[]" marks arrays groceries[]; array of scalars Beer mybeers[]; array of objects of class Beer * "{}" marks hashes (associative arrays) members{}; associative array An array or hash may contain another array/hash as one of its members. Example: bizarre{} = { "red": [ 3, 4 ], "blue": [ 1, 5, 6 ] }; Variables do not have to be explicitly declared -- they are implicitly declared the first time you use them. However, beware that your first access of the variable defines its type. If you access it as a scalar, it becomes a scalar and cannot be used as an array later. You may explicitly declare variables before you use them, though, if you like. A declaration is a valid expression, so it may be used anywhere in an expression or block of code. For example, to set two Turtle's to the same new Turtle: Turtle t1 = Turtle t2 = new Turtle; Note that goo would be just as happy with: t1 = t2 = new Turtle; since they are clearly being assigned as type type Turtle. (2) Expressions OPERATORS: (highest to lowest precedence) @ domain scope change ( ) [ ] grouping, list creation . class member referencing (...) function call [...] {...} [:] array or hash reference, array slice ++ -- increment, decrement (pre and post) ! ~ # keys logical not, string to-lower, length-of, keys list - + unary negative, positive new object creation .. string concatenation * / % multiply, divide, modulo + - add, subtract >> << binary left-shift, right-shift < > <= >= logical comparisons == != ~= in ~in logical equality or inequality, case-insensitive string equality, and substring matching is object type checking & binary and ^ binary xor | binary or as object type casting && and logical and || or logical or ?: expression "if" = += -= *= /= %= ..= assignment, the 5 math assignments, concat assign , separator The precedence is largely based on C precedence, so there should be no surprises. COMPARISONS: Tests for equivalence ("==", for example) compare scalars by trying to guess what they're meant to be. Goo remembers whether a scalar is holding an integer, a float, or a string, even though it will treat them all equally. For the purposes of comparison, if both sides are the same type of scalar, they will be compared in the obvious way. Otherwise, they will be compared according to the type of the left operand. Two objects compare equal only if they are pointing to the same underlying object. That is, if you create two objects with identical members, they will still compare as non-equal. VARIABLE EXPANSION: Values in expressions are either method calls, variable names, or constants. Obviously constants and method calls can only be rvalues. Constant scalars: 3 int (scalar) 2.998 float (scalar) "hello" string (scalar) undef the "nil" or "null" (undefined) scalar value Constant arrays: "[" *( "," ) "]" [5, 3, 10] Constant hashes: "{" ":" *( "," ":" ) "}" { "anchor": 5, "cherry wheat": 34 } These may be combined -- it's all perfectly legal: { "anchor": 5, "cherry wheat": [ 5, 3, { "x": 9, "y": 12 } ] } Indexing an array: "[" "]" (array indexes start at 1) myToys[2] Indexing a hash: "{" "}" beerTally{"anchor"} If the above combo-constant was stored in "beerTally", this expression would evaluate to "12": beerTally{"cherry wheat"}[3]{"y"} This is another perfectly valid way: x = "cherry wheat"; g = 3; beerTally{x}[g]{"y"} Method calls are distinguished by the "(" ... ")" following the identifier, and can't be used after any "[" ... "]" or "{" ... "}" pairs. It may be used before, though: getGrades("scott"){"math"} In this sense, you'll start to think, "Hey, so {} and [] are just operators like + and .!" You would be correct -- they are. Some of the odder things this allows are: x = getMagicNumber(); y = [ 1.0, 1.1, 1.3, 1.5, 2.2, 3.9, 5.8, 9.0 ][x]; and: pn = getName(); y = { "Robey": { "age": 24, "sex": "m" }, "Scott": { "age": 17, "sex": "yes" } }{pn}; if (y{"age"} > 18) { ... } That last one is an alternate way of doing an expr?a:b thing. An array "slice" is a segment of an array. This concept and syntax was stolen directly from python. g[] = myToys[3:5]; will set g to be an array made up of elements 3, 4, and 5 of myToys. Either parameter can be negative, which means to count from the end instead of the beginning (-1 is the last entry in an array). If the left parameter of a slice is missing, it's assumed to be 1. If the right parameter is missing, it's assumed to be -1. Thus g[] = myToys[:]; just makes a copy of myToys (from element 1, the first element, to element -1, the last element). Note that slices can't ever be assigned to (they can't be the left side of an assignment). Slices and array elements can be taken on a scalar. In that case, the scalar is treated as if it were an "array of characters". Thus if 'name' was a scalar, 'name[1]' would be the first character in that string. When used this way, the array element operator can't be assigned to (it can't be the left side of an assignment). To get the length of a string (scalar), use the # unary operator. (3) Statements For the purposes of goo, a block is equivalent to a statement. A block is: "{" *( ) "}" A statement can be an expression followed by a semicolon, a block, or one of the following constructs: "if" "(" ")" [ "else" ] Note that goo's "if" statement works like perl's (where braces are always required), and not like C's. This avoids confusion (read the Perl book to find out why). The expression is false only if it evaluates to "undef", 0, 0.0, the empty string, or an empty array or hash. All other values are true. "while" "(" ")" Pretty typical. Same values of "true" and "false" hold. "foreach" "(" { "," | "in" } ")" The is treated as a list of values. The is executed once for each member of that list, with the containing each value in turn. If is a scalar, only one iteration is done. If is an array, each member of the array is used, in order. If is a hash, each hash key is used, in what is effectively a random order. "for" "(" ";" ";" ")" This is equivalent to "for" in C. "switch" [ "(" ")" ] "{" *( *( "," ) ":" ) [ "else" ":" ] "}" There are two forms of the "switch" statement. If an expression is included in parens, it behaves similar to a C "switch" statement -- each item is implicitly compared "==" to the expression in parens. Unlike in C, the individual items do not have to be constants. Without an expression in parens, it behaves more like David Gries' "guard" statement. It acts like multiple "if" statements. All of the expressions that return true will have their statements executed, in order (unless/until a "done" is reached). [Note for C programmers:] C requires a "break" command at the end of each case in a switch to prevent it from executing the next case, even if the next case expression doesn't match. Goo doesn't do that. Instead, each case expression is evaluated and ONLY those that match are executed. So you don't need to put a "done" inside each case. If you want multiple expressions to execute the same piece of code, separate those expressions with commas in a single case. "done" ";" Break out of the current "while", "foreach", "for", or "switch" statement. "return" ";" Cause some value to be the value returned from a function. "throw" ";" Cause some value to be thrown as an exception (see later section on exceptions). "finally" Execute this statement before leaving the current block of code. Only one "finally" may be used per block. "catch" "(" [class-name]