C-style language to Lobster Cheat Sheet

Since every programmer usually knows at least one C-style language (C/C++/C#/Java/JavaScript/PHP etc.), a quick way to get to know Lobster is seeing how it differs from what you're familiar with. Where C-style languages differ I will by default pick C# (as being the most  "average" of the range), though sometimes may show multiple language alternatives (as noted in the comments). This document mostly focusses on things that are different, i.e. you will not see how a + b in Lobster is the same as a + b in C#.

Basics


Lobster version C-style version Comments
a = 1a = 1;Assign existing variable.
var a = 1int a = 1;Create new variable, type thru type inference.
let a = 1const int a = 1;Create constant variable.
let a, b = 1, 2 int a = 1; int b = 2; Define multiple at once.
let a, b = f() int a = f(&b); Define multiple from a function returning multiple values.
let v = [ 1, 2, 3 ] int[] v = new int[] { 1, 2, 3 }; The type of vectors is inferred. They are also resizable, so they are probably more akin a C# List than an array.
let w = v + v vec3 w = new Vec3;
w.x = v.x + v.x;
w.y = v.y + v.y;
w.z = v.z + v.z;
Vector operation exist for most operators and functions.
nil null Nil is more strict in lobster, in that a reference type which can be nil is different from those that are never nil, and you explicitly convert between them.
a or b and c (a || b) && c These are really the only operators that are different.
let a = f() or g() var a = f();
if (a == null) a = g();
The or operator works slightly differently in that rather than returning true, it returns whatever value was true (and true is everything that is not nil, false, 0 or 0.0)


Control Structures

Lobster version C-style version Comments
if a: b else: c if (a) b; else c
if a:
    b
    c
else:
    d
    e
if (a) {
    b;
    c;
} else {
    d;
    e;
}
for(m) i: print i for (int i = 0; i < m; i++) print(i);
for m: print _ for (int i = 0; i < m; i++) print(i);
for(m) i:
    print i
for (int i = 0; i < m; i++) {
    print(i);
}
while a: b while (a) b;
for(list) a: print a foreach (var a in list) print(a);
a := switch i:
    case 1: "no"
    case 2, 4..6: "yes"
    default: "maybe"
switch (i) {
    case 1:
        a = "no";
        break;
    case 2:
    case 4:
    case 5:
    case 6:
        a = "yes";
        break;
    default:
        a = "maybe";
}
r := map(list) x: x * x var r = new List();
foreach(var x in list) r.Add(x * x);

r := map(list) x: x * x var r = list.ConvertAll(x => x * x); C# and pretty much all programming languages except for Java (< 8) can nowadays use some form of lambdas that are similar but not quite as powerful as the ones in Lobster (for example, you can't use "return" to break out of a loop).
r := filter list: _ > 0 var r = new List();
foreach (var x in list) if (x > 0) r.Add(x);
r := exists list: _ > 0 var r = false;
foreach (var x in list) if (x > 0) { r = true; break; }


Function Definitions and Scope

Lobster version C-style version Comments
def name(a:int, b:int) -> int:
    return a + b
int name(int a, int b) { return a + b; }In Lobster it is unusual to specify types, especially the return type.
def name(a, b):
    return a + b
T name<T>(T a, T b) { return a + b; } By default function are declared without types, and automatically inferred on use.
def name(a, b):
    return a + b
T name<T>(T a, T b) {
    return a + b;
}
For multiple lines, use indentation.
def magnitude(v::xy):
    return sqrt(x * x + y * y)
// inside class xy
float magnitude() { return sqrt(x * x + y * y); }
The :: way to indicate a type (v is of type xy) allows you to access object elements directly rather than having to write v.x etc. This is similar to writing a method, though Lobster makes no such distinction.
// inside class/struct xy
def magnitude():
    return sqrt(x * x + y * y)
// inside class xy
float magnitude() { return sqrt(x * x + y * y); }
This is an equivalent way of writing the above when inside the scope of a class/struct (see below).
v.magnitude() v.magnitude() On a function call, you can move the first argument to before the call, for any function, not just "methods".
def name(x:X): return 0
def name(y:Y): return 1
/* inside class X */ int name() { return 0; }
/* inside class Y */ int name() { return 1; }
You write multiple function implementations for multiple types, which can then be called and resolved either statically (overloading) or dynamically (dynamic dispatch) depending on the situation. These functions can work on user defined types or builtin ones. They can be written by whoever wrote the type (even in-line in the class definition), or completely separately.
let f = def(a, b): a + b var f = (int a, int b) => a + b Function value in C#
let f = def(a, b): a + b auto f = [](int a, int a) { return a + b; } Function value in C++
def fold(xs, init, fun):
    for(xs): init = fun(init, _)
    return init
T fold<T>(List<T> xs, T init, Func<T, T, T> fun) {
    foreach (var x in xs) init = fun(init, x);
    return init;
}
How to write a Higher Order Function: a function that takes a function argument. In this case "fold": take a list, and apply the function to each element and the previous result, effectively "folding" the list into a single value.
r := fold(list, 0) a, b: a + b var r = fold(list, 0, (a, b) => a + b); How to call that function with a function value. This sums all values in a list.
r := fold(list, 0): _a + _b var r = fold(list, 0, (a, b) => a + b); Anonymous arguments in lexical order, see language reference.
r := fold(list, 0) a, b:
    print a
    a + b
var r = fold(list, 0, (a, b) => {
    print(a);
    return a + b;
});
Note how in most languages lambda syntax becomes messy when you want to use them with a larger body, and looking very different from builtin control structures.
r := fold(list, 0) a, b:
    if a < 0: return a
    a + b
/* not possible */ Another way in which lambdas in most languages differ from Lobster: you cannot return/break from the loop, making them often useless as control structures. In Lobster, they function just like real constrol structures would. By default, return returns from the lexically enclosing named function.
def f():
    g()
    return 0
def g():
    if something: return 1 from f
    return 0
int f() {
    try { g(); return 0; }
    catch (int x) { return x; }
}
int g() {
    if (something) throw 1;
    return 0;
}
Return even allows you to specify which function to return from, which in other languages you can do with exception handling. In fact, exception handling in Lobster is not a language feature, it is simply some utility functions (try/catch/...) implemented on top of return/from (implemented in exception.lobster).
def mret(): return 1, 2 int mret(out int o) { o = 2; return 1; }
let a, b = mret() var b; var a = mret(&b);


User Defined Types

Lobster version C-style version Comments
struct xy:
    x:float
    y:float
public struct xy { float x; float y; }
struct xy<T>
    x:T
    y:T
public struct xy<T> { T x; T y; } Generics: unlike functions, these are explicitly specified in Lobster.
struct xyz : xy:
    z:float
public struct xyz : xy { float z; } Inheritance.
let v = xyz { 1, 0, 0 } var v = new xyz(1, 0, 0) You'd actually have to define the constructor in C# to be able to do this.
struct xy:
    x:float
    y:float
    def magnitude():
        return sqrt(x * x + y * y)
public class xy {
    float x;
    float y;
    float magnitude() {
        return x * x + y * y;
    }
}
Intendation based syntax, with inline function definition (automatic this argument).
enum color:
    red = 1
    green
    blue
    yellow = 10
enum color {
    red = 1,
    green,
    blue,
    yellow = 10
}