My Brain Is Hard-Wired Against ==; Help Me, Julia

I am not supporting the OP’s suggestion. But its terrifying that this works in julia,

a = 0; b = true
if (a = b)
    println("a is equal to b")
end # Output: a is equal to b

But it might be hard to determine how much of an issue this is, practically.

1 Like

I was a bit surprised that worked, it’s less terrifying since without parentheses this is an error:

if a = b

so even if you grew up with them needed, as in C, I would stop using them, since they’re not needed and are harmful. This can’t be fixed it seems (or can it since always a bug [waiting to happen]?), as it would be a breaking change, but I highly recommend the linters should block it.

I’m not sure why it’s allowed (only for compatibility with C?), and what the meaning of this is, since it’s not a tuple as I thought, that would be:

julia> (a = b,)
(a = true,)

unlike:

julia> (a = b)
true
1 Like

In this case, true is assigned to the variable a. It seems the parenthesis trick julia to no see the assignment. (Indeed, we can call a function with side effects in a if statement, it is a bit similar here I think)

uhhhh… If you change the code to:

a = 1; b = true
if a == b
    println("a is equal to b")
end # Output: a is equal to b

then you have the same result. So I am not entirely sure what was your point. == is not strict about types and 1 and true are the same thing for it.

1 Like

Sorry bad example. Edited to fix it.

1 Like

After a bit of searching, I think that the (a=b) is a compound expression.
I did not find any documentation of how it should behave in a condition. I personally would expect the same behavior from a compound expression than from a regular expression. Surely, this would be a breaking change, but maybe it goes under undefined behavior (I’m not sure about this point).

I think it’s just an expression. I proposed disallowing it, but it was closed very quickly:

a=b is an assignment, and all expressions in Julia (as with some other languages) return a value, so here a (that’s same as b, just now). It’s only that without parentheses you don’t get access to it, the truth-value.

Most often you get away with this (while a runtime, rather than compile time, error):

julia> a=1;b=1;
julia> if (a=b)
        print("Equal")
       end
ERROR: TypeError: non-boolean (Int64) used in boolean context

it’s only a problem when b (or both) is a Boolean, mitigating the issue. I still think most often an error for any type combination, and would like to see a useful counterexample.

1 Like

Yes. Its probably not an issue in practice as b needs to be Boolean.

1 Like

Patterns like this are sometimes useful:

if (flag = test_that_should_only_be_done_once())
    start_something()
end
do_stuff()
if flag
   finish_something()
end
6 Likes

A typical use case is :

if (result = computation())
   # do something with result
end

Another use case example is given in the PEP report for the python walrus operator. It helps storing a computation needed for the condition to use it inside the if statement.

1 Like

That pattern is useful in Python and C, but in Julia, the only value that result can have inside that if block is true, so there’s no need to store it (unless it will also be used outside of the if-statement).

3 Likes

Don’t think this can be used generally as this would only work if computation() was a Boolean value. But the example @Per gave seems to be a valid use case.

Is this three-way pattern used enough, in Julia, to outweigh the danger of when = should be == ?

It seems to be the only counterexample (or possibly four-way+ patterns do also exist?). Could this pattern be named, and be in Base: some_name(condition(), start(), middle(), end()) and those functions could be anonymous, and possibly number 4+?

Just looking at one if individually, it can be:

flag = test_that_should_only_be_done_once()
if flag

and shorter (by number of letters) if flag is changed to f (while still more vertical space, and variable repeated), for two ifs, there’s redundancy anyway, and with the proposed named pattern the variable would never need to be named.

While loops are also another issue, can also be rewritten.

A mistaken = instead of == is only a problem if you ignore the advice in the manual that says “Don’t parenthesize conditions” and the right-hand side is a Bool, so it probably happens fairly rarely.

The advantage of putting the condition on the same line as the if keyword is readability.

Whether the tradeoff is worth it is entirely subjective, of course.

4 Likes

My main problem with disallowing assignment in an if-condition is inconsistency.

When looking at the code, and knowing about the behavior of assignment, I would reason that it ought to work, even if it’s not so useful. One would have to special-case this to disallow it, and that makes the language more inconsistent, strange and surprising.

5 Likes

Yes, I use this type of assignment all the type, mostly within while loops where I like to mutate the state:

i=0
while (i = i +1) <= length(lst)
    if dotest(lst[i]) pop!(lst, i) end
end

This isn’t the best example but with something like parsing tokens, you can easily have some forward-looking logic within that loop that also mutates your list. Sometimes you even want to mutate the list at a location <i then you just have to increase/decrease i if you removed or added an item.

1 Like

Heh, I hate ← in R, but I really like := in Pascal.

To each his own!

2 Likes

I wonder, couldn’t the compiler decide the context if we use = for assignments and bool comparisons? One might think that a multiple dispatch language should be the right place for this.

Some languages do that – the interpretation of = depends on context.

But how would the compiler know whether the user deliberately used assignment, or intended to use comparison, but misspelled it?

Multiple dispatch has to do with the types used, not with the context.

Imho, this would make the language more inconsistent and unpredictable. Trying to get Julia to interpret intent, turning it into a ‘do what I mean language’ would not be a good thing. Especially in cases like these, where it is actually fundamentally impossible to know the intent.

2 Likes