In general the Julia parser tries not to steal identifiers as keywords so there’s several words (abstract, as, doc, mutable, outer, primitive, type, var, isa, where) which are normally identifiers but have special parsing rules in some circumstances.
There’s two circumstance (quoting with : and field access with .) where words which are normally keywords become identifiers:
x.end = :for
A downside of this is that a syntax highlighter would need to be a full parser to get the highlighting 100% correct.
Yeah the rules are (mostly?) local enough that syntax highlighting should be able to get them right though it’ll need some lookahead / lookbehind for things like outer which are somewhat more annoying. outer is a keyword here: for outer i = 1:10 and here for outer i (in) 1:10 but not here: for outer = 1:10 or here for outer in 1:10.
Speaking of outer… here’s a puzzle I’ve concocted using some other tricks up-thread, and another fairly serious WAT I recently discovered.
Does anything get printed here?
let isa = isa isa where where where
outer = false
for outer outer in isa
end
try
if outer isa Any
@info "Certainly true, right?"
end
finally
outer = false
catch
if outer
@info "Surprise?"
end
end
end
(Edit: I think it’s fair to say this isn’t exactly a WAT in itself, as it’s intentionally obtuse )
println("What a lovely day!")
for i in 1 : 100_000_000
for j in 1 : 10_000
x = cos(j)
end
end
# Next day...
println("WAT!")); # Syntax error discovered
The default behavior of == when comparing structs has always been a bit of a WAT to me.
julia> struct A
x::Vector{Int}
end
julia> A([1, 2]) == A([1, 2])
false
julia> mutable struct B
x::Int
end
julia> B(1) == B(1)
false
In my opinion, the default behavior should be to compare the values of the contents of the structs, regardless of whether the structs or the contents of the structs are mutable.
This is not so much of a WAT for everyone, but… WAT!!!
julia> macro weird(a::Int)
@show a, typeof(a)
1
end
@weird (macro with 1 methods)
julia> macro weird(a::Float64)
@show a, typeof(a)
2a
end
@weird (macro with 2 methods)
julia> macro weird(a::String)
@show a, typeof(a)
a^3
end
@weird (macro with 3 methods)
julia> macro weird(a::Symbol)
@show a, typeof(a)
:($(a)^4)
end
@weird (macro with 4 methods)
julia> macro weird(a::Expr)
@show a, typeof(a)
a
end
@weird (macro with 5 methods)
julia> @weird 10
(a, typeof(a)) = (10, Int64)
1
julia> @weird 1.0
(a, typeof(a)) = (1.0, Float64)
2.0
julia> @weird "Hi"
(a, typeof(a)) = ("Hi", String)
"HiHiHi"
julia> @weird im
(a, typeof(a)) = (:im, Symbol)
1 + 0im
julia> @weird "Hi" ^ 3
(a, typeof(a)) = (:("Hi" ^ 3), Expr)
"HiHiHi"
I would imagine that macro calling logic would consider all arguments as “typeless”, but that doesn’t seem to be the case.
(Without knowing the specifics, I guess that macros are “just” functions underneath that have a special syntax and run on a different moment under the Julia parsing-lowering-compilation-execution pipeline. i.e., just after the parsing and before the lowering).