-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dict construction calls generator side effects twice on failure #33147
Comments
This seems to be an unintended consequence of the error handling introduced in #12453: namely that if the generator has side effects, those side effects occur twice (once in the initial construction, and once in the check |
Also, thanks for the bug report! |
Maybe just drop that code now for #12451? I think our default error reporting now may provide enough context from showing the argument types and bounds error information that this won't be needed anymore. |
I tried that out, but the resulting errors were a lot less obvious. Maybe a heuristic like
would serve fine — we don't need to be precise here, only offer a more helpful error "when possible" |
On Julia 1.6 the "caused by" statement appears on the same line as the redundant error message resulting in this misleading statement:
Edit: This was just an error formatting change which I was unfamiliar with. I had only seen the |
I just ran into this issue; it confused me for a while, especially since side-effects of the generator were caused twice before the double error was printed. I am not sure what guarantees Julia normally makes regarding iteration restarts, but this behavior is especially confusing with once-iterables like channels: f(xs) = Channel() do c
push!.(Ref(c), xs)
end
Dict(x => @show log(x) for x in f([1, 2])) # ok
Dict(x => @show log(x) for x in f([1, -1, 2])) # DomainError with -1.0
Dict(x => @show log(x) for x in f([1, -1, 2, -2])) # DomainError with -2.0, caused by: DomainError with -1.0
Dict(x => @show log(x) for x in f([1, -1, 2, -2, 3])) # same, but 3 is left in channel The solution proposed in #40445 does not fix this. I think I would prefer the julia> Dict([[1, 2, 3]])
Alternatively, maybe the code that fails to index could wrap the Should I try a PR or am I missing something? |
Fixes: #33147 Replaces/Closes: #40445 Co-authored-by: Jameson Nash <[email protected]>
Fixes: #33147 Replaces/Closes: #40445 Co-authored-by: Jameson Nash <[email protected]>
Fixes: #33147 Replaces/Closes: #40445 The difference here, compared to past implementations, is that we use the zero-cost `isiterable` check on every intermediate step, instead of wrapping the call in a try/catch and then trying to re-approximate the `isiterable` afterwards. Some samples: ```julia julia> Dict(i for i in 1:3) ERROR: ArgumentError: AbstractDict(kv): kv needs to be an iterator of 2-tuples or pairs Stacktrace: [1] _throw_dict_kv_error() @ Base ./dict.jl:118 [2] grow_to! @ ./dict.jl:132 [inlined] [3] dict_with_eltype @ ./abstractdict.jl:592 [inlined] [4] Dict(kv::Base.Generator{UnitRange{Int64}, typeof(identity)}) @ Base ./dict.jl:120 [5] top-level scope @ REPL[1]:1 julia> Dict(i => error("$i") for i in 1:3) ERROR: 1 Stacktrace: [1] error(s::String) @ Base ./error.jl:35 [2] (::var"#3#4")(i::Int64) @ Main ./none:0 [3] iterate @ ./generator.jl:48 [inlined] [4] grow_to! @ ./dict.jl:124 [inlined] [5] dict_with_eltype @ ./abstractdict.jl:592 [inlined] [6] Dict(kv::Base.Generator{UnitRange{Int64}, var"#3#4"}) @ Base ./dict.jl:120 [7] top-level scope @ REPL[2]:1 ``` The other unrelated change here is that `dest = empty(dest, typeof(k), typeof(v))` is made conditional, so we do not unconditionally construct an empty Dict in order to discard it and allocate an exact duplicate of it, but only do so if inference wasn't precise originally. Co-authored-by: Curtis Vogt <[email protected]>
Greetings...
This is not a major issue, but potentially reflects some underlying bug and is certainly confusing: when creating a
Dict
with a generator expression and an exception occurs, for some reason the generator restarts until it hits the exception a second time. Once it hits the exception a second time, it stops, thankfully. For example (using@show
to track execution)Dict(x => sqrt(@show x) for x=[1,2,3,4,-5,6])
does everything (but the 6) twice. I would have expected it to immediately error out, but...In my case an exception occurred near the end of a calculation that should have taken 30 minutes. I started getting suspicious when it was still running after 40 minutes, even more so when I noticed it was re-doing parts of the job that should have been finished earlier. Granted I of course should have written code that didn't crash, but still. :)
Many thanks for a great programming environment...
Version info, if that helps. (The same issue also occurs on 1.3.0-rc1.0)
The text was updated successfully, but these errors were encountered: