Pair iteration specification

What is going on here? Why is this not allowed, and given that it is not allowed, why is there not an error?

julia> a,b = 1,2
(1, 2)

julia> [a+b for (a=>b) in [3=>4, 5=>6]]
2-element Vector{Int64}:
 3
 3

Invalid unpacking syntax:

julia> (a, b) = 3 => 4
3 => 4

julia> (a => b) = 3 => 4
Error showing value of type UnionAll:
ERROR:
SYSTEM (REPL): showing an error caused an error
ERROR:
SYSTEM (REPL): caught exception of type StackOverflowError while trying to handle a nested exception; giving up

edit: that two-line demo is a remarkably innocuous-looking way to create an irrecoverable, unkillable state.

Try

julia> [a+b for (a, b) in [3=>4, 5=>6]]
2-element Vector{Int64}:
  7
 11
1 Like

Thanks! I realize now that my initial question was a bit lacking. I’ve edited it to be more specific.

where did you see this? Julia is not Haskell/Clojure (I don’t know what language has this pattern matching just guessing here). This is simply not a thing in Julia

If it’s invalid syntax or simply not a thing I’d like to get ERROR: syntax: invalid iteration specification. Similarly, does [8 for f(x) in 1:3] have any sensical meaning? It evaluates without error to [8,8,8], but [8 for f(5) in 1:3] gives an ERROR: syntax: "5" is not a valid function argument name.

I feel like your demo is getting at a deeper issue.

               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _' |  |
  | | |_| | | | (_| |  |  Version 1.7.0 (2021-11-30)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> a => b = error("Hi!") # Let's define a new function
=> (generic function with 1 method) # Only 1 method

julia> 1 => 2 # Oh look, the new method throws an error :)
ERROR: Hi!
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] =>(a::Int64, b::Int64)
   @ Main ./REPL[1]:1
 [3] top-level scope
   @ REPL[2]:1

julia> 1+1 # At least this still works
2

julia> Pair(1, 2) # Wow, Julia internals don't break when I define a new function Main.=>
1 => 2

julia> 

whereas

               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _' |  |
  | | |_| | | | (_| |  |  Version 1.7.0 (2021-11-30)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> 3 => 4 # This line is the only difference between this example and the last. It should have no side effects but...
3 => 4

julia> a => b = error("Hi!") # We try to define a new function but...
Error showing value of type UnionAll:
ERROR: 
SYSTEM (REPL): showing an error caused an error
ERROR: 
SYSTEM (REPL): caught exception of type ErrorException while trying to handle a nested exception; giving up

julia> 1+1 # Wow, this is bad...
β”Œ Error: Error in the keymap
β”‚   exception =
β”‚    Hi!
β”‚    Stacktrace:
β”‚      [1] error(s::String)
β”‚        @ Base ./error.jl:33
β”‚      [2] Pair(a::Int64, b::Int64)
β”‚        @ Main ./REPL[2]:1
β”‚      [3] _region(s::Union{REPL.LineEdit.MIState, REPL.LineEdit.ModeState, IOBuffer})
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:131
β”‚      [4] region(s::Union{REPL.LineEdit.MIState, REPL.LineEdit.ModeState, IOBuffer})
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:132
β”‚      [5] refresh_multi_line(termbuf::REPL.Terminals.TerminalBuffer, terminal::REPL.Terminals.UnixTerminal, buf::IOBuffer, state::REPL.LineEdit.InputAreaState, prompt::Any; indent::Int64, region_active::Bool)
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:430
β”‚      [6] refresh_multi_line(termbuf::REPL.Terminals.TerminalBuffer, terminal::REPL.Terminals.UnixTerminal, s::Union{REPL.LineEdit.PrefixSearchState, REPL.LineEdit.PromptState}; beeping::Bool)
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:1840
β”‚      [7] refresh_multi_line(termbuf::REPL.Terminals.TerminalBuffer, terminal::REPL.Terminals.UnixTerminal, s::Union{REPL.LineEdit.PrefixSearchState, REPL.LineEdit.PromptState})
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:1839
β”‚      [8] refresh_multi_line(terminal::REPL.Terminals.UnixTerminal, args::Any; kwargs::Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}})
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:533
β”‚      [9] refresh_multi_line(terminal::REPL.Terminals.UnixTerminal, args::Any)
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:531
β”‚     [10] refresh_multi_line(s::REPL.LineEdit.PromptState; kw::Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}})
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:412
β”‚     [11] refresh_multi_line(s::REPL.LineEdit.PromptState)
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:408
β”‚     [12] refresh_multi_line(::REPL.LineEdit.MIState)
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:227
β”‚     [13] refresh_line(s::Union{REPL.LineEdit.MIState, REPL.LineEdit.ModeState, IOBuffer})
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:1327
β”‚     [14] commit_line(s::REPL.LineEdit.MIState)
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:2131
β”‚     [15] (::REPL.LineEdit.var"#113#166")(::REPL.LineEdit.MIState, ::Any, ::Vararg{Any})
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:2215
β”‚     [16] #invokelatest#2
β”‚        @ ./essentials.jl:716 [inlined]
β”‚     [17] invokelatest
β”‚        @ ./essentials.jl:714 [inlined]
β”‚     [18] (::REPL.LineEdit.var"#25#26"{REPL.LineEdit.var"#113#166", String})(s::Any, p::Any)
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:1466
β”‚     [19] prompt!(term::REPL.Terminals.TextTerminal, prompt::REPL.LineEdit.ModalInterface, s::REPL.LineEdit.MIState)
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:2586
β”‚     [20] run_interface(terminal::REPL.Terminals.TextTerminal, m::REPL.LineEdit.ModalInterface, s::REPL.LineEdit.MIState)
β”‚        @ REPL.LineEdit /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:2488
β”‚     [21] run_frontend(repl::REPL.LineEditREPL, backend::REPL.REPLBackendRef)
β”‚        @ REPL /Applications/Julia-1.7.0.app/Contents/Resources/julia/share/julia/stdlib/v1.7/REPL/src/REPL.jl:1230
β”‚     [22] (::REPL.var"#49#54"{REPL.LineEditREPL, REPL.REPLBackendRef})()
β”‚        @ REPL ./task.jl:423
β”” @ REPL.LineEdit /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:2588
julia> 

SYSTEM: caught exception of type :ErrorException while trying to print a failed Task notice; giving up
ERROR: fatal: error thrown and no exception handler available.
ErrorException("Hi!")
error at ./error.jl:33
Pair at ./REPL[2]:1
display_error at ./client.jl:104
unknown function (ip: 0x1297f9448)
jl_apply_generic at /Applications/Julia-1.7.0.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.7.dylib (unknown line)
display_error at ./client.jl:107
unknown function (ip: 0x1297f9044)
jl_apply_generic at /Applications/Julia-1.7.0.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.7.dylib (unknown line)
jl_f__call_latest at /Applications/Julia-1.7.0.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.7.dylib (unknown line)
#invokelatest#2 at ./essentials.jl:716 [inlined]
invokelatest at ./essentials.jl:714 [inlined]
_start at ./client.jl:497
jfptr__start_28060.clone_1 at /Applications/Julia-1.7.0.app/Contents/Resources/julia/lib/julia/sys.dylib (unknown line)
jl_apply_generic at /Applications/Julia-1.7.0.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.7.dylib (unknown line)
true_main at /Applications/Julia-1.7.0.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.7.dylib (unknown line)
jl_repl_entrypoint at /Applications/Julia-1.7.0.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.7.dylib (unknown line)

This is either a Julia bug or extremely counterintuitive behavior.

Please file an issue - we should throw sensible errors instead of leaving users in the dark. See:

julia> 3 + 4
7

julia> a + b = error("Hi!")
ERROR: error in method definition: function Base.+ must be explicitly imported to be extended
Stacktrace:
 [1] top-level scope
   @ none:0
 [2] top-level scope
   @ REPL[5]:1

Right! Thanks. This is exactly the warning/error we should have. That (and its presumable fix in Julia) settles your unfortunate demo.

We still have the original questions, though.

Try this in a fresh Julia session:

julia> a + b = error("Hi!")
+ (generic function with 1 method)

In your case it fails only because you previously used + from Base in the same session. That’s how it works for all functions, to enable backward compatibility: if the user defines a function and a later version of Julia defines the same function in Base, the user code continues to work.

2 Likes

The error @stillyslalom produces with + is great. We don’t want to accidentally pirate functions from other modules. The bug is that the error is lacking for constructors (e.g. =>) so we end up accidentally redefining Base.=> which breaks the REPL.

3 Likes