Up to Main Index Up to Journal for July, 2025 JOURNAL FOR TUESDAY 29TH JULY, 2025 ______________________________________________________________________________ SUBJECT: A ternary conditional for Mere DATE: Tue 29 Jul 15:25:55 BST 2025 A feature often requested for my programming language Mere is for a ternary operator. Initially I wasn’t sure I wanted a ternary operator. It can lead to crytptic code, especially when nested. Indeed, Go does not have a ternary operator for this very reason — “used too often to create impenetrably complex expressions”[1]. However, a simple single instance can be quite elegant: quote = b==2 ? "to be" "not to be" Consequently, I have spent ages implementing such an operator. Most of the time was spent dithering on its form and whether the conditional should be a relaxed ‘truthy’ test or a strict boolean true/false test. I went for strict. The ternary operator ‘?’ is a conditional expression. In Mere it has the form: condition ? (expression1, expression2) For simple expressions the parentheses and comma can be omitted. The condition is a boolean value. If the condition evaluates to true then expression1 is returned, otherwise expression2 is returned. This is equivalent to the following longhand if-else-fi statement block: if condition == true result = expression1 else result = expression2 fi Here is a simple example of using the ternary operator: func display n println n " item" n==1 ? "" "s" end @display 0 // displays "0 items" @display 1 // displays "1 item" @display 2 // displays "2 items" This is equivalent longhand code for the function using an if-else-fi block: func display n if n == 1 suffix = "" else suffix = "s" fi println n " item" suffix end A little care has to be taken as Mere does not currently have any sort-circuit evaluation yet. This means that both expression1 and expression2 are always evaluated, in that order. The ternary operators may be nested: println a == 1 ? "one" a == 2 ? "two" "many" The ternary operator has right associativity. In the above, assuming a is 10, ‘a == 2 ? "two" "many"’ is evaluated first returning “many”. Then ‘a == 1 ? "one" "many"’ is evaluated, which also returns “many”. If there are many nested ternary operators, it can also be written using this form: println a == 1 ? ("one", a == 2 ? ("two", "many", )) This can be seen as a little ugly as commas and parenthesis are required to allow splitting the expressions over multiple lines. In either case, it is the longhand equivalent of: if a == 1 println "one" elif a == 2 println "two" else println "many" fi As currently implemented, due to there being no short circuit evaluation, all of the nested ternary operators will be evaluated. A better approach than deeply nesting ternary operators would be to use if-elif-fi or a table lookup. When testing with 10 nested ternary operators against a if-elif-fi block, the if-elif-fi block was about 33% faster. This is mainly due to the if-elif-fi being able to skip additional processing once a match was found. The optimizer has a rule for when the condition evaluates to a constant bool. Borrowing from an example in Go issue #33171, consider the following code where Production is known at compile time: const Production = true const Port = Production ? 80 8080 println "Using port: " Port This is optimized to the equivalent of: const Production = true const Port = 80 println "Using port: " 80 While the conditional is a strict boolean test, a more relaxed ‘truthy’ test can be achieved using a boolean conversion. In converting to a boolean, zero values for a type, empty arrays, empty maps and undefined variables all evaluate to false. For example: list = "" range ; item; []string "ant", "bat", "cat" list += bool list ? ", " "" list += item next println list // displays "ant, bat, cat" Here the “bool list” evaluates to false if ‘list’ is an empty string, the zero value for a string, otherwise it evaluates to true. If the list isn’t the empty string we append “, ” else we append an empty string “”. The above is only an example, it can be more efficiently written as: println []string("ant", "bat", "cat") ~j ", " This is only an initial implementation and I consider it experimental. -- Diddymus [1] https://go.dev/doc/faq#Does_Go_have_a_ternary_form Up to Main Index Up to Journal for July, 2025