Locus
Locus is a language built and designed to interoperate with Objective-C. Its native types are Objective-C types; at its very lightest, it serves as a definition syntax for NSArray, NSDictionary, and NSString instances.
This article assumes familiarity with Objective-C, and, to some degree, the Foundation framework in Cocoa. Locus can be used in isolation, but it shines best with Objective-C.
Literals
Locus’ syntax is designed to be simple and clear, and as such it borrows a lot from JavaScript, especially JSON. Arrays, dictionaries, and strings are taken outright from it:
[1, 2, 3]
{ one: 1, two: 2 }
"stringy!"
Dictionary literals also provide the basis of Locus’ object-orientation; as in JavaScript, dictionaries double as objects, and methods assigned to slots in the dictionary can be called via messages.
Methods
To that end, methods are defined with a vaguely Ruby-ish syntax:
method = { x: 1, y |
x * y
}
Here x has a default value, 1, but y is unspecified. You would call it like this:
method(y: 2)
method(x: 2, y: 3)
method(2, 3) # same as x: 2, y: 3
method(2) # same as y: 2
Objects
As discussed, putting methods into dictionaries gives you object-orientation. You could do that like this:
Rectangle = {
width: 1,
height: 1,
area = {
width * height
}
}
As well as giving an example of argument-less methods, this also shows encapsulation—these methods have access to slots bound in their context, in this case width and height.
After Rectangle has been defined, if you wanted to add a perimeter calculation to it, you could do so easily like so:
Rectangle perimeter = {
2 * width + 2 * height
}
Locus respects the order of operations.
Messages
Dictionary/object access is done by chaining symbols together separated by spaces. So if you had a Rectangle instance named rect you would get its perimeter like so:
rect perimeter()
If a method takes a single argument, you can call that method with a literal (not a variable) argument omitting the parentheses that would normally wrap its argument list. This is done for pure prettiness; compare the following two equivalent method calls:
foo([1, 2, 3])
foo [1, 2, 3]
The leading space in the second example can be omitted, which can make methods seem like they’re taking a subscript operator (as in C). This allows the syntax to represent both methods taking e.g. arrays and methods that take an index into their objects with the same syntax. Compare:
sum [1, 2, 3]
matrix at[1, 2]
The same syntax is used, with the same meaning to the language, but the latter looks a lot like indexes in C. This flexibility also applies to other literals:
[1, "two"] collect { each |
each description()
}
print "I am a banana!"
sin 3.1415
Unlike in Ruby, however, if there are multiple arguments, the parentheses are required.
Expressions
Expressions can be separated either by newlines (and other optional whitespace) or by semicolons or both:
1
2
is equivalent to:
1 ; 2
As you may have noticed before, methods do not use an explicit return statement; instead, the value of a set of expressions in a block is the value of the last expression.
Further, expressions can be extended across multiple lines by using the \ character at the end of the line, as in C macros and bash scripts, making these equivalent:
NSAutoreleasePool alloc \
init
NSAutoreleasePool alloc init