Skip to content

Code blocks

The main logic compartmentalization mechanism in Blombly are code blocks. These are source code segments that can be treated as functions or inlined within running code. Code blocks are enclosed in brackets and assigned to a variable. This only sets the variable and does not execute code yet.

Inlining

"Paste" a block's code to the current position by following the variable holding it with double dots (:), as demonstrated below. This is called inlining and grants full access to the scopes variables for usage and modification. This way, the inlined block enriches current code with a snippet that is defined elsewhere, and which may also change dynamically.

// main.bb
test = {
    print("Hello world"); 
} 
test:
> ./blombly main.bb
Hello world!

Info

Use the @value = do @blockname: syntax to intercept return statements, if those are expected from inlined blocks. This is described later.

Functions

Blombly can treat code blocks as functions by executing some code inside a parenthesis. This starts a new scope from the values to run the block's code. The last semicolon may be omitted from blocks, so this mostly looks like keyword arguments separated by semicolons (;). We later show a modification that accepts positional arguments too. Use a return statement to yield back a value. This stops block execution immediately. An example of running a code block follows.


Being able to execute code as part of the arguments allows more dynamic patterns than regular keyword arguments, namely the reuse of arbitrary preparations before calling methods. For example, declare configuration blocks that generate the arguments and inline them within the calling parenthesis.

// main.bb
adder = {
    return x + y;
}
result = adder(x=1;y=2); 
print(result);
> ./blombly main.bb
3

Immediate return

Blombly comes alongside several macros, one of which is @signature => @expression. This is a shorthand for code blocks that only return an expression's outcome. Below is an example that combines several concepts.

// main.bb
final adder => x + y + bias;
final suber => x - y + bias;
final increase = {if(increment) bias=1 else bias=0}
final nobias = {bias=0}

increment = true;
a = adder(increase:x=1;y=2);
b = suber(nobias:x=1;y=2);
print(a);
print(b);
> ./blombly main.bb
4
-1

Execution closure

Once arguments are transferred and the code block starts running, the latter can view only final variables of the scope from which it is called. This means that moving blocks between scopes makes them adapt to the finals of the new scope. This lets the language internally schedule certain block calls to run in parallel threads for speedup. Below is an example.

// main.bb
scope = {
    final value = "Declaration scope";
    value_printer = {print(value)}
    value_printer();
    return value_printer;
}

final value = "Running scope";
value_printer = scope();
value_printer();
> ./blombly main.bb
Declaration scope
Running scope

Info

The property of obtaining values from a surrounding context is broadly called closure. Contrary to most interpreted languages, like Python and JavaScript, Blombly aims for efficient memory management and parallelization. This is achieved by restricting access only to the final variables from the scope at which functions run (not where they are defined) as closure.

Positional arguments

Blocks can be called using comma-separated positional arguments. This is a common programming pattern, though we stress that it is better to execute code to determine configurations. Positional arguments are stored in a list called args. For safety, this is considered a language keyword and the compiler does not allow assigning to it. You can then access list elements or use args|next to sequentially pop arguments.


A shorthand of the last practice is to add positional comma-separated variable names inside a parenthesis next to the block. This front-pops the values. You can still assign the block to other variables or inline it within other blocks given that they have enough remainder elements in args.

// main.bb
// could also write `adder(x,y)=>x+y;`
adder(x, y) = {return x+y} 
test = adder;
result = test(1, 2);
print(result);
> ./blombly main.bb
3

Blombly mixes positional arguments and code execution by separating the two with double colons (::) inside the call parenthesis. These also require whitespaces before and after. Positional arguments are created first from the calling scope, so further argument generation can modify them.

// main.bb
adder(x, y) = {
    default wx = 1; 
    default wy = 1; 
    return x*wx + y*wy;
}
result = adder(1,2 :: wx=1;wy=2); 
print(result);
> ./blombly main.bb
5