No ternary operator?!

6,768 views
Skip to first unread message

Sam Fredrickson

unread,
Nov 12, 2009, 1:08:23 AM11/12/09
to golang-nuts
How can you call your self a C-like language and NOT have the ternary
operator? But seriously, why isn't it in Go? This could be a deal-
breaker for me, as it's often more succinct and clear to use a ternary
operator than an if/else, *especially* if you require curly braces
even for single-line blocks.

John Barker

unread,
Nov 14, 2009, 1:03:57 AM11/14/09
to golang-nuts
Then "go" write your own language or use a language that makes use of
your precious ternary operator.

Loren Brichter

unread,
Nov 14, 2009, 1:53:34 AM11/14/09
to golang-nuts
I like the ternary operator, and I think it would be a nice addition.
But I think there are deeper implications that need to be weighed
(more than "it's better than if/else so do it or else it's a deal
breaker"). The fact that the syntax is so simple seems to be one of
the great strengths of the language, can the ternary syntax be
implemented without complicating the parser?

Saying that such an insignificant language shortcut is a "deal
breaker" leads me to believe you're missing all the other great
innovations here. It's insulting to the authors who clearly put a
*ton* of thought into the language. And like they said, it's still
unfinished.

Ask nicely, outline the arguments for it, bring up any potential
downsides. Download the code – see if you can add the feature
yourself. Nobody owes you anything.

philcolbourn

unread,
Nov 14, 2009, 2:39:42 AM11/14/09
to golang-nuts
Could it be because the ?: would make the parser slower or require
multiple passes?

David

unread,
Nov 14, 2009, 6:01:03 AM11/14/09
to golang-nuts
I like the ternary operator and use it often (it's especially useful
in soft-typed, special-purpose languages like PHP).
HOWEVER, more often than not, the ternary operator introduces
ambiguities and makes code more difficult to read.

Let alone the extra overhead of re-writing a code block if another
case comes up later in production and you have to catch it via a new
else-if branch.

j-g-faustus

unread,
Nov 14, 2009, 7:38:28 AM11/14/09
to golang-nuts
I missed it too. But I think it's no great loss, especially since we
got the extended switch() statement instead - I think my savings in
typing there more than outweighs the loss on the ternary operator.

Christoffer Hallas Pedersen

unread,
Nov 14, 2009, 8:08:55 AM11/14/09
to golang-nuts
I must have missed this, but a function seems unable to call it self. I
am using a function named "recurrence", inside of it I am defining a
function "iterate", var x = func() {};

Iterate is a recursive function but it cant call it self. Should i
declare the function somewhere so the function knows it exists before
its defined, if u understand, just like in C.

Hope you can understand.

C.

Chas. Owens

unread,
Nov 14, 2009, 9:52:12 AM11/14/09
to Christoffer Hallas Pedersen, golang-nuts
Well, simple recursion works just fine:

package main

import "fmt";

func r(i int) int {
fmt.Printf("%d\n", i);
if i <= 0 {
return i;
}
return r(i - 1);
}

func main() {
r(5);
}

I am not sure why you want to use a function variable to implement
recursion, but here you is one way:

package main

import "fmt";

func r(i int) int {
var f func (int) int = r;
//or the more succinct
//f := r;
fmt.Printf("%d\n", i);
if i <= 0 {
return i;
}
return f(i - 1);
}

func main() {
r(5);
}


--
Chas. Owens
wonkden.net
The most important skill a programmer can have is the ability to read.

Ian Lance Taylor

unread,
Nov 14, 2009, 9:54:54 AM11/14/09
to Christoffer Hallas Pedersen, golang-nuts
When starting a new topic, please send a new e-mail message rather
than replying to an existing one. Otherwise your message appears
incorrectly threaded for people who use threaded e-mail readers.
Thanks.


A closure is just a value which gets assigned to a variable, so to
call it assign it to a variable and call the variable. You can't use
the := syntax for this, because the new variable won't be defined on
the right hand side. But you can do it like this:

package main
import "fmt"
func main() {
var fac func(i int) int;
fac = func(i int) int {
if i == 1 {
return 1;
}
return i * fac(i - 1);
};
fmt.Println(fac(5));
}

Ian

Christoffer Hallas Pedersen

unread,
Nov 14, 2009, 10:00:25 AM11/14/09
to Chas. Owens, golang-nuts
ty.

Edward Marshall

unread,
Nov 14, 2009, 10:13:03 AM11/14/09
to golan...@googlegroups.com
On Sat, Nov 14, 2009 at 6:38 AM, j-g-faustus <johannes...@gmail.com> wrote:
I missed it too. But I think it's no great loss, especially since we
got the extended switch() statement instead - I think my savings in
typing there more than outweighs the loss on the ternary operator.

Ternary notation in C/PHP/etc. is useful, but awful to read back later:

    a = b > c ? b : c

Not exactly readable. The Python take on it is at least a bit more obvious to the casual reader:

    a = b if b > c else c

A combination of assignment and comparison is mentally useful, but it's a small thing; the equivilent in Go:

    if b > c { a = b; } else { a = c };

Really, not that bad, albeit with a bit of stuttering. Arguably, if you're doing anything more complicated than this with a ternary operator, you probably shouldn't be, for your own sanity later on.

--
Ed Marshall <e...@logic.net>
Felix qui potuit rerum cognoscere causas.
http://esm.logic.net/

Jessta

unread,
Nov 14, 2009, 10:24:44 AM11/14/09
to Sam Fredrickson, golang-nuts
you can always do this instead, it's kind of the same.

stuff := func()int{if 5>6 {return 8} return 5}();

- Jessta
--
=====================
http://jessta.id.au

Edward Marshall

unread,
Nov 14, 2009, 10:41:40 AM11/14/09
to golang-nuts
On Sat, Nov 14, 2009 at 9:24 AM, Jessta <jes...@gmail.com> wrote:
you can always do this instead, it's kind of the same.

stuff := func()int{if 5>6 {return 8} return 5}();

My eyes, they burn! *grin* If all you're looking for is a one-line conditional assignment, a basic if/else on one line would be more readable than that.

(That's not to say I don't agree that ternary operations aren't mentally useful, but not at the expense of readable results.)

Edward Marshall

unread,
Nov 14, 2009, 11:02:33 AM11/14/09
to golang-nuts
On Sat, Nov 14, 2009 at 9:41 AM, Edward Marshall <e...@logic.net> wrote:
(That's not to say I don't agree that ternary operations aren't mentally useful, but not at the expense of readable results.)

Tell you what, here's an implementation taken out of VB's playbook:

package main
import "fmt";

func Tern(exp bool, a interface{}, b interface{}) (interface{}) {
    if exp { return a }
    return b
}

func main() {
    a := 7; b := 1;
    result := Tern(a > b, a, b);
    fmt.Printf("%d\n", result);
}

You know, I'm really starting to like this language. ;-)

Chas. Owens

unread,
Nov 16, 2009, 8:46:46 AM11/16/09
to Edward Marshall, golang-nuts
This lacks a vital component of the conditional operator (often called
the ternary operator): only a or b will be evaluated, never both.

package main
import "fmt";

func Tern(exp bool, a interface{}, b interface{}) (interface{}) {
if exp { return a }
return b
}

func foo() int {
fmt.Println("foo");
return 1;
}

func bar() int {
fmt.Println("bar");
return 0;
}

func main() {
a := 7; b := 1;
result := Tern(a > b, foo(), bar());
fmt.Printf("%d\n", result);
}

vs

#include <stdio.h>

int foo() {
printf("foo\n");
return 1;
}

int bar() {
printf("bar\n");
return 0;
}

int main(int argc, char** argv) {
int a = 7;
int b = 1;
int result = a > b ? foo() : bar();
printf("%d\n", result);
return 0;

Edward Marshall

unread,
Nov 16, 2009, 9:10:46 AM11/16/09
to Chas. Owens, golang-nuts
On Mon, Nov 16, 2009 at 7:46 AM, Chas. Owens <chas....@gmail.com> wrote:
This lacks a vital component of the conditional operator (often called
the ternary operator): only a or b will be evaluated, never both.

Good point, I did miss that. Your example hints at a partial solution: reflect on the second and third arguments and, if they're funcs passed by reference, evaluate only the winning function (otherwise, simply return the value provided). But, the behavior starts becoming less obvious, and the calling idiom becomes uglier in relatively simple cases.

Either way, "if {...} else {...}" still works just fine. :)

Chas. Owens

unread,
Nov 16, 2009, 9:13:08 AM11/16/09
to Edward Marshall, golang-nuts
To get the proper behavior, you would need to say something like

package main

import "fmt"

type Delayed func () (interface {})

func Cond(test bool, a Delayed, b Delayed) (interface {}) {
if test {
return a();
}
return b();
}

func foo() int {
fmt.Println("foo");
return 1;
}

func bar() int {
fmt.Println("bar");
return 0;
}

func main() {
a := 7;
b := 1;
result := Cond(a > b, func () (interface {}) { return foo() }, func
() (interface {}) { return bar() } );
fmt.Printf("%d\n", result);
}

And at that point it is probably cleaner to say

var result int;
if a > b {
result = foo()
} else {
result = bar()
}

even with the code repetition.

Chas. Owens

unread,
Nov 16, 2009, 9:24:45 AM11/16/09
to Edward Marshall, golang-nuts
Well, if/else does work, but the real win of ?: is that you can use it
to factor out common parts of the code. Compare

var result int;
if a < b {
result = a
} else {
result = b
}

with

result := a < b ? a : b;

In the code that works now, you have to repeat the assignment to
result. Repeated code leads to bugs. At least Go's type system and
unused-variable error will find most of those bugs at compile time
(unlike what happens to most dynamic languages).

Oleku Konko

unread,
Aug 7, 2013, 12:39:35 PM8/7/13
to golan...@googlegroups.com


Am sure this might be reconsidered in future .. but for now  this works :

func T(exp bool, a interface{}, b interface{}) (interface{}) {
    if exp { return a }
    return b
}

Thomas Bushnell, BSG

unread,
Aug 7, 2013, 12:49:14 PM8/7/13
to Oleku Konko, golang-nuts
How indeed! It would surprise you no end to discover that Scheme is described as an Algol-like language. Sometimes the things people are referring to by such statements are about very deep similarities, and not superficial ones.


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

chris dollin

unread,
Aug 7, 2013, 1:05:12 PM8/7/13
to Oleku Konko, golan...@googlegroups.com

It does not work. Unlike an if-expression, both of the conditional parts. Are evaluated at the call. (also the result will have to be converted back to the right type.

Chris onna bus.

--

Matthew Kane

unread,
Aug 7, 2013, 1:13:25 PM8/7/13
to chris dollin, Oleku Konko, golang-nuts
So have T() take two functions returning interface{} instead.

func T(exp bool, a func() interface{}, b func() interface{}) (interface{}) {
if exp { return a() }
return b()
}

An example:
aNumber := T(4 == 5, func() { return 17 }, func() { return 102 }).(int)

Of course, this is idiomatic SuperCollider, not idiomatic Go.
--
matt kane
twitter: the_real_mkb / nynexrepublic
http://hydrogenproject.com

Michael Jones

unread,
Aug 7, 2013, 1:40:37 PM8/7/13
to Matthew Kane, chris dollin, Oleku Konko, golang-nuts
Should there be real heartburn about this, I'd suggest a different solution taken partially from GCC's extensions to the C/C++ languages.

1. GCC allows an expression in braces to have a value; the value of the final statement. ("x = {b += 20; b--}" will assign b+19 to x. ("x = {c += 20; c--; 42}" will assign 42 to x.

2. Algol68/Pascal/Modula/etc. all appreciate "if" more generally than most of the languages that followed them.

Synthesizing these two ideas gives...(drumroll)...

x := if exp {a} else {b}

For the declarational use here the types of a and b would need to match. What this would change in Go would be that an expression could also be an "expression-if" as well as a "statement-if" where an expression-if has a value for any LHS that wants it. This could be applied to switch statements too as desired. Alternatively, you could have expression-if (and expression-switch if desired) simply be normal statements by expanding the logic of if (and switch) to provide their "final statement" as their RHS should they be used in a case where that value is desired: assignments, declarations, function calls, etc.)
Michael T. Jones | Chief Technology Advocate  | m...@google.com |  +1 650-335-5765

Melvin Tercan

unread,
Aug 7, 2013, 2:39:06 PM8/7/13
to golan...@googlegroups.com, Edward Marshall, chas....@gmail.com
if a < b { 
    result = a 
} else { 
    result = b 

I would write this as:

result = b
if a < b { 
    result = a 
}

TR NS

unread,
Aug 7, 2013, 9:15:56 PM8/7/13
to golan...@googlegroups.com, Matthew Kane, chris dollin, Oleku Konko


On Wednesday, August 7, 2013 1:40:37 PM UTC-4, Michael Jones wrote:

1. GCC allows an expression in braces to have a value; the value of the final statement. ("x = {b += 20; b--}" will assign b+19 to x. ("x = {c += 20; c--; 42}" will assign 42 to x.

2. Algol68/Pascal/Modula/etc. all appreciate "if" more generally than most of the languages that followed them.

Synthesizing these two ideas gives...(drumroll)...

x := if exp {a} else {b}

 
+1

Tamás Gulácsi

unread,
Aug 7, 2013, 11:58:28 PM8/7/13
to golan...@googlegroups.com
-1

Just way too easy to abuse the ternary operator...

frankr...@gmail.com

unread,
Aug 8, 2013, 2:06:03 AM8/8/13
to golan...@googlegroups.com
+1 -1 ... +1 ;)

when I started Go, I have read some of its rules before that made me hesitant, but given the authors track record and my deep admiration for all the books/articles that Rob wrote, I decided to put my trust in their decisions and gave it a go...

Now I can live with all these rules and with most of them even quite fine and I do enjoy all those great decisions and even after a few weeks do feel that Go might be my most-productive language+environment ever - anyway one of the few things I'd still like to have are an if-expression and a switch-expression. From my POV it's the best compromise.

And hello group btw - Frank
Reply all
Reply to author
Forward
0 new messages