Short circuit evaluation vs if

I am trying to understand efficient coding practices looking at source code of released packages and comparing to what I would write. I find some developers use short circuiting instead of an if statement.
For example in Weave.jl package source

Base.Meta.isexpr(expr,:(=)) && (options[expr.args[1]] = expr.args[2])
Base.Meta.isexpr(expr,:toplevel) && map(pushopt,fill(options,length(expr.args)),expr.args)

There is an example in the docs which encourages this.

true && (x = (1, 2, 3))

vs

if true 
  x = (1,2,3) 
end

Could someone please lend some insight into the advantages/disadvantages of using short circuiting compared to an if statement?

Personally, I think it hinders readability, however I will adopt it if there are other advantages.

4 Likes

I mostly find it useful when the if block is just a single line and the condition is somewhat short.

6 Likes

In addition, && has become kind of common for returning early, eg

function f(x)
    is_special(x) && return "special"
    y = do_the(x)
    z = rest_of_the(y)
    calculation(y, z)
end
7 Likes

Short circuit evaluation is best applied in these situations:

  • between clauses of a compound conditional
  • between a simple validation and throwing an exception
  • between a state check and an early return
if x < 0 && y <= 0
  z = x
end

iszero(x) && throw(DomainError("x must be nonzero"))

x == y && return 0.0
return x/y

otherwise use an if block

7 Likes

As far as I can tell, it is purely a matter style and taste. Many people who program in Julia like concise code, and the short circuits help with that.

If you prefer if blocks for readability, there is no reason not to use that.

8 Likes

I am not a fan of && used as a one-liner IF. Julia is great because it’s mostly What You See Is What You Mean, with very little extra cruft. But the one-liner is an idiom, in the sense that it looks like a logical comparison, and only makes sense as IF for those familiar with short-circuiting. I’d like for code just to make sense to anyone, without need for much cultural background. This kind of tricky-cool pattern was pervasive in the bad-old days of Perl, and it makes me cringe to see it in Julia, especially semi-encouraged in the documentation. What You See Is Sensible Only If You Parse Like a Compiler.

If people really want one-liners, why not provide more explicit syntax for that?

if x==y then return 0.0 instead of &&
if x==y else return 1.0 instead of ||

Of course, people should be free to code however they want. But the heavy use of idioms seems to be a sign of demand for syntactical sugar, like an explicit one-liner if.

4 Likes

See

3 Likes

The two forms produce exactly the same code:

julia> Meta.@lower test && something()
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope'
1 ─      goto #3 if not test
2 ─ %2 = something()
└──      return %2
3 ─      return false
))))

julia> Meta.@lower if test; something(); else false; end
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope'
1 ─      goto #3 if not test
   └
    @ REPL[19]:1 within `top-level scope'
2 ─ %2 = something()
└──      return %2
3 ─      return false
))))

So the only difference is how it looks to humans. I remember not really liking it at first, but I now really like it, especially for quick defensive argument checks. I still don’t really like it for much more than test || error() — in fact I’d favor a PR that changed the doc example you initially cite which uses an assignment to show the side-effect because I don’t think that’s where this feature shines.

10 Likes

That’s a nice discussion going back three years, that looks like it might eventually lead to some new syntax! Meanwhile, it would also be nice to provide less encouragement of the short-circuit pattern. It’s fine for the cool kids to use it in their own code, but the documentation could encourage clarity rather than making it seem cool to use it.

https://github.com/JuliaLang/julia/issues/16389

1 Like

There shouldn’t be any difference in terms of speed. I prefer if because it is more readable and also more familiar to other programmers.

I think it’s time for Julia to support one-line conditionals (omitting the end keyword) as many old languages do. Compare Fortran and C one liners vs. Julia’s &&:

if (.true.) x = x + 1  # Fortran   
if (true) x += 1;      # C
true && (x += 1)       # Julia
if true x += 1         # Julia (unsupported)

I’m not sure what you meant by “it’s time”. If anything, the change you propose is a major breaking change (the syntax, as appears on a single line, is valid as is awaiting an end in the coming lines) so it’s definately not the right time to do such a change.

Also, I’m not sure what you are trying to show with the comparison of the “one liners”. If you are talking about length, the current julia one is already the shortest. If you just want if, then just keep the end and it’s a single character longer than the C one and still shorter than the fortran one.
Or if you just don’t like end, and I should say I don’t like it either mostly due to the dual use of it in indexing, it’s the property of the language and the if isn’t something you should single out on.

8 Likes

May be I used the wrong expression with the word “time”, I meant at least to be scheduled for the next major version, the discussion at this issue https://github.com/JuliaLang/julia/issues/16389 seems to reach at nothing.

Personally, I use && very often for early returns and for throwing exceptions. But, the problem with true && (x += 1) for example is that it is not as clear as if, especially for new users. And if one drops the parens, it will parse as (true && x) += 1 which is an invalid assignment.

I don’t also like end at the same line with if, I see it unnecessary and think it is more suitable for ending a block, besides being used for indexing as you said. I’m not sure though how hard it is to parse the the one-liner if without end.

1 Like

As I said, it incompatible with the current parsing

1 Like

Generally, a lot of specific syntactic extensions were proposed to Julia prior 1.0. While some of these may be useful, I think that in general 90% of these should be reviewed and then closed because the extra complexity is not worth the benefit.

While most people (and some style guides) avoid assignents after &&, IMO

condition && return stuff

is a perfectly good idiom, and for assignments writing out the multi-line if is a feature as it calls attention to changes in values, which may get lost in one-liners, so I would suggest sticking to

if condition
    x += 1
end
3 Likes

One difference that hasn’t been mentioned yet is the interaction with line-based coverage analysis. A one-liner (short-circuit or an if expression written on one line) gives no information whether you have covered the conditional branch, whereas a multi-line if does.

Normally more information is better but it’s a trade-off with other aspects of the code. In particular error exits are not necessarily worth the effort of covering.

6 Likes

I just found this thread a bit late into the game. Learning from Julia manual, I was a bit surprised to see this idiom promoted. My main concern is with this pattern:

condition || action()

which is equivalent to:

if !condition action() end

It seems to be counterintuitive and I’m sure led to an error or two. This is somewhat mitigated by this equivalence:

if condition else action() end

but only a little bit. This leads me to the question: is it accepted in Julia style guides to put a short if statement in a single line?

I just noticed an ominous warning Are you sure you want to continue this old conversation. I hope it is OK.

1 Like

Most forums prefer users to create new threads than posting to very old threads. The reasons vary, but I think it is mostly because all people of the previous conversation are notified of a new reply and become confused for a moment. Avoid it if possible. Probably there is one or another case it is the best course of action.

This is subjective. The notation is entirely natural to me, I read it as “OR this condition is true, OR we need to do this”.

A style guide is often not enforcing, you can do it. However, I would point that: (1) if you are using an if already, you can also use three lines instead of putting the if in a single line; (2) the style guide of the specific library you are working with has precedence, JuMP style guide, for example, clearly opposes one recommendation of the Julia Style guide:

Use of underscores within names

The Julia style guide recommends avoiding underscores “when readable”, for example, haskey , isequal , remotecall , and remotecall_fetch . This convention creates the potential for unnecessary bikeshedding and also forces the user to recall the presence/absence of an underscore, e.g., “was that argument named basename or base_name ?”. For consistency, always use underscores in variable names and function names to separate words.

2 Likes

I like your reading.

I meant it is a bit counterintuitive or unusual for a C/C++ user. You could write:

condition || action()

in C++ and many other languages with short-circuiting ||, but I’ve never seen it promoted as an idiom. Maybe it will grow on me. :grinning:

1 Like

Joining this thread a little late, but I just started using julia and I like the short circuit evaluation once I figured out what it was.

For readability, I might suggest “condition then statement” since “&&” can easily be misinterpreted. Dropping the false (||) would be okay because !cond accomplishes the same thing.

My two cents…