Why no ternary expression?

134 views
Skip to first unread message

Brandon Gillespie

unread,
Jan 26, 2024, 5:07:05 PMJan 26
to elixir-lang-core

I'm sure there's a reason, so I figured I'd ask why there isn't a ternary expression?

It seems like ternary would help with the functional paradigm of Elixir.

I realize one can use the `if...` as a construct, but it just isn't very readable (imho of course).

Consider:

some_function(
  log_id,
  if(type == :before, do: action.order, else: action.order + 1)
)

vs:

some_function(log_id, type == :before ? action.order : action.order + 1)

Invariably when I come upon a use case for a single-line if, I end up never liking its readability. So instead of the above, I end up with:

new_order = if type == :before, do: action.order, else: action.order + 1
some_function(log_id, new_order)

While this works, it's also not great, because I try to avoid assignments wherever possible (being a functional language and all).

Anyway, just a question more than anything. Thanks!

-Brandon


A few other things to address suggestions I know may come:

1. "It's too cryptic" — I just need to point to the `&(&1)` type shortcut to show precedence for smaller syntax sugar in elixir.

2. Just make a `ternary()` function — but I don't think it really helps any with the visual readability, and in fact is probably LESS so since it's a less known function/name in the general programming world, where ternary ?: is pretty ubiquitous.

3. use pipes in the above last example — not what I want, because that requires re-ordering the function's arguments. That's a bizarre requirement just because we can't handle ternary's.

José Valim

unread,
Jan 26, 2024, 5:28:29 PMJan 26
to elixir-l...@googlegroups.com
One of the goals behind Elixir is to provide a certain amount of syntax that translates to a clear abstract syntax tree. The syntax available to create the language should also be available for others to extend language.

Operators are generally tricky because they are hardcoded in the language. You can’t smash tokens together to create a new operator (nor would that be desired), in contrast to how we can smash letters together to create new functions. So operators by definition are less extensible, which we want to avoid, and Elixir partially addresses that my providing a set of operators without meeting.

Introducing ternary operators is complex because they require new syntax rules as well as two operators not used anywhere, so they end up consuming more tokens combinations, and we would need to add a handful more in the name of extensibility. 

Therefore, the Elixir-y thing to do is to rely on existing constructs and use the same constructs to solve different problems. That’s why defining a function is syntactically the same as a conditional. That’s why cond and case and try follow a similar structure. This means everyone can create similar constructs too. The goal is to do more with less.

1. "It's too cryptic" — I just need to point to the `&(&1)` type shortcut to show precedence for smaller syntax sugar in elixir.

Note the existence of “cryptic syntax” is not an argument for adding more cryptic syntax. I am not saying that any of these are cryptic, just that the counter-argument does not hold :)
--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/112d8d35-c65e-4d8d-a221-5707c211f26b%40cold.org.

José Valim

unread,
Jan 26, 2024, 5:39:21 PMJan 26
to elixir-l...@googlegroups.com
While this works, it's also not great, because I try to avoid assignments wherever possible (being a functional language and all).

Assignments do not make your code any less functional. The let form, used for assignments in many programming languages, comes from an extended version of the typed lambda calculus. Avoiding assignments feels like a highly arbitrary restriction to impose on your code. :)

Robert Viragh

unread,
Jan 26, 2024, 11:53:48 PMJan 26
to elixir-l...@googlegroups.com
About me:
I've been learning Elixir intensively for a few months and hope to get a job as an Elixir/Phoenix developer soon.
I don't have too much experience developing languages myself, I just made a YAML templating language so take what I have to say with a grain of salt! 

This is my personal experience with Elixir, if there are any mistakes or I am misusing the language let me know!

As a user of Elixir, it seems to me that I can write ternary expressions in Elixir by treating the if statement as an expression and it remains highly readable.

Other languages don't do this and it is a "quirk" of Elixir.  In Python, C, and C++, a regular if statement itself does not become a value and can't be used as an rvalue; it would be a syntax error to assign the if statement itself. Only Elixir allows this, and as a result if can be used as a ternary expression!

The "Ternary" Expressions in C/C++, Python, Elixir

Here's my evidence:
This is a ternary construct:
avariable = true ? 42 : 43

avariable is set to 42 if true is true.  If you can set avariable to one of two values based on a boolean test, using an expression, then that is a ternary expression. Here's a language that has a ternary expression: JavaScript.

avariable = true ? 42 : 43 //javascript

image.png

as you can see, it gets set to 42.

Now let's try it in Python.  Well, the straightforward way doesn't work:
# Python:
image.png

Instead Python does it this way:
avariable = 42 if True else 43
#Python:
image.png

This is special syntax that differs from a normal if expression, it was specifically introduced to be Python's equivalent of the ternary operator.  As I recall, Python picked this since frequently one of the values is more common.  (As an aside, in the history of language development, Perl also has an if that can come after an expression as a "statement modifiier", but in Perl that version didn't have an else clause; Perl instead used the ternary expression with ? for this purpose.)

Instead of "a? b : c" it just reads "b if a else c" in Python.

Here's Elixir's version:

iex(1)> avariable = if true do 42 else 43 end
42

image.png

if we set it to false instead we would get 43.
image.png

It's still just like a ternary operator.  Instead of "a ? b : c" it just reads "if a do b else c end".
Naturally the short form also works:
image.png

If you tried to do this in C++ or Python you would get an error. (You can't assign  = if () ... in those languages.)

# Can't do it in the Elixir order in Python.  In Python this would be an error:

# Python:
image.png

Because as mentioned earlier, if statements can't be treated like an expression the way the whole if can be treated as an expression in Elixir.

For comparison, you can't do that in C++ either.  This is broken code in C++:

// C++
#include <iostream>

int main() {
    int value = if (true) 42 else 43; // This line will cause a compilation error in C++

    std::cout << "Value is: " << value << std::endl;
    return 0;
}

image.png

Instead it works like this:

#include <iostream>

int main() {
    int value = true ? 42 : 43; // value is 43

    std::cout << "Value is: " << value << std::endl;
    return 0;
}

image.png


From this comparison, Elixir is the only language among these three languages that uses if exactly in this way.  Using if the same way in any of the other languages would be a syntax error, since the if expresssion in the other languages doesn't itself have a value and can't be used as an rvalue.

In summary then, we have this language comparison guide:

image.png


I think it works perfectly well for this purpose.  Let me know if I've misunderstood the syntax or I'm abusing the language by doing it this way!



--

Greg Vaughn

unread,
Jan 27, 2024, 1:08:20 PMJan 27
to elixir-l...@googlegroups.com
On Jan 26, 2024, at 10:52 PM, Robert Viragh <rvi...@gmail.com> wrote:
>
> As a user of Elixir, it seems to me that I can write ternary expressions in Elixir by treating the if statement as an expression and it remains highly readable.

You are so close to being correct here. You're not "treating" a statement as an expression. Elixir has no if statement. It only has an if expression. This is by design and is common among functional languages.

It just so happens that Elixir is the first language where you have encountered it. It's great to see you have a "lightbulb moment" when a new concept fits together in your mind. Google for terms such as "expression based language" for more details.

That being said, yes, this insight offers you a deeper way of looking at conditional logic in Elixir. However, a ternary operator is distinct, as José pointed out, because it is an operator.

-Greg Vaughn

oliver....@googlemail.com

unread,
Mar 20, 2024, 9:47:11 AMMar 20
to elixir-lang-core
&(&1) ...  sigh. In the project where I work I generally argue against these constructs because it really reduces readability. There's a limit of special character the brain can process correctly in a row. (My personal opinion, though.)

In general, two constructs are more common in our code:

if ... do .. else .. end # inline in any other expression
... && .. || ... # the favorite of some of my colleagues

I still limit the use of the latter one simply because it quickly gets out of hand, but for filling a field in a struct with simple values it can be really useful.

Best regards,
Oliver

Reply all
Reply to author
Forward
0 new messages