Release Notes

Summary

Cobra 0.7 adds class level invariant contracts, support for .NET attributes, out and inout arguments, event listening, a FORTH interpreter and fixes another round of bugs.

Language Improvements

invariant

In continued support of Eiffel-style contracts, Cobra 0.7 adds the optional invariant clause to class, interface and struct declarations:

class Player invariant .name.length .score >= 0 .isAlive implies .health > 0

Invariants are executed at the end of all initializers, methods, properties and indexers similar to the ensure clause of such members. Invariants are useful in at least the following ways:

Attributes

The .NET platform supports having "attributes" attached to declarations which can be used by compilers or through reflection for various effects. For example, some testing frameworks use attributes to mark which methods contain test code. In Cobra, attribute declarations are preceded by has which answers the question "What attributes does the method have?" A: "It has ..."

class ForthMachine def dup has BuiltIn ... def printStack has BuiltIn('.S', doesPrint=true) ...

Some rules about attributes:

Abstract Classes

Classes and their members can be marked abstract like so:

class Entity is abstract get name as String return .getType.name def act is abstract

Some rules about abstract classes and members:

In less formal terms, abstract classes help document the intent of the class. They also relieve you of having to create dummy implementations of abstract methods that return meaningless values or throw exceptions. Finally, because they are a language level feature, the compiler can assist you by blocking the instantiation of such classes or by listing abstract members you forgot to implement in your concrete subclass.

out and inout

The .NET platform supports pass-by-reference arguments. Cobra now understands the methods that use them in libraries and can declare them as well. A common use for them is to "return" multiple values as seen here:

class Example def main is shared w = r = 0 .divMod(15, 10, out w, out r) assert w == 1 assert r == 5 def divMod(numerator as int, denominator as int, whole as out int, remainder as out int) is shared whole = numerator // denominator remainder = numerator % denominator

Events

Cobra can now listen to and subsequently ignore .NET events:

listen saveButton.onClick, ref .save ignore saveButton.onClick, ref .save

Note the use of ref (for "reference" or "refer to") as a prefix to prevent method invocation. As a prefix, it also aids readability by indicating immediately that what follows is a reference and not an invocation.

Language and Library Refinements

get foo from var is protected
print to file print 'Started at', DateTime.now .computeStuff print 'Stopped at', DateTime.now

Now at any point, including inside .computeStuff, you can write CobraCore.printDestination.flush or some such.

Wow, this was overdue! I looked for #file a long time ago but didn't find it so never realized there was, in fact, a #line directive in C# that optionally took the file name. Now if you type "cobra -d myprogram" and it throws an exception you will see a stack with the correct file names and line numbers.

Command Line Improvements

cobra -sharp-args:'-main:Bar' foo.cobra
$ cobra -d -c foo.cobra bar.cobra
$ mono --debug foo.exe

But if you don't need the separation between compiling and running, you can do both in one shot:

$ cobra -d foo.cobra bar.cobra

Sample Programs

Added forth.cobra which interprets a subset of the stack-based language FORTH. Just for fun.

In Sizes.cobra, removed a stray assert false and fixed various warnings. Also, made it recover gracefully from I/O errors.

Fixes

Technical Notes