I came across the walrus/assignment operator in Python 3.8.
The idea is that you can make an assignment in the if-expression and the variable is only visible in the
elseif blocks. Just wondering if there’s any discussion before whether it’s a good idea for Julia… or not.
Example if it were to exist in Julia:
x = [1,2,3]
if (n := length(x)) > 0
println("There are $n elements in `x`")
println("Sorry, nothing in `x`")
So, the variable
n is not available outside of the if-block nor in the else-branch.
Currently, we could use a let-block to limit the scope of
n but it would be available in all branches of the if-block. Maybe that’s good enough for most people…
AFAICT the main difference from a
let is indention and that’s easily solvable with a macro. And python can’t do that since AFAICT they have neither
let or macros.
I believe it is good to separate additional variable scope from the expression that uses it. (i.e. it’s a bad idea to encourage
if .... long expression ... (n := sth) ..... long expression). The variable assignment should just come before where it is used. Note that the example you give is one of this case since
n is not a
Bool, you have to write sth like
if (n := length(x)) > 0 and it’s much cleaner to just write
@let n = length(x) if ... else ... end instead.
Oh yeah… my example is flawed regarding the condition. I have just updated the post.
I think a more appealing example is the walrus operator used with the comprehension expressions. Something like
[y for x in range(3) if (y := 2 * x) > 1] in Python.
That case is similarly easy to handle with a
let around the generator though.
It’s slow due to boxing and also not parallelizable (e.g., when reducing a lazy iterator constructed by the comprehension).
I’m not opposed to us getting this doo-hicky, but I don’t think it really helps with anything. It makes code shorter, but often more confusing! Is there any way a variable like this could be treated differently by the compiler for some kind of speed boost or something?
The main reason Python needs this operator isn’t scoping but because
x = ... doesn’t have a return value.
It’s kinda crazy that
if statements don’t generally introduce scopes but this does?
So it the difference between the walrus operator in Python and our assignment operator is that the walrus operator makes a local binding. We can do that already with the
julia> my_list = [1,2,3,4];
julia> if (local m = length(my_list)) > 3
ERROR: UndefVarError: m not defined
Those are mostly implementation details (iteration itself isn’t parallizable either, without change in semantics) but I do agree that it is somewhat useful in comprehension. Comprehension/generator is already a compact syntax so it should be OK to introduce something along the same style to allow the condition and the return value to share a state. However, for all the normal code blocks, having a normal
let would still be better.
I think it’s nice to come up with the surface syntax that is easily handled by the compiler.
It is actually very useful to consider that the iterator comprehension is defining iterator transformation rather than the iterator itself. It makes parallel algorithms work naturally with the collections created by the iterator comprehensions, e.g., using the conversion of the iterator transformations to transducers (Transducer as an optimization: map, filter and flatten by tkf · Pull Request #33526 · JuliaLang/julia · GitHub). But yes, it’s in a way a change in semantics.
Ooops… I made a mistake.
Somehow I was led to believe that it would introduce a local scope from reading a random blog post but I just checked with a real example and that’s not true. So, it seems that this operator is merely used for making code a little shorter. Sorry about the confusion