Skip to content

Trailing body macros using function bodies #1906

@erenjanje

Description

Would it make sense to enable the @body macros to use the function bodies? Let there be such a code:

fn int foo(int x) {
    @pool() {
        return string::tformat("%d", x).len;
    };
}

Many functions only need an array or string only for their lifetime, so I suppose this kind of functions are not that rare to write in C3. However, this creates a new scope just for the @pool macro. This is reasonable, but collapsing these two scopes may be nice, like this:

fn int foo(int x) @pool() {
    return string::tformat("%d", x).len;
}

This also enables short function declarations to be used with such patterns:

fn int foo(int x) @pool() => string::tformat("%d", x).len;

which is possible without this, but then we would need another feature such as trailing blocks in macros returning values, since all bodies currently return void. I saw that there is a discussion about this feature in issue #1889. Macros in macros can solve this problem, but I think they do not look as clean as trailing bodies directly being able to return values:

fn int foo(int x) => @pool(macro() => string::tformat("%d", x).len);

where the hypothetical @pool takes a macro argument instead of a trailing body unlike the current one.

With the function attribute-ish macro syntax, it is also cleaner to chain multiple such macros. For example, say we have a @synchronized macro, which takes a mutex as # parameter and a body to run while locked.

struct MyMonitor {
    Mutex mutex;
    int number;
}

macro @synchronized(#lock; @body()) {
    var lock = &#lock;
    lock.lock()!!;
    defer lock.unlock()!!;
    @body();
}

fn int MyMonitor.increase(&self) @synchronized(self.mutex) => self.number += 1;

Say we also want to create a memory pool for this function. Then this would be possible:

fn int MyMonitor.digit_count(&self) @pool() @synchronized(self.mutex) => string::tformat("%d", self.number).len;

I guess that this can be translated to the following code trivially by the compiler if it sees a macro usage between the function parameters and function body:

fn int MyMonitor.digit_count(&self) {
    @pool() {
        @synchronized(self.mutex) {
            return string::tformat("%d", self.number).len;
        }
    };
}

Metadata

Assignees

No one assigned

    Labels

    Discussion neededThis feature needs discussion to iron out details

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions