Julia has let block in case you need a local scope, so you don’t often need ad-hoc defined+called anonymous function for that as in JavaScript. But another sugar in the ad-hoc called function syntax is, you can early-return inside that block.
I’m not sure this is my new discovery in Julia, though the approach is rather simple.
function depart(f, args...) f(args...) end
Then for lengthy blocks those don’t deserve a dedicated function name:
m, n = 2, -7
#...
depart(3n, m) do x, y
if x > 10
println("Big x=$x vs $y")
return
end
if x < 0
println("Negative x=$x vs $y")
return
end
@assert false "Not that anyway expected."
end
I like it quite much, and I hope it be appropriate Julia practice, what’s your thoughts?
I’ve definitely wished on few occasions to be able to “break out” of the current let (or similar) block. But break can’t be used for that in a non-breaking julia change, and I’d guess the usefulness of this is too marginal to introduce a new keyword for it. Your trick with depart is cool, although I would probably not bother in general, and instead just use if/else blocks, or even @goto end_of_block if it’s more practical.
julia> m, n = 2, -7
(2, -7)
julia> map(3n,m) do x, y
if x > 10
println("Big x=$x vs $y")
return
end
if x < 0
println("Negative x=$x vs $y")
return
end
@assert false "Not that anyway expected."
end
Negative x=-21 vs 2
But map would collect the results into a vector, which is bloating if you don’t need that. Also depart seem to express the intention clearer, i.e. marking a return point for nested returns.
Nice idea. Regarding the name, I find depart a bit misleading - it enables departing, doesn’t perform a depart itself. Some names that occur off the top of my head are:
departable(3n, m) do ... - seems fine; I would prefer the return keyword was more directly referred to somehow, but one can get used to this; maybe someone unfamiliar could read it as something to do with tables, though that also seems a minor first-use-only issue.
exitable(3n, m) - I can’t decide if this sounds cool or sounds weird. Leaning towards weird tbh.
withreturn(3n, m) - I like that it explicitly mentions the return which makes the point of the block immediately clear. That makes me slightly prefer this over departable
returnable(3n, m) - this makes it sound like this is something to be returned, not something in which return happens
breakable(3n, m) - this is like departable, but uses a more familiar keyword, and one can quickly learn to see returns within the block as breaks
For those that don’t mind verbose names, breakableblock is a good name too.
(One could turn either of the last two into a macro and have it accept actual break statements, and replace those with return statements in the macro - but let’s keep it simple here.)
Oh, and for those familiar with Lisp-y languages, apply is a nice name too. For those with that context, the returns will have obvious meaning.
PS: On that note, I find it surprising that Julia doesn’t have a apply/call function or statement (unless I’m forgetting something?). Neither invoke nor invokelatest is directly equivalent to a normal function call in all situations. One can do this using the non-allocating Iterators.map and only, but it’s clunky (in terms of syntax):
julia> Iterators.map(3n, m) do x, y
if x > 10
println("Big x=$x vs $y")
return
end
if x < 0
println("Negative x=$x vs $y")
return
end
@assert false "Not that anyway expected."
end |> only
Negative x=-21 vs 2