Same for me, but my brain wasn’t so fond about the same thing happening to Float32
s:
julia> f = 10
10
julia> 2f + 1
21
julia> 2*f+1
21
julia> 2f+1
20.0f0
julia> 2f+1f # (2f+1)*f
200.0f0
Same for me, but my brain wasn’t so fond about the same thing happening to Float32
s:
julia> f = 10
10
julia> 2f + 1
21
julia> 2*f+1
21
julia> 2f+1
20.0f0
julia> 2f+1f # (2f+1)*f
200.0f0
This was definitely wat for me, and is arguably a bug:
julia> 0.0 in Set([-0.0])
false
julia> 0.0 in collect(Set([-0.0]))
true
And on the flip side:
julia> NaN in Set([NaN])
true
julia> NaN in [NaN]
false
Edit: I didn’t read the docs for in
closely enough: It’s not a bug, but it definitely is wat
(Edit: this is incorrect)0.0 in Set([-0.0])
is definitely a bug in the implementation (or the documentation) as Collections and Data Structures · The Julia Language says “For example, Sets check whether the item isequal to one of the elements.”
By the way, the specification of Base.in
is clearly qualified as a WAT: Base.in
may follow ==
or isequal
semantics depending on the argument types.
This is documented the way it works, as the documentation states:
Some collections follow a slightly different definition. For example,
Set
s check whether the itemisequal
to one of the elements.
and
julia> 0.0 == -0.0
true
julia> isequal(0.0, -0.0)
false
but
By the way, the specification of
Base.in
is clearly qualified as a WAT
Fully agreed
To go with your other example of lowering iteration specifications… Here’s the weirdest way I know to define a closure:
julia> for wat() in 1:3
println(wat())
end
1
2
3
Thanks, I did check it, and it is definitely in the REPL history. I have no idea why I interpreted it backward.
Who knew we had infix macros?
julia> macro +(a,b)
QuoteNode((a,b))
end
@+ (macro with 1 method)
julia> @(x + y*2)
(:x, :(y * 2))
(Please don’t use this! I hesitate to even mention it and I think it should get removed soon.)
@miguelraz the categorization of the countlines()
example in your Julia WATs seems wrong to me. I’d class it as “paths are hard”, perhaps. See also
Using isequal
is the only reasonable behavior, using ==
is quite broken.
Wow, this is wild.
Lowering is hard, credit to
Jonnie Diegelman
:julia> nums = zeros(Int, 10); julia> for nums[rand(1:10)] in 1:20 end julia> nums 10-element Vector{Int64}: 12 16 7 20 19 18 15 0 13 17
(Python suffers from something similar). Explanation: As
Jabon Nissen
pointed out, “It’s because for i in 1:20 lowers to for i = 1:20 in Julia. Here, it’s nums[rand(1:10)] = 1:20”
I do find this behavior very surprising, but I don’t think it has anything to do with lowering. It’s equally surprising to me with =
as with in
(after all, nums[rand(1:10)] = 1:20
is not a valid assignment anyway).
Maybe an example like this helps explain what is going on:
julia> x = [0,0]
2-element Vector{Int64}:
0
0
julia> for x[1] in 1:2; println(x); end
[1, 0]
[2, 0]
or the example by Chris_Foster above?
I wonder if this was deliberately implemented or is just a bug, since it doesn’t seem to be mentioned in the docs (Control Flow · The Julia Language). In fact, the docs seem to imply that the for
line always defines new variables. Also, it doesn’t work with let
:
julia> let x[1] = 1; end
ERROR: syntax: invalid let syntax around REPL[28]:1
In fact, the docs seem to imply that the for line always defines new variables.
The linked documentation seems very clear to me:
Maybe the term variable is inaccurate, as the for
loop clearly lowers the code in a way that setindex
is called, but I either expected this to be an error or to work the way it works (i.e. working like x[1] = iteration_value
was called at the start of the loop each iteration).
A lot of this is just people omitting spaces where they really should not omit spaces. Use a linter or a coding style or something…
It’s equivalent to writing
f(x) = x
+ 1
and then wondering why f(1) == 1
.
A good source of wats is the where
keyword:
julia> isa isa where where where
true
It’s very clear only about the little it says, which is only about variables. And to me, the fact that it consistently says “variable” and not “expression” suggests that it only works for variables. And the part about scope seems to say that the variables to the left of the =
or in
are new variables (although technically the paragraph only covers the case where there is no existing variable of the same name in the enclosing). So I would not expect to be able to refer to existing variables at all in this context. The docs about scope also seems consistent with that.
The fact that for x = 1:3
introduces a new x
, while for x[1] = 1:3
refers to x
from an outer scope seems pretty odd to me. (The closure example for g() = 1:3
makes a lot more sense, but is pretty useless.)
A lot of this is ambiguities arising from allowing 2f
to mean 2*f
. The spaces required for disambiguation are unnecessary in many other languages.
From my perspective that explains how folks develop this bad habit—it does not justify it.
Different people, different interpretations.
The for loop iterates through these values, assigning each one in turn to the variable i.
The first phrase talks about assigning to i
even before the text says that for
specifically can implicitly introduce new variables, consequently it can only be talking about a variable i
that already exists.
One rather important distinction between the previous while loop form and the for loop form is the scope during which the variable is visible. If the variable i has not been introduced in another scope, in the for loop form, it is visible only inside of the for loop, and not outside/afterwards.
The rest of the paragraph talks about the exception in behavior of the for
loop, in the specific case the variable was not introduced before, consequently it leaves implicit the previously stated behavior is expected outside this specific case; otherwise it should mention that, differently from the while
loop, the variable used to control the loop cannot be declared before it.
But yes, instead of variable, the text should probably say assignment location (or assignable location), which is an expression used in some Julia error messages.
julia> a = [1]
1-element Array{Int64,1}:
1
julia> true && a[1] = 2
ERROR: syntax: invalid assignment location "true && a[1]" around REPL[2]:1
Stacktrace:
[1] top-level scope at REPL[2]:1
I can see how this is a possible interpretation, but under that interpretation the docs are just wrong, rather than simply misleading. for x in ..
introduces a new x
regardless of whether x
is already defined:
julia> x = 2
2
julia> for x = 1:5
end
julia> x
2