Sunday 7 February 2021

Ternary Operator, Expressions and Statements

Lately I've seen myself trying to overuse the ternary operator, and I've needed to review how it really works. It had made me to revisit some basic concepts like statement vs expression. In this article, if I don't specify the language it means that it applies both to C# and JavaScript. Let's see:

Expression vs Statement:
An expression returns a value.
A statement does something.
An expression followed by a ";" becomes a statement (an expression statement). But depending on the language this is not valid for all expressions.

This article is an excellent reference about expressions/statements in JavaScript. Particularly interesting sentence:

wherever JavaScript expects a statement, you can also write an expression. Such a statement is called an expression statement. The reverse does not hold: you cannot write a statement where JavaScript expects an expression. For example, an if statement cannot become the argument of a function.

An assignment does 2 things: the assignment itself and returning the assigned value. This means that you can write code like this: myFunction(a + 1);.

In JavasScript a function always returns a value. If it has no an explicit return, it returns "undefined" (that is considered as a value). This means that it's syntactically correct to use any kind of function call wherever an expression is expected. This is not the same in C#, where void is not a value.

The ternary operator is an expression made up of 3 expressions: condition, consequent and alternative. In JavaScript you can use it as a statement, and based on my precedent paragraphs, you can use as consequent and alternative code that does not look much like a expression, but indeed is treated as such. The below is perfectly valid JavaScript code (though as I explain at the end of this post, we should avoid it)


let condition = true;
let a;

condition
    ? a = "Y"
    : a = "Z";

console.log("a: " + a);

condition  
    ? console.log("True")
    : console.log("False");

The equivalent C# code will not compile. In C# the ternary operator can not be used as a statement. To make it work you'll need to use it in an assignment (even if you don't want to use the assigned value for anything).



static void ReturnNothing(string st)
{
    Console.WriteLine("inside ReturnNothing");
}

public static void Main()
{
	var a = "";
	//compiles OK, we do the assignment and pass x over
	ReturnNothing(a = "X");

	var condition = true;

	//does not compile, we can't use the ternary operator as a statement
	// condition
	//     ? a = "Y"
	//     : a = "Z";

	//we have to use this additional, useles assignment to make it compile
	var st = condition
	? a = "Y"
	: a = "Z";

	//does not compile
	// condition  
	//     ? Console.WriteLine("True")
	//     : Console.WriteLine("False");
	
}

This question explains what you can see in the code above. Though you can compile the central code, you should avoid it, as wisely explained by Eric Lippert

In my opinion, expressions should be useful for their values, and statements should be useful for their side effects. What you are running into is that you have an expression that is only useful for its side effect, and that is a bad code smell.

No comments:

Post a Comment