# Decorators

Decorators are used to wrap or modify the behaviour of functions without permanently changing their source code. Decorators are implemented as functions that take another function as input and return a new function with the desired modifications.

Here's an example of a simple Timer decorator that prints the time it took a function to execute before returning the function's result:

```rust
const Timer = (func) => {
    return (...args) => {
        const start = clock()
        var value = func(...args)
        const duration = clock() - start
        println(f"Duration (${func.info().name}): ", duration * 1000)
        return value
    }
}

@Timer
const somefunc = () => {
    return 5 * 20
}

println(somefunc())

/* Output:

Duration (somefunc): 0.004
100

*/
```

There's a small gotcha with decorators that you should be aware of.

If we print the name of the somefunc function after applying a decorator to it, you'll get an empty string. Why?

If you look carefully, the decorator simply returns a lambda. Lambdas inherently do not have names. So how do we fix this?

We'll use a module in our standard library called `functools` to rename our lambda before returning it:

{% code overflow="wrap" %}

```rust
import [rename] : functools

const Timer = (func) => {
    return ((...args) => {
        const start = clock()
        var value = func(...args)
        const duration = clock() - start
        println(f"Duration (${func.info().name}): ", duration * 1000)
        return value
    }).rename(func.info().name)
}
```

{% endcode %}

Now instead of returning a nameless lambda, we rename it to the original function's name using the `rename` function provided by `functools`.

If we print the function's name now, you'll get the correct string back.

Decorators can accept functions with arguments as well. Since we're returning a function that takes a variable number of parameters, it will simply pass those on to the original function call within the decorator.

{% code overflow="wrap" %}

```rust
@Timer
const somefunc = (a, b) => {
    return a * b
}

println(somefunc(5, 20))

/* Output:

Duration (somefunc): 0.002
256

*/
```

{% endcode %}

**Note:** Much like how the returned function loses its name without interverntion from `functools`, its arity will also be lost. This is because the variadic parameter (`...args`) is only one parameter, thus the new arity becomes 1. This is not something that can be modified.

You can attach multiple decorators to the same function like so:

```rust
@[Timer, Timer]
const somefunc = (a, b) => {
    return a * b
}

somefunc(8, 32).println()

/* Output:

Duration (somefunc): 0.004
Duration (somefunc): 0.002
256

*/
```

Decorators can also accept multiple arguments. When constructing a decorator, the first parameter is reserved for the function you'll be wrapping. You're free to keep adding parameters after that.

```rust
const Timer = (func, diff = 1) => {
    return ((...args) => {
        const start = clock()
        var value = func(...args)
        const duration = clock() - start
        println(f"Duration (${func.info().name}): ", duration * 1000 * diff)
        return value
    }).rename(func.info().name)
}

@[Timer(1000), Timer]
const somefunc = (a, b) => {
    return a * b
}

somefunc(8, 32).println()

/* Output:

Duration (somefunc): 2
Duration (somefunc): 0.057
256

*/
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://dibs.gitbook.io/vortex-docs/language-reference/decorators.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
