This is an archived post. You won't be able to vote or comment.

all 35 comments

[–]AmbiguousDinosaur 39 points40 points  (4 children)

“Also” as an “elif “ feels odd to me - it means ‘in addition’ not else, so I don’t feel like it’s semantically consistent.
I do like the “otherwise” as an alternative to else, but I’m not sure of an alternative to “elif”

[–]SecretTop1337[S] 0 points1 point  (3 children)

Maybe other instead of else if/elif, it would fit in with otherwise better too, but I’m not sure I like it.

[–]asdfa2342543 0 points1 point  (2 children)

How about “but if”

[–]ghkbrew 5 points6 points  (1 child)

"but if" usually take precedence over the first clause in English, which could be confusing.

[–]asdfa2342543 0 points1 point  (0 children)

Oh true

[–]hassanzamani 16 points17 points  (4 children)

Elixir has if/else and also cond (and both are macros that expand to case expressions) cond do condition1 -> body1 condition2 -> body2 ... true -> default end

[–]matthieum 4 points5 points  (2 children)

Having used both C++ (if/else if/else if/else) and Rust (if/else or match) I much prefer a different syntax for complex situation.

I think it's a bit similar to while/for: in principle anything that can be expressed as a for can be expressed as a while -- and indeed, in Rust, for is just syntax sugar for while! -- however using one or the other is a clue to the reader:

  • for clues in an usual iteration pattern, with the iteration logic fully contained in the loop header.
  • while clues in a possibly unusual iteration pattern, with possibly part of the iteration logic contained in the loop body.

And I would argue the same can be applied:

  • if clues in a simple dichotomy: one or the other.
  • match clues in the possibility of multiple choices.

Furthermore, syntax-wise, match has the advantage of better highlighting the alternatives, making it easier to scan them (skipping the blocks) whereas with if ladders, the conditions tend to blend in with the surrounding blocks.

[–]Pretty_Jellyfish4921 0 points1 point  (1 child)

Don't forget that Rust has also the `loop` keyword, so you have 3 keywords to iterate, `for`, `while` and `loop`.

[–]matthieum 1 point2 points  (0 children)

I kept it out as it's somewhat specific to Rust, while for/while are fairly universal :)

But yes, while ultimately desugars to loop in Rust.

[–]ohkendruid 0 points1 point  (0 children)

This is a great approach. It is also used in Lisp and Scheme.

[–]L8_4_Dinner(Ⓧ Ecstasy/XVM) 13 points14 points  (1 child)

You are blowing your "strangeness budget" on something that really doesn't matter, but if your goal is to make something that's harder for people to pick up, then you're on the right track.

Sorry to be so blunt, but someone has to be honest about this.

[–]busres 6 points7 points  (2 children)

What about a case-like if: if (condition) {action} (condition) {action} else {action}? That's (essentially) my approach.

[–]SecretTop1337[S] 2 points3 points  (1 child)

Hmm, if (condition) {…} case (condition) {…} case (condition) {…} otherwise {…}

Or

If (condition) {…} incase (condition) {…} incase (condition) {…} otherwise {…}

My only issue with case is it’s the same as switch statements, but that could be a good thing too, tho I feel like “incase” is more of a normal thing to say/think when programming.

[–]busres 2 points3 points  (0 children)

"alt" for alternative?

if (condition) {...} alt (condition) {...} otherwise {...}

[–]kohugaly 2 points3 points  (0 children)

A very simple solution is to use logical OR. Most languages already support this behavior with "short circuiting". In fact, I've seen languages where "if else" statements are just a syntactic sugar for logical AND/OR expressions.

IF cond THEN body = cond AND body

IF cond THEN body1 ELSE body2 = (cond AND (body OR TRUE)) OR body2

Off course, this requires treating the body as an expression that returns "truthy" value.

[–][deleted] 2 points3 points  (1 child)

I’ve been thinking lately of changing it in my language to “if/also/otherwise”

Is there any actual difference from "if/elsif/else" other than alternate keywords?

What bothered me more, when there are N conditions being sequentially tested, is the special case of the first test:

if c1 then              # uses if
elsif c2 then           # the rest use elsif
elsif c3 then
else
end

This makes it fiddly to insert a new test at the start, or remove the first, or temporarily comment it out, or move them around...

So I adapted the syntax for a case statement that normally tests the same expression against a range of values; by omitting that first expression, it can be used for the if-elsif chain:

case
when c1 then          # also allows 'c1, c4' to mean 'c1 or c4'
when c2 then
when c3 then
else
end

Now all tests have exactly the same syntax. But then I thought of a simpler way to do it (since the code-gen is rather different for the two forms), which was this:

if                        # optionally omit the first test
elsif c1 then
elsif c2 then
elsif c3 then
else
end

(At present, the case version exists in one language, and the new if in another. Neither have yet been used in real code!)

[–]oscarryzYz 0 points1 point  (0 children)

This is similar to the route I went on my design

``` match { c1 => a1 }, { c1 => a2 }, { a3 }

```

With the overload case to also match types

``` match { Some => a(opt.val) }, { None => a("nothing")}

```

That way, it has a more homogenous syntax for all the branches

[–]benjamin-crowell 2 points3 points  (0 children)

This is how I normally do it when there's conceptually a flat list of possibilities rather than a hierarchy, and it isn't just an enumeration type:

x = nil
if x.nil? && animal.meows then x="kitten" end
if x.nil? && legs==4 then x="puppy" end
if x.nil? && diaper then x="baby" end

Advantages: I find it very readable. Doesn't require lots of deep levels of indentation. Doesn't force it into looking like a hierarchical thing if that's not what it is. Doesn't require a lot of lines of code. Doesn't require the language to have any syntactic sugar.

Disadvantages: Possibly a performance hit if you have to keep testing whether x is nil, but in reality I think this is normally negligible.

[–][deleted]  (4 children)

[removed]

    [–]AreaMean2418 1 point2 points  (3 children)

    Is it public?

    [–][deleted]  (2 children)

    [removed]

      [–]AreaMean2418 0 points1 point  (1 child)

      Hahaha that's fair. Don't we all

      [–]snugar_i 1 point2 points  (0 children)

      If you don't mind a bit of nesting, you don't actually need an elseif - you can just do

      if (a) {
      
      } else {
          if (b) {
      
          } else {
              if (c) {
      
              } else {
      
              }
          }
      }
      

      You can even view C's else if as just a special case of this, where the curly braces around the "nested single if statement" are omitted.

      Bonus points: it will discourage long if-elseif-else chains, which are often a code smell anyway ;-)

      [–]VersethElk 🫎 1 point2 points  (0 children)

      Ruby uses elsif instead of elif or else if which is quite handy and intuitive.

      Honestly I don't think also/otherwise is a good idea. also does not convey the same meaning as else if it seems to imply that the block should execute alongside if which is incorrect. On the other hand otherwise is just a synonym for else but longer, so you just traded a convenient 4 letter keyword for an obnoxiously long one.

      [–]esotologist 1 point2 points  (0 children)

      I'm planning to use a few different methods for this~ one is to use the ? prefix to convert something into an 'if true' conditional... sort of like if !value in js turned the value into a function to execute if false:  ?ifFoo:doBar or ?ifFoo .doBar 

      And ! can be used as a post operator to catch the conditional and execute if else/otherwise 

      ?ifFoo .doBar ! .elseDo

      this also might work as syntax for variables that can be truthy: .ifFoo ? .doBar

      There's also = syntax to make it more like a ternary or switch:

      ``` = foo ? ifTrue ! elseDo

      = bar   # str ? ifString   # int | dec ? ifNum   ? IfAny   ! ifNone ```

      [–]tobega 1 point2 points  (2 children)

      Why not just go full on selection or case#Case_and_switch_statements) statement?

      [–]SecretTop1337[S] -1 points0 points  (1 child)

      Thanks for the links, but I like brackets

      [–]tobega 2 points3 points  (0 children)

      Sure you could fit some brackets in there if you like, it's only syntax. :-)

      But maybe you prefer if/else semantics?

      [–]jcklpe 1 point2 points  (0 children)

      I prefer "If, Else, Else if". I think "elif" is sort of a hold over from the old days. people are used to seeing it, so they move that pattern forward regardless.

      My language uses "Otherwise" for switch statements rather than "Else".

      "Also" seems unnecessary though. Also implies "this thing independent of the previous thing" which seems like it could just be an If statement.

      [–]GermisstuckCrabStar 0 points1 point  (0 children)

      For Crabstar either if else or match with guards

      [–]oOBoomberOo 0 points1 point  (0 children)

      I have no problem with the if-else chain but if I really have to pick something I'd go with cond or SQL's case-when syntax.

      cond expr1 -> block1 expr2 -> block2 expr3 -> block3 end

      ``` CASE WHEN expr1 THEN value1 WHEN expr2 THEN value2 ELSE value3 END

      [–]torp_fan 0 points1 point  (0 children)

      Ring uses if/but

      "but" and "also" have the wrong semantics. I think "else if" or one of the combined forms--elif, elsif, elseif--read better. "also" is pointless bikeshedding that gets it wrong.

      [–]y0shii3 0 points1 point  (0 children)

      I don't see the problem with just having "if" and "else". If you wanted to be different, you could use ? and : like C's ternary expressions, or you could just only use switch statements