12

Is there a good way to write code like this in Erlang?

A == B ? X : Y

below is ruby-style code. This is also known as a ternary operator.

2240
  • 1,547
  • 2
  • 12
  • 30
why
  • 23,923
  • 29
  • 97
  • 142
  • 11
    You do realize that what you wrote is the same as `a == b`, right? Is that really what you're asking for, or is it something else? – Gabe May 23 '11 at 04:53
  • 1
    @Gabe in C or a language which has a C-like syntax, sure. That's not valid erlang though :-) –  May 23 '11 at 04:56
  • 2
    All `if` statements in erlang are already an expression ... I'm not sure what the question is asking. Are you looking for something like `if cond -> true_expr; true -> false_expr; end`? There is also `case`, which may be more desirable, depending. –  May 23 '11 at 04:57
  • 6
    `a` and `b` are inequal atoms in erlang. You could just write this as `false` – Dustin May 23 '11 at 05:36
  • See also [this question](http://stackoverflow.com/questions/963918/how-to-achieve-if-else-in-erlang). – legoscia Sep 12 '12 at 16:23

6 Answers6

38

Explanation

The reason the ternary operator _ ? _ : _ exists in many languages is due to the fact that they have two syntactic classes: Statements and Expressions. Since if-then-else constructions usually belong the the statement-class, there is no way to get that working for when you are entering an expression. Hence you add the _ ? _ : _ operator to the expression class.

As another post states, you can take a == b ? true : false and just write a == b, but that does not explain the general case where we may have a == b ? X : Y for arbitrary expressions X and Y. Also note that a == b is always false in Erlang, so you could argue that the real thing to do is to replace the whole expression with false.

Luckily, Erlang, as is the case for most functional languages, have one syntactic class only, expressions. Hence you can use case a == b of X -> ...; Y -> ... end in any place in a function, other expressions included. In other words, the ternary _ ? _ : _ operator is redundant in Erlang since the case already works.

An example:

Suppose we are to return a simple proplist and we have some computation we need to do

  f() ->
    case a == b of
          true -> 
           [{a, 3},
            {b, <<"YE">>},
            {c, 7}];
          false ->
           [{a, 3},
            {b, <<"YE">>},
            {c, "HELLO!!!"}];
    end.

But since the case construction is an expression, we can just inline it:

  f() ->
    [{a, 3},
     {b, <<"YE">>},
     {c, case a == b of
          true -> 7;
          false -> "HELLO!!!"
         end}].

and be done with the thing.

Why I am not advocating the use of IF

the if .. end construction in Erlang is usually not what you want. You want to scrutinize a value a == b in this case and it can yield one of two outputs true or false. In that case the case-expression is more direct. The if is better used if you have to check for multiple different tests and pick the first matching, whereas we only have a single test to make here.

Fylke
  • 1,753
  • 3
  • 19
  • 30
I GIVE CRAP ANSWERS
  • 18,739
  • 3
  • 42
  • 47
  • 1
    Just want to mention that in case of Ruby particularly using tertiary operator is mostly the matter of convenience. Compare `a = if false then "T" else "F" end` and `a = false ? "T" : "F"`. Both forms work. – Victor Moroz May 23 '11 at 14:09
  • 1
    "The reason the ternary operator _ ? _ : _ exists in many languages is due to the fact that they have two syntactic classes" While that's true, the real reason I use it in languages that support it is because it is less verbose than other methods. It's true that there's a difference between statements and expressions, and I understand the difference between the two, but my reasons for choosing to use `_?_:_` is always based on code clarity. – Davy8 Jul 28 '15 at 19:24
8

We use macro like this:

-define(IF(Cond,E1,E2), (case (Cond) of true -> (E1); false -> (E2) end)).

Then in your code you write:

io:format("~s~n", [?IF(a==b, "equal", "not equal")]).
nivertech
  • 391
  • 1
  • 4
  • 7
5

If you're asking how to write something like A == B ? X : Y as an if expression, it's

if
    A == B ->
        X;
    true ->    % "true" means "else" here
        Y
end

You can also write it as a case expression:

case A == B of
    true ->
        X;
    _Else ->
        Y
end

or

case A == B of
    true ->
        X;
    false ->
        Y
end
Gabe
  • 84,912
  • 12
  • 139
  • 238
4

Since a == b ? true : false maps to a == b, you can use a == b in Erlang also.

Richard Schneider
  • 34,944
  • 9
  • 57
  • 73
  • 5
    For sake of clarity: to be valid erlang you'd need to make 'a' & 'b' upper case, i.e. variables. Otherwise it'll compare the atoms 'a' and b'. That match will always fail so the expression will always return false. – sfinnie May 23 '11 at 07:49
  • 1
    Thanks @sfinnie. I do not really know erlang, so did not catch the case issue. – Richard Schneider May 23 '11 at 08:45
1

You can use 'if' like that

foo(A,B) ->
    [1,
     2,
     (if A == B -> 3; true -> 4 end), % A == B ? 3 : 4
     5,
     6].

special ?: form seems to be not necessary. You can of course use true/false as return value but I think you meant more general form, as that one would be useless (A == B does the same job).

Łukasz Milewski
  • 1,897
  • 13
  • 14
0

@Gabe's answer is the most concise, and (as far as I can tell) idiomatic. The C expression ((A==B) ? X : Y) maps directly to the Erlang expression

case A == B of
    true -> X;
    false -> Y
end

However, this is vastly more code than the C version. You should probably wrap it up into a convenience function — and someone should tell me if this already exists in the Erlang standard libraries!

iff(true, X, Y) -> X;
iff(false, X, Y) -> Y.

Then your C expression becomes simply iff(A == B, X, Y). However, beware! that just like C, Erlang eagerly evaluates function arguments. If X or Y have side effects or are expensive to evaluate, then iff will not be equivalent to an in-line case expression.

Community
  • 1
  • 1
Quuxplusone
  • 23,928
  • 8
  • 94
  • 159