Named blocks and return

question

#1

Is there some control flow construct which would allow returning from an enclosing block instead of the current function? I am thinking of something similar to COMMON-LISP:RETURN-FROM. For example, it would be useful in early termination, eg in

function matched_positions(keys, argnames)
    positions = [findfirst(keys, key) for key in argnames]
    any(positions .== 0) ? false : positions
end

which could be rewritten as

function matched_positions(keys, argnames)
    function _find(keys, key)
        p = findfirst(keys, key)
        p == 0 ? return_from matched_positions false : p # hypothetical
    end
    [_find(keys, key) for key in argnames]
end

I have seen a @goto in Base, so I could probably emulate it, but I am wondering if this is a good idea.


#2

I know that this isn’t really what you’re asking for, but any and all now always short-circuit on their own on master.

This kind of behavior is a surprising non-local effect that Julia has typically steered clear from. I think that you’d be surprised by the result even in your toy example if this were implemented. I think it’d end up returning an array of length length(argnames)… but with uninitialized gibberish for trailing indices beyond the short-circuit.


#3

Thanks. Is there a way to write the above to terminate early when possible? I could not figure it out.


#4

You can use break to terminate a loop early.


#5

Apparently the issue has come up, and

function matched_positions(keys, args)
    return [begin
            p = findfirst(keys, arg)
            if p == 0 @goto nm end
            p
            end
            for arg in args]
    @label skip
    return nothing
end

does not even compile. See


#6

Sorry, I can’t figure out how that would help me. I find that

function findfirst_allornothing(A, B)
    positions = similar(B, Int)
    for (index, b) in enumerate(B)
        p = findfirst(A, b)
        p == 0 && return nothing
        positions[index] = p
    end
    positions
end

works, ie

julia>  findfirst_allornothing([:a,:b,:c], [:b,:a])
2-element Array{Int64,1}:
 2
 1

julia>  findfirst_allornothing([:a,:b,:c], [:d])
# nothing

If someone could post a version with break that is more elegant, I could learn from that. I don’t see a way to combine break with collections though.