Proposal: `then`, `else` syntax to replace `&&`, `||` short-circuiting

Yes, I don’t suggest doing that.

I think that was just @Palli, @Ismael-VC implemented it to be identical to && and ||, i.e. short-circuiting

1 Like

It would be nice if the OP could clarify if he wants

  1. people to stop (ab)using short-circuiting syntax for control flow
  2. to change the spelling of short-circuiting operators
  3. to remove short-circuiting operators completely

For points 1. and 3., my opinions are, respectively, “Good luck!” and “No way!”

As for point 2. you cannot get around the fact that short-circuiting operators have different use cases. No spelling will be ideal for both.

if cond1 && cond2
    do(something)
    do(more)
end

The natural way of reading this is “if condition1 and condition 2, do stuff”. Changing the spelling to then would be unnatural:

if cond1 then cond2
    do(something)
    do(more)
end

Conversely,
x < 0 && error(...)
is more naturally spelled as
x < 0 then error(...)

But you cannot have it both ways (IMO). In fact, keeping &&/|| might be preferable, since it is more abstract, and you can pronounce it “and/or” or “then/else” depending on context.

2 Likes

There was this proposal that I kind of liked: Make ? work without : · Issue #6823 · JuliaLang/julia · GitHub

This lets you write

x < 0 ? error()

and the syntax is available. We don’t necessarily need both and and or versions, since you can just invert the condition.

11 Likes

Would you then want to deprecate allowing anything (usually control flow) after && and ||?
(i.e. only allow Bool on both sides)?
? does seem reasonable to me also, better than many of the alternatives offered up, IMO.

I think that would also be clearer than what is coming up frequently in the code at our company, i.e.
cond1 && cond2 && throw(error) would become:
cond1 && cond2 ? throw(error) and
(cond1 || cond2) && throw(error) (needs parens because && higher precedence than ||) would become:
cond1 || cond2 ? throw(error)
(and we need short circuiting, because cond2 might give an error if cond1 is not true in the first case, or true in the second)

2 Likes

I remember trying this syntax when I first started with Julia version 0.3, in one of those “hoping that this works like I would expect it to” moments; I would welcome its implementation one day!

1 Like

JB has shot a hole through using else here

Just to clarify, I’m not suggesting that && should do anything different. I’m just suggesting we create an additional explicit syntax for ‘one-line-if’ and ‘one-line-ifnot’.

+1 from me for allowing a ? b

I would quite like to see a ? : b as well, as this would bring a symmetry to ? – i.e. you can miss out either branch. If I’m aware of the standard ternary operator I would straightaway realise what this syntax is doing.

Can anyone conjure a situation where this would fail to parse, though?

I think arguments against ?:

  1. !a ? b is probably easier to understand than a ?: b (or reversing the condition x >= 0 ? b instead of x < 0 ? b)
  2. with just ?, nothing else needs to be added to the language
  3. there’s no issue of worrying about whitespace (a?:b means a ?: b or a ? :b)

It was briefly mentioned in the issue, but not addressed, that this conflicts with x ? y:z; should that be a range?

It looks as though : is getting a bit overloaded/overused in Julia.

I rather like Swift’s a..b range syntax, as far as I can see that doesn’t conflict with anything. Also it is a more natural syntax – it would take some of the pressure off.

What think y’all? There is still time to change!

So that would be two breaking changes for some vague benefit of principle that is in the eye of the beholder, improving on something many other languages are fine with?

In any case, bikeshedding of surface syntax is always very tempting, and possibly innocuous. The proof of the pudding is in the PR: a simple grepping suggests 700+ obvious cases in Base that you would need to replace for the first syntax alone (did not count tests, etc). Making a PR would signal that you care about this enough to invest the fraction of the hours that you would expect others to devote if the change goes through. It would also allow you to assess the improvement in real-life examples.

3 Likes

Yes, I brought it up (there under my “Páll Haraldsson” name, not my nickname), still writing my counterproposal (mostly justification, performance analysis) for opening a new issue on Github.

julia> hello() = begin print("Hello"); return false end # think of this as just some slow function without side-effects and the other fast
julia> world() = begin println(" world!"); return true end

julia> hello() & world();
Hello world!

Is this the semantics we want for bitwise & (that order, ignoring the side-effect of actually printing anything out)?

julia> if hello() && world()
         println("This would be strange, would only happen if short-circuit was right to left..")
       end
Hello

I’m looking at all options, than only “logical” && (left short-circuit), or bitwise & (seems to [must?] evaluate left, right, then the middle - the “bitwise and”).

E.g. the non-existing right short-circuit (or other possibilities…).

[Comparisons chaining, e.g. a() < b() < c() < d() … (currently) implies a() < b() && b() < c() && c() < d() …

All (or any) of the implied && could have been right-short-circuiting (or &), so you have exponentially many options just there.

I guess the semantics of chaining must imply one operator, we as language designers “choose” that one, but it could be my super-operator and that can take many forms, allowing for any combination.]

Real “logical and” is associative, McCarty added short-circuit, conflating it with control flow.

Other options, that can be faster, are:

  • right-short-circuit
  • sometimes left sometimes right, for the same code, depending on data.
  • maybe other options with even deeper implications… I’m working on that, to see if they lead to nowhere

I want the default to be maximally fast, or at least allow the implementation to consider all the above options and optimize statically for the best way if possible, dynamically if you have to.

I think I know what Julia does currently. And many C and C++ can (and cannot do… see my survey (already with some wrong answers - for Julia, in the context of if & is safe to substitute for &&, but not in C) at:

https://www.quora.com/and-and-or-Do-you-use-or-or-or-Is-faster-than-See-details-first-not-other-answers-I-also-want-beginners-to-answer-Similar

P.S. Did you know you can overload && and || in C++? One more reason to hate C++, as it disables short-circuiting and then brakes code. Who designed that, and why? This is I guess very rarely done, but I guess the optimizer needs to know, if done…

It’s a hack yes; not strictly abusing && or || as I believe that syntax started in C. But calling it “logical and” and or without associative binary relations, as logic dictates, is however wrong. C (or earlier?) is to blame for the syntax, John McCarthy for the semantics, that is short-circuiting, stating in Lisp.

I don’t like his semantics, or [linked] lists (as in Lisp), or S-expressions/non-infix (he did plan for M-expr.); other than that I really like Lisp (reads Julia).

If we consider an open source project as some kind of a block-sliding puzzle, where one performs incremental change from one working configuration to another via a PR, it is possible that this mode of operation (i.e. Incremental change) fails to explore the entire solution space. i.e. It may fail to reach some new configuration that involves simultaneously moving several blocks.

So for that reason I think it’s worth having a discussion layer that doesn’t require a PR for every suggestion.

Pretty much every language is fine with its own syntax, just as people by and large are fine with the QWERTY keyboard (despite the keys all being in silly places) and will complain if their keyboard is replaced by a (superior) DVORAK layout.

Julia prides itself on synthesising the best syntax ideas from many languages and I think this process is still ongoing.

I still have many (tens/hundreds?) hours of learning to do before I have a deep understanding of Julia, I’m currently aiming to follow in the tracks of @Ismael-VC who is learning on his feet as he submits surface-syntax PRs. I’m working through SICP first! So I’m not making suggestions expecting anyone to do anything. I have no expectation!

2 Likes

IMO exploring the space of language design by discussion is an illusion in most cases except trivial ones. The ramifications are usually not apparent until you use them — doing a PR is just a small step towards that. Also, as noted in another thread you started, the scarce resource is developer time, not the lack of willing discussants to these bikeshedding threads.

Many projects, apparently also Julia, have a culture of asking for PRs if you want a change. This has some wonderful benefits:

  1. the proposer signals some interest in the change,
  2. the PR provides a rudimentary test of the proposal,
  3. even small PRs draw people in and familiarize them with the codebase and practices.

(2) and (3) are very important. I have abandonned many PRs midway, or refrained from submitting, learning that what I want is impractical or meaningless (2). Also, many Julia contributors will ask that you do a PR for trivial changes, even when the cost of mentoring apparently exceeds what it would take for them to do it (3). When I suggested that you do a PR if you really care about his, I was serious.

(Food for thought: most people who write code for a living and have deadlines would do more than complain if you replaced their silly QWERTY with superior DVORAK without their permission. Doing this in a company would get you fired.)

3 Likes

In this particular thread, discussion has revealed that both proposals fall through (counterexamples supplied by JB and TotalVerb). So it would have been foolhardy of me to create a PR — I’m glad I chose to open a discussion rather than just dive in.

I see the merit in all three points you make — I just haven’t yet got anything to the point where it is suitable for a PR. If preliminary discussion is stage 1 and PR is stage 2, I haven’t yet proposed something ready for stage 2.

Also, many Julia contributors will ask that you do a PR for trivial changes, even when the cost of mentoring apparently exceeds what it would take for them to do it (3). When I suggested that you do a PR if you really care about his, I was serious.

I’m very grateful to the dev community for doing this, it’s a super way of teaching!

(Food for thought: most people who write code for a living and have deadlines would do more than complain if you replaced their silly QWERTY with superior DVORAK without their permission. Doing this in a company would get you fired.)

Conversely if the entire company acts as a unit, gets their heads together, says ‘hey, if we collectively take a hit for a couple of months and put ourselves through some degree of frustration, we come out 20% more productive per year if we make the switch’ … then progress has been made!

i.e. should we not seek remedy for this ugly situation, rather than simply accept it? It is around us everywhere in the world. The structure we create becomes an obstacle for an improved structure; as it gains momentum it loses the ability to change direction. I think Julia will gain a huge amount of momentum over the next few years, with universities switching out MatLab and IPython en-masse. I think 1.0 will be a pivotal point — a public declaration of stability and readiness. Can Julia somehow protect itself against the QWERTY syndrome?

Please don’t take away this conclusion from this thread. The primary reason to encourage people to write PR’s is to ensure that the costs of their brainstorming are paid by them rather than by the other developers who have to read their comments.

Maybe we should split out these kinds of discussions from “Development” into a “python-ideas” kind of category where anything goes?

5 Likes

There does seem to be a proposal on the table that has support from at least a few people, that of @jeff.bezanson, with a single ? for a short control-flow operator.
I think that just needs someone to invest the time to write a PR, and see if it does get accepted.
A related question with that proposal, is whether && and || should then no longer accept expressions on the RHS that don’t return a Bool, which would need first a deprecation for a cycle.

I’m up for implementing cond ? expr

It will take me a while as I’m going to be slow and clumsy in the beginning, so if anyone wants it ASAP then go for it!

The primary reason to encourage people to write PRs is to ensure that the costs of their brainstorming are paid by them rather than by the other developers who have to read their comments.

Sure, an organism seeks to minimise it’s overall (appropriately weighted) cost function. But it seems a bit futile to do a lap on an exercise bike just to earn credit to say something. Pedalling should generate motion to engage the reward system.

As for the cost, I don’t want to be chewing up anyone’s time. I would have thought the cost would be higher if I go ahead with a PR, because that creates discussion on the Github Issue Tracker – surely that’s going to eat more dev-joules. Also it creates clutter – an issue/PR that will immediately be closed/rejected. Isn’t the idea to keep the core clean, taking every opportunity to move activity outwards? I am new to collaborative coding so maybe I’ve got things out of proportion…

Looks like maybe I’m making some wrong assumption as regards the purpose of these forums. I thought the idea is:

  • for the heavy lifting we have Github Issue Tracker (core devs spend most of their time here)
  • for more general discussion / brainstorming we have the discourse forums (core devs keep an eye on these)
  • for coffeebreak style / ephemeral chitchat and help we have Gitter (not so many core devs here)

i.e. Some kind of 3-tier system

I’m still not convinced that floating the proposal was a poor choice. Rather than waste my own time with a flawed PR and then dev-time scrutinizing it, I can have a crack at something that is well motivated. So I think the real question is: where to float such a discussion?

I like the idea of a “brainstorming” category. I think there should be a place for brainstorming; there is value in it.

1 Like