DistortedASD
DistortedASD

Reputation: 138

Julia short-circuiting

Consider

function foo(x)
    x isa Bar || throw(ArgumentError("x is not a Int64..."))

    dosomething(x)
end

as opposed to a traditional

function foo(x)
    if !(x isa Bar) 
        throw(ArgumentError("x is not a Bar..."))
    end

    dosomething(x)
end

(functionally equivalent is !(x isa Int64) && ...) Poking around a few packages, it seems this sort of conditional evaluation is not popular -- at face value, it seems convenient, and I prefer it a bit stylistically.

Is there a consensus on this stylistically? I understand that using the Unicode \in is discouraged over the word "in" by at least the Blue style guide for the sake of readability/ compatibility -- is this something similar?

Is this less performant? At face value, it seems like it would take about the same number of operations. I came across this post as well, but the answers aren't very satisfying, even ignoring that it's now likely outdated.

Upvotes: 3

Views: 182

Answers (2)

Przemyslaw Szufel
Przemyslaw Szufel

Reputation: 42214

When asking yourself performance question like this it is usually good idea to peek into compiled code via @code_lowered, @code_typed, @code_llvm, @code_native. Each of those macros explains one step further in the compilation process.

Consider

function x5a(x)
    x < 5 && (x=5)
    x
end

function x5b(x)
    if x < 5
        x=5
    end
    x
end

Let's try @code_lowered

julia> @code_lowered x5a(3)
CodeInfo(
1 ─      x@_3 = x@_2
│   %2 = x@_3 < 5
└──      goto #3 if not %2
2 ─      x@_3 = 5
└──      goto #3
3 ┄      return x@_3
)

julia> @code_lowered x5b(3)
CodeInfo(
1 ─      x@_3 = x@_2
│   %2 = x@_3 < 5
└──      goto #3 if not %2
2 ─      x@_3 = 5
3 ┄      return x@_3
)

Almost identical - will it get simplified further in the compilation process? Let's see!

julia> @code_typed x5a(3)
CodeInfo(
1 ─ %1 = Base.slt_int(x@_2, 5)::Bool
└──      goto #3 if not %1
2 ─      nothing::Nothing
3 ┄ %4 = φ (#2 => 5, #1 => x@_2)::Int64
└──      return %4
) => Int64

julia> @code_typed x5b(3)
CodeInfo(
1 ─ %1 = Base.slt_int(x@_2, 5)::Bool
└──      goto #3 if not %1
2 ─      nothing::Nothing
3 ┄ %4 = φ (#2 => 5, #1 => x@_2)::Int64
└──      return %4
) => Int64

Both functions have identical lowered codes which means that they will result in an identical assembly code and hence execute identical sets of CPU instructions.

Regarding the style - it is not documented in official style guidelines so code readability is the criterion and like Bogumil said this style is quite popular.

Upvotes: 2

Bogumił Kamiński
Bogumił Kamiński

Reputation: 69829

From my experience:

  1. There should be no performance difference between if and short-circuting evaluation. The choice should be purely stylistic.
  2. the style cond || ... and cond && ... is quite popular. Just if the expression following the || or && is long so that it would not fit a single line then if is used.

Upvotes: 1

Related Questions