ceylon icon indicating copy to clipboard operation
ceylon copied to clipboard

Add let conditions

Open lucaswerkmeister opened this issue 7 years ago • 6 comments

Occasionally, it can be useful to introduce a new variable in a condition list.

if (is BaseMemberExpression bme = that.primary,
    let text = identifierText(bme.identifier),
    (importMemberAliases[text] else text) in inlineAnnotations) {
    // ...
}

It would be nice if that was legal syntax, instead of having to use workarounds like this:

if (is BaseMemberExpression bme = that.primary,
    exists text = identifierText(bme.identifier) of String?,
    (importMemberAliases[text] else text) in inlineAnnotations) {
    // ...
}

However, there is one problem: let conditions as shown above are very different from let statements, expressions, and (once implemented: see #3483) comprehension clauses – they only introduce one variable, and they aren’t parenthesized. To introduce multiple variables, you would use multiple let conditions instead of one let with multiple patterns. I’m not sure how much that bothers me.

lucaswerkmeister avatar Sep 18 '18 20:09 lucaswerkmeister

It seems to me that the natural syntax for this would be:

if (is BaseMemberExpression bme = that.primary,
    text = identifierText(bme.identifier),
    (importMemberAliases[text] else text) in inlineAnnotations) {
    // ...
}

The let keyword would be neither regular, nor necessary here.

gavinking avatar Sep 21 '18 06:09 gavinking

Looks okay, but might be confusing/ambiguous if the expression happens to be boolean…

lucaswerkmeister avatar Sep 21 '18 08:09 lucaswerkmeister

True. The = would be mistaken for an assignment operator.

gavinking avatar Sep 21 '18 08:09 gavinking

OTOH, I'm pretty sure that assignments in ifs are something we already strongly discourage...

gavinking avatar Sep 21 '18 09:09 gavinking

I briefly thought that value might be an alternative keyword to use instead of let, but then I realized that thinking this through most likely means full-featured declarations inside a condition list, either with inferred type (value) or with explicit type. And that starts to feel silly.

lucaswerkmeister avatar Sep 21 '18 09:09 lucaswerkmeister

I guess what you are trying to achieve by

if (is BaseMemberExpression bme = that.primary,
    let text = identifierText(bme.identifier),
    (importMemberAliases[text] else text) in inlineAnnotations) {
    // ...
}

is either

  1. possibility to have a else statement that executes if any of the conditions fail - without having to duplicate the else as in
if (is BaseMemberExpression bme = that.primary) {
    value text = identifierText(bme.identifier);
    if ((importMemberAliases[text] else text) in inlineAnnotations) {
        // ...
    } else {
        // ...
    }
} else {
    // duplicate code
}
  1. minimize indentation

I do have to say that 1. is something that personally annoys me every now and then. I wonder if there could be some construct to avoid duplicating/outsourcing the else blocks even if you have nested if statements with code in between.. Kindof like throwing an exception "blah this didn't work out, fallback behaviour please".. Hmm could it perhaps even be plausible to use the exception construct but not actually throw exception.. i.e. optimize the case when it is caught locally AND exception object never used.. :) Not that I like try blocks very much.. they mess with the otherwise beautiful indentation of code :)

xkr47 avatar Oct 09 '18 17:10 xkr47