Introduction

This is an introduction to the Cobra programming language. It assumes you already know one or more high level languages such as Python, C#, Java, C++, Visual Basic, PHP, Ruby, etc.

Cobra is an imperative, high-level, object-oriented language with direct support for contracts, unit tests and compile-time nil tracking. It has namespaces, classes, interfaces, generics, methods, properties, indexers, variable number of args, overloading, exception handling and garbage collection. It has a high-level syntax with indented blocks, doc strings, list literals, dictionary literals, set literals, in operator, slicing, for expressions, if expressions, assert, and more.

That may sound like a lot, but its complexity is in the same neighborhood as other high-level languages, most of which have been accumulating features since their initial release (for example, Python and C#).

Let's get started with "Hello, world.":

class Hello def main print 'Hello, world.'

Cobra uses indentation to denote code structure since adept programmers do this anyway in languages that don't even require it (C#, Java, C++, etc.). In Cobra, one INDENT is accomplished by one TAB or four SPACES. Mixing tabs and spaces in a single line is not allowed and will produce a compiler error as mixing the two is always problematic.

Cobra is supported on both Microsoft(R) Windows(R) as well as Unix-like systems (Mac, Linux, etc.) via Microsoft .NET and Novell Mono, respectively. At the command line, on Windows:

> cobra hello.cobra
Hello, world.

And on Posix:

$ cobra hello.cobra
Hello, world.

A hello.exe is left after the execution and, if you want, you can compile a Cobra program without running it. In the examples below, the program is then run directly:

Windows:
> cobra -compile hello.cobra
> hello
Hello, world.
Posix:
$ cobra -compile hello.cobra
$ mono hello.exe
Hello, world.

You can specify "-c" for "-compile". Now let's print the Fibonacci sequence:

class Fib def main n = 10 a = 0 b = 1 for i in n print b save = a a = b b += save
1
1
2
3
5
8
13
21
34
55

Note that a statement like n = 10 is really a shorthand for n as int = 10. Cobra infers the type for a local variable from the value it is initialized with. The type is fixed from that point on—attempting to assign a string to n will give a compile-time error. Type inference allows for clean, quick coding while the fixed type enables better error checking and faster execution.

As a convenience, you can assign multiple items at a time:

class Fib def main n, a, b = 10, 0, 1 for i in n print b a, b = b, a + b

Let's keep the main small and break out Fib into more library-oriented code:

class Fib def compute(count as int) is shared a, b = 0, 1 for i in count print b a, b = b, a + b class Program def main Fib.compute(10)

Now Fib.compute can be used from anywhere and the number of elements to compute can be passed as an argument. But its output is still going directly to the console instead of being returned to the caller. We can fix that by having it return a list:

class Fib def compute(count as int) as List<of int> is shared list = List<of int>() a, b = 0, 1 for i in count list.add(b) a, b = b, a + b return list class Program def main i = 1 for n in Fib.compute(10) print '[i]. [n]' i += 1
1. 1
2. 1
3. 2
4. 3
5. 5
6. 8
7. 13
8. 21
9. 34
10. 55

The List<of int> is an example of a generic where type arguments are passed to construct the final type. In this case, the type is spoken as "list of int". Generics increase readability, type safety, and sometimes, performance.

To instantiate any class, whether generic or not, call it with parens ()s. Some classes will, of course, take arguments for their initialization.

Also, introduced in the above example is string substitution where any Cobra expression can be embedded in a string by surrounding it with square brackets. This turns string literals into a kind of mini-templating language.

And finally, the += operator is a shorthand for left = left + right and may also be more efficient.

Now let's take a more object-oriented approach by making the Fib class an actual list of the Fibonacci numbers, as opposed to a "computer of them":

class Fib inherits List<of int> cue init(count as int) base.init(count) a, b = 0, 1 for i in count .add(b) a, b = b, a + b class Program def main is shared i = 1 for n in Fib(10) print '[i]. [n]' i += 1

The above program makes Fib a subclass of List<of int> by stating inherits List<of int>. Then an initializer is declared for the class with cue init. Although it looks like an ordinary method, init has some special rules:

Note the init has no is shared modifier because it is intended for the object level, not the class level. In fact, most methods (properties, inits, etc.) are not shared.

The base.init(count) call is taking advantage of the fact that the List<of> base class provides an init(capacity as count) to set the initial capacity of the list. (The list can still grow in size past that capacity on any call to add.)

The .add(b) is an invocation on the current object. It is like obj.add(b), but with the obj assumed to be this. The leading period is a cue to anyone reading the code, and when writing the code, it is a cue to the IDE to provide autocompletion choices limited to the current object.

Where to next?

Now that you know some basic syntax and capabilities, things get much more interesting. Read about Coding for Quality.