Replacing Trailing Invocation Operators with a `do` Prefix

Many languages (often implicitly) support appending invocation operators to function expressions to create IIFEs (Immediately Invoked Function Expressions). Swift uses them when setting the default value of a property with a closure. For example:

class SomeClass {
    let someProperty: SomeType = {
        return someValue
    }() // <- these guys
}

Having the parens after the closure (when they're not usually present there) makes them easy to overlook, lowering readability. They're also noisy and ugly.

In CoffeeScript (where everything's an expression), this was solved with a unary prefix do operator that simply invokes its only operand (with no arguments), allowing IIFEs to be prefixed with do instead of suffixed with (). For example:

colorizeElements = do ->
  elements = findAllTheElements(selector)
  return (color) -> elements.css({color})

Swift has a do keyword, and I can't see any conflict with reusing it for property closures (though I'm new to Swift, so may have missed something). Assuming it's possible, please consider supporting the following grammar (as an alternative to the original example above):

class SomeClass {
    let someProperty: SomeType = do {
        return someValue
    }
}

The trailing parens would still be valid (at least for the foreseeable), but could not be combined with do (for a given property closure).

5 Likes

Ah, thank you. I love this idea. In the same vein, I'd love to see "computed" as a qualifier for computed variables, so we'd have:

let foo = 0
var foo = 0
computed foo { return oldValue + 1 }
let foo = do {return 0 }
1 Like

Can we please refer to the existing syntax using a term that doesn’t evoke genitalia?

5 Likes

You can simulate it:

func name_of_your_choice<T>(_ p: () -> T) -> T {
    p()
}

let someProperty = name_of_your_choice {
    someValue
}
12 Likes

I didn't know you could do that. That's very cool. Thanks.

Yeah, admittedly muttnuts is not the classiest nomenclature (though I've heard them called worse), and don't know of a nicer word for them.

Update 1: The post has been flagged and will be removed now, so I guess there's little point trying to coin a new term.

Update 2: I edited the post, and completely removed any reference to muttnuts, so the post should (hopefully) be reinstated now.

You used “IIFE” in the original post, which is probably a suitable alternative.

IIFE already describes the general case (with or without do).

Perhaps, "removing unsightly call operators" would be an improvement?

2 Likes

You don’t need a name for the precise syntactic form you’re proposing to obsolete. You just need enough specificity that people understand what you’re proposing to change.

The prods can restore the post with a less rude name/title.

I edited the post (and title), and removed the offending word completely. Hopefully, everything can stay up now. There are ideas and tips in the responses that are worth keeping.

Thinking about @tera's suggestion, it seems possible to provide a more general solution than a do prefix would offer, without changing Swift's syntax.

A builtin, maybe named iife (pronounced iffy), that works like name_of_your_choice in @tera's post, could be overloaded to also support other cases (of trailing parens).

If the builtin handled every case (so you never needed trailing parens), it would solve the problem very neatly.

I don't know Swift well enough to know whether that's possible, but it's obvious that that approach should be fully considered before adding new syntax. On that basis, there's not much I can personally add to the conversation.

I would like to thank you all for considering this. Best wishes.

How do you pass arguments to the do block?

Generally speaking, IIFEs don't take arguments. They're really just a way of creating a block (with its own scope) that's executed immediately and evaluates to something.

In a language with function expressions, you can define a function that takes no args and returns something useful, then immediately invoke it as part of the same expression (allowing the function to be garbage collected as soon as it returns).

One longstanding issue with using an immediately invoked function expression is the grammar, which looks identical to a regular function expression, except for the trailing parens.

The decorator that @tera posted is a good solution, and Swift's syntax makes it especially elegant to apply (in other languages, you often need to wrap the function expression in parens to apply the decorator). I just don't know Swift well enough yet to be certain that that decorator could handle every case (though it seems like it would). Assuming it does, it would be nice to have it available out the box, but either way, there'd be no reason to add new syntax.