Release Notes


Cobra 0.5 adds dynamic typing, the trace statement, better error checking and fixes several bugs.

Additions / Major Improvements

class Person get name as String return 'Blaise' class Car get name as String return 'Saleen S7' class Program shared def main assert .add(2, 3) == 5 assert .add('Hi ', 'there.') == 'Hi there.' .printName(Person()) .printName(Car()) def add(a, b) as dynamic return a + b def printName(x) print # dynamic binding

In general, all decisions about dynamic values are deferred until run-time where they will either succeed or throw an exception. Some operations, such as assigning a value to a dynamic variable, will never throw an exception. Some statements such as print, trace, if and while work with any kind of object/value and therefore never complain at run-time about the actual value of a dynamically typed expression.

In code, you can refer to the type as dynamic, but there are three places where you need not bother because absence of typing implies dynamic:

Dynamic typing offers more flexibility, but with costs including decreased performance. This is summarized here:

def add(a, b) as dynamic return a + b # + flexible (any type with "+" operator works) # + fast prototyping # + less brittle wrt other software components that change unpredictably # + more reusable # - errors detected late (run-time) # - one error reported at a time (the first one that throws an exception) # - slow at run-time # - fat at run-time (values must carry type information; boxing) # - difficult IDE support # (Intellisense/autosuggestion requires complex analysis and/or execution of code) def add(a as decimal, b as decimal) as decimal return a + b # - inflexible # - slower coding / more typing # - more brittle (to change program to `float` you must find and replace everywhere) # - less reusable (cannot use with int and float) # + errors detected early (compile-time) # + multiple errors reported (every one that the compiler can find) # + fast at run-time # + slim at run-time (values need only carry data) # + easy IDE support (Intellisense/autosuggestion)

Note that "nilable" trumps dynamic: You cannot assign nil to a variable or property of type dynamic, but you can do so to one of type dynamic?.

Note that there are some changes with the introduction of dynamic. The types for empty collection literals now use dynamic:

t = [] # t is a List<of dynamic> now, not a List<of Object> d = {} # d is a Dictionary<of dynamic, dynamic>

Also, the type returned from calling a System.Type is now dynamic instead of Object:

def makeNamedObject(Type type) as dynamic obj = type() # obj is dynamic instead of Object now trace # `name` is looked up at runtime since `obj` is dynamically typed return obj # You can typecast if you know the base type involved: def makeNamedObject(Type type) as INamedObject obj = type() to INamedObject trace return obj

Other Enhancements

Compile-time Error Checking

The syntax for inheritance is to put "inherits BaseClass" on the following line, indented.
def foo(String s) # error: The correct parameter syntax is "paramName as ParamType". Try "s as String". ... int i = 0 # error: The correct local variable syntax is "name as Type" or "name = initValue". Try "i as int".
raise Exception('message') # error: The "raise" keyword may be used in the future to raise events. # If you are trying to throw an exception, use the "throw" keyword.
Generic parameter names must start with an uppercase letter in order to
avoid collisions with other identifiers such as arguments and local variables.