Decorator

Home of the ABS programming language: the joy of shell scripting.


Decorator

Decorators are a feature built on top of ABS’ functions – they’re not a type per se but they do have their own syntactic sugar.

A decorator is a function that “wraps” another function, allowing you to enhance the original function’s functionality with the decorator’s one.

An example could be a decorator that logs how long a function takes to execute, or delays execution altogether.

Simple decorators

A decorator is a plain-old function that accepts the original function and returns a new function that wraps the original one with its own behaviour. After defining it, you can “decorate” other functions through the convenient @ syntax:

f uppercase(fn) {
    return f() {
        return fn(...).upper()
    }
}

@uppercase
f stringer(x) {
    return x.str()
}

stringer({}) # "{}"
stringer(12) # "12"
stringer("hello") # "HELLO"

As you see, stringer’s behaviour has been altered: it will now output uppercase strings.

Decorators with arguments

As we’ve just seen, a decorator simply needs to be a function that accepts the original function and returns a new one, “enhancing” the original behavior. If you wish to configure decorators with arguments, it is as simple as adding another level of “wrapping”:

f log_if_slow(treshold_ms) {
    return f(original_fn) {
        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 taken the stage:

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

Decorators are heavily inspired by Python – if you wish to understand how they work more in depth we’d recommend reading this primer on Python decorators.

Next

That’s about it for this section!

You can now head over to read a little bit about ABS’ standard library.