Skip to content

v1.11.0

Compare
Choose a tag to compare
@odino odino released this 16 Feb 16:16
· 172 commits to master since this release

A new minor release of ABS: always be shipping! 🚢

Named functions

Functions can now be "named":

f my_func(x) {
  return x**2
}

Earlier, you would have had to assign
the function to a variable:

my_func = f(x) {
  return x**2
}

while right now function names are first-class
citizens. For example, the string representation
of a function will actualy include its name (to be
included in stacktraces as well):

⧐  f test() {echo(1)}
f test() {echo(1)}

Decorators

A decorator is a plain-old function that
accepts 1 + N arguments, where 1 is the
function being wrapped, and returns a new
function that wraps the original one:

f log_if_slow(original_fn, treshold_ms) {
    return f() {
        start = `date +%s%3N`.int()
        res = original_fn(...)
        end = `date +%s%3N`.int()

        if end - start > treshold_ms {
            echo("mmm, we were pretty slow...")
        }

        return res
    }
}

That's as simple as that: a named function
that returns a new function that executes the
decorated one (original_fn) and returns its
result, while logging if it takes longer than
a few milliseconds.

Now that we've declared our decorator, it's time
to use it, through the @ notation:

@log_if_slow(500)
f return_random_number_after_sleeping(seconds) {
    `sleep $seconds`
    return rand(1000)
}

and we can test our decorator has takn the stage:

⧐  return_random_number_after_sleeping(0)
493
⧐  return_random_number_after_sleeping(1)
mmm, we were pretty slow...
371

Accessing a function's arguments

Functions can receive a dynamic number of arguments,
and arguments can be "packed" through the special
... variable:

f sum_numbers() {
    s = 0
    for x in ... {
        s += x
    }

    return s
}

sum_numbers(1) # 1
sum_numbers(1, 2, 3) # 6

... is a special variables that acts
like an array, so you can loop and slice
it however you want:

f first_arg() {
    if ....len() > 0 {
        return ...[0]
    }

    return "No first arg"
}

first_arg() # "No first arg"
first_arg(1) # 1

When you pass ... directly to a function,
it will be unpacked:

f echo_wrapper() {
    echo(...)
}

echo_wrapper("hello %s", "root") # "hello root"

and you can add additional arguments as well:

f echo_wrapper() {
    echo(..., "root")
}

echo_wrapper("hello %s %s", "sir") # "hello sir root"

Call a function with an array of arguments

call calls a function "spreading" the array of arguments into the function's arguments:

multiplier = f(x, y) { x * y }
multiplier.call([10, 2]) # 20