Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make ? work without : #6823

Open
davidanthoff opened this issue May 12, 2014 · 25 comments
Open

Make ? work without : #6823

davidanthoff opened this issue May 12, 2014 · 25 comments
Labels
needs decision A decision on this change is needed

Comments

@davidanthoff
Copy link
Contributor

There was a discussion about this pattern in Julia on the mailing list recently:

...
flag = true
...
flag && (x = rand(2,2))
...

I very much see the need for something short and sweet in these cases (rather than a long if ... etc), but this particular syntax strikes me as pretty opaque to new users. I've also seen things like

...
flag = true
...
flag && error("Error")
...

Which again is super useful for e.g. argument error checking, but somehow to me looks like a misuse of &&.

Couldn't ? without a : work in these cases? I.e. the following syntax:

...
flag = true
...
flag ? x = rand(2,2)
...

and

flag = true
...
flag ? error("error")
...

Essentially ? would just be a shorthand notation for an if.

@ivarne
Copy link
Sponsor Member

ivarne commented May 12, 2014

Great!

What would

Y = flag ? x = 1 : 4

Mean?

@davidanthoff
Copy link
Contributor Author

Same thing it means today? Sorry, I guess I'm not getting your point :)

@ivarne
Copy link
Sponsor Member

ivarne commented May 12, 2014

Some might think you are assigning a range.

flag ? x = (1:4)

@davidanthoff
Copy link
Contributor Author

Good point. On the other hand, is it really much worse than what is currently happening? At least I had to try out what

flag ? 1:2:3

actually does. It just seems that one needs to know the rule for how ranges and ?: interact in any case, right?

Another option could be to use ?? for this. In any case, the flat && something notation seems like a hack to me with a potential for a cleaner syntax.

@joehuchette
Copy link
Member

I could see keywords and = && and or = || being useful in this situation (although I've gotten used to and now love how concise using && and || is).

@mbauman
Copy link
Sponsor Member

mbauman commented May 12, 2014

I don't know that I really understand the motivation. Do you not like the way && looks? Or do you not find it very readable? Short-circuit evaluation is pretty standard across many languages, although not many use it idiomatically for control flow. Are there any languages that allow you to omit the colon of a ternary conditional operator? There's a GNU C extension that lets you omit the true branch expression… but that's different.

If you're after a more readable alternative, I'd go for more verbose and standard instead of less. One suggestion a while ago was to introduce the then keyword for this, e.g., if flag then x = rand(2,2). I really like the way that reads, personally, but an if without an end would make editor code folding support a bit tougher.

The disadvantage here would be that it requires one more language keyword. I don't think it'd be too terrible to deprecate, but it's not a decision to be taken lightly. The same would be true for and and or.

@davidanthoff
Copy link
Contributor Author

I think short-circuit evaluation is one of those things that is super natural to programmers but to most non-programmers it really looks weird to do control flow via that trick. I think code could be more easily understood if there was some way to do one-line if...then... semantic with a more obvious syntax than short-circuit evaluation. The if flag then thing would also work. If that debate is still ongoing maybe this issue should be folded in (I just tried to search for it but the search terms "if then" is not ideal ;)

@mbauman
Copy link
Sponsor Member

mbauman commented May 13, 2014

It was a julia-users discussion thread. Also related is the and/or issue: #5238.

@yurivish
Copy link
Contributor

Would a || b ? return c do something different from a || b && return c? I found myself writing the latter today, which behaved differently than I meant it to; if a is true, the return condition is never evaluated.

@JeffBezanson
Copy link
Sponsor Member

That's a good point; ? has lower precedence than && and ||, which makes it better for "guarding" a return or assignment.

I actually like the idea of allowing ? without :. Currently it is a syntax error, so it should be simple to support without breaking much.

@StefanKarpinski
Copy link
Sponsor Member

I'm kind of shocked that you like this. It is currently fine to put the colon on the next line in a ternary operator expression. While I think that's uncommon, it will potentially break code. I guess we can do that though.

@JeffBezanson
Copy link
Sponsor Member

I don't believe that is true:

> (julia-parse "true ? b
: c")
error: colon expected in "?" expression
#0 (error ("colon expected in \"?\" expression"))

@StefanKarpinski
Copy link
Sponsor Member

Well, what do you know. I guess I never tried that. Then this syntax is actually available. If we're going to start doing things with ? can I lobby for also letting d[k] ?= ex mean what get!(()->ex, d, k) currently means, but without actually having to create the thunk?

@lucasb-eyer
Copy link
Contributor

I just stumbled upon the "colon on next line" thing and wanted to report it as a bug, because I'm used to be able to format the ternary that way in C/C++ and wanted to do it in Julia too:

α(t) = t < 1000  ? 0.5  - 0.46/1000* t
     : t < 10000 ? 0.04 - 0.04/9000*(t-1000)
     : 0

My current alternative looks slightly worse to me:

α(t) = t < 1000  ? 0.5  - 0.46/1000* t       :
       t < 10000 ? 0.04 - 0.04/9000*(t-1000) :
                   0

Mind you, this is a very minor complaint.

@StefanKarpinski
Copy link
Sponsor Member

I would also expect it to be possible to have the : on the next line and would be quite surprised for a ? b by itself to mean if a; b; end. If we're going to do that, then there have been several other less unusual suggestions put out there already, including b if a and if a then b on a single line.

@quinnj
Copy link
Member

quinnj commented Jun 20, 2014

I would also be in favor of if a then b as the go to one-liner for conditionals. It's simple, clear, very readable and doesn't confuse anything else we're already using.

@goszlanyi
Copy link

+1 for if a then b

@davidanthoff
Copy link
Contributor Author

Is there some new issue that tracks suggestions like if a then b, or some other alternative? I didn't get the impression that there was overwhelming dislike for some solution to this in the discussion here, so not clear to me why this issue is being closed.

@p-i-
Copy link

p-i- commented Jan 6, 2017

If we drop the leading 'if, we would be able to do:

a then b
a else b

... both of which I think people will find perfectly clear / readable / obvious without explanation.

Thread here: https://discourse.julialang.org/t/proposal-then-else-syntax-to-replace-short-circuiting

@JeffBezanson
Copy link
Sponsor Member

JeffBezanson commented Jan 6, 2017

I don't think that else syntax is workable, since the following currently parses:

if 1 < 0
2 else 3
end

or more generally when writing conditional expressions on a single line, if 1 < 0 2 else 3 end.

@StefanKarpinski
Copy link
Sponsor Member

@p-i-: that's basically already how I read && and || in my head. To me the only real issue with && and || is precedence issues with assignment (i.e. x = y && z vs x && y = z).

@StefanKarpinski
Copy link
Sponsor Member

Looking at the precedence table, I'm starting to think the Perl solution of having two different pairs of short-circuit operators for this is actually not so bad: && and || have higher precedence than arrows, conditionals or assignment (as they currently do) while and and or have lower precedence than assignment. However, we have the added complication of xor, & and | (as well as .& and .|) so there's a lot of things to sort out. Basically, I think what we have now is not so bad.

@jballanc
Copy link
Contributor

jballanc commented Jan 8, 2017

Perhaps consider borrowing Ruby's post-fix conditionals? b if a and b unless a? I know opinions on this particular feature vary, but I've always found them extremely useful.

EDIT: Just to add...

&& and || have higher precedence than arrows, conditionals or assignment (as they currently do) while and and or have lower precedence than assignment

Ruby shares these extra operators with Perl, and anecdotally they lead to far more confusion than benefit. Beginning developers will see these in Ruby and assume && === and, which works...until it doesn't. Very little Ruby code uses and and or in practice (likely due to the post-fix conditionals being available and much more intention revealing).

@andyferris
Copy link
Member

Sorry to revisit this, but I was thinking about how some of this stuff is parsed.

In some contexts at least, I can make the Julia code

 ;

which returns nothing. Given that lack of code is basically nothing, I'm wondering if it would be natural that I could write some code like:

cond ? a : ;
cond ? : b

(Perhaps we could have shorter forms like cond ? a; and cond ?: b... these aren't really a very readable alternative to #16389 but do seem to extend the ternary to binary forms in a somewhat consistent way)

Current behavior (v0.6 and v0.7):

julia> true ? 1 : ;
ERROR: syntax: unexpected ";"

julia> true ? : 1
ERROR: syntax: space not allowed after ":" used for quoting

@rikhuijzer
Copy link
Contributor

rikhuijzer commented Dec 1, 2020

I would politely like to bump this discussion again since I think the use of

A || do_stuff() 

meaning

if !(A)
    do_stuff()
end

and

B && do_stuff()

meaning

if B
    do_stuff()
end

is just super confusing. I would argue that users expect to find whether the clause is negated in front of the clause. With this style, readers have to infer the negation from behind the clause. Also, normally the conditional has no side effects and this promotes having side effects in conditionals. As an extreme example, this approach would also suggest to new users that

if A
    do_C(x)
    do_D(y)
end

where do_C and do_Ds return type is Bool, should be rewritten to

A && do_C(x) && do_D(y)

since it requires fewer lines of code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs decision A decision on this change is needed
Projects
None yet
Development

No branches or pull requests