-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
keys(g::Generator) = keys(g.iter)
is not generically correct and should not be defined
#58341
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
Comments
The method was added here, and approved by triage multiple times it seems: #34678 |
how unfortunate. well, it's not documented behavior so it's not too late to revert. note that the triage approval summary contained the language but it is harmful, as it makes some basic functions in |
Since isequal(collect(values(A)), [A[k] for k in keys(A)]) and So I'd favor an error over the |
I think it would be good to get this done because it's a correctness hazard. Is this ready for triage? |
as @nsajko noted, this behavior was already considered and approved by triage in #34678. I don't have a productive solution that wouldn't be very breaking, so I'm not sure what there is for triage to discuss. I should probably just close this as won't fix although, I will also note that the
... so which is it? |
I'm still trying to figure out what exactly makes this wrong. Because it's definitely right in other cases. Most notably, we need generators to expose their iteration space's axes in order to julia> g = (i*j for i in 1:3, j in 1:4)
Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}, var"#5#6"}(var"#5#6"(), Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}((1:3, 1:4)))
julia> Base.IteratorSize(g)
Base.HasShape{2}()
julia> axes(g)
(Base.OneTo(3), Base.OneTo(4)) That's not only correct, but it's precisely what's needed in order to I think this is the same fundamental problem as julia> d = Dict(:a=>1, :b=>-1);
julia> findmax(d) # indexing-based
(1, :a)
julia> findmax(kv for kv in d) # iteration based
(:b => -1, :b)
julia> findmax(v for (k,v) in d) # FTFY!
(1, :a) Is the second one there actually wrong? The key-value pair |
I actually mostly agree with you that this is p r o b a b l y closer to "footgun caused by the intersection of vague interfaces" than it is to "correctness bug" but consider
why is this allowed? namely: that
but this is not guaranteed generically here! imagine I make a dictionary type
then (never mind the fact that |
But isn't this all just doing the right thing? The generator is exposing the iteration space of a collection over a set of its keys — we can literally write
You lost the styling from the docstring there, but perhaps that's even better because it makes it clear where the ambiguity lies. Is it the English "iterate" or the Julia function Make a data structure that breaks that requirement, and generators will happily forward along that brokenness. Perhaps the hardest part here is knowing when some |
I'd like to repeat my previous example with some code --- not because I don't think you understood it, but just so I can see very specifically where our disagreement begins.
this produces
I am currently inferring from your response that you would describe this as a broken data structure, and not meeting the contract of one or both of also note of course that it is not the case that |
I might be way behind here, but I'd like to try articulating my own view. Imho the gospel should be that
To demonstrate, take the case of julia> g = (x for x in Dict(:a => 10))
Base.Generator{Dict{Symbol, Int64}, typeof(identity)}(identity, Dict(:a => 10)) If julia> keys(g)
KeySet for a Dict{Symbol, Int64} with 1 entry. Keys:
:a If
and julia> findmax(identity, g)
(:a => 10, :a) where I think therefore that defining |
Yeah, that's precisely it. I also wasn't as certain — my response wasn't so much "you broke it, RTFM", but rather, realizing that the end effect of It's a rather interesting end effect. I don't think there are other places where we assume/require this — at least not so strongly. I'm not nearly as concerned that generators don't immediately expose an indexable interface but still have |
So there are two problems here. One is the fact that dicts generate different elements upon iteration than indexing. That's a problem, but that ain't going away til 2.0, surely (cf. #24019). So given that we live in a world where iterating and indexing can give you different things, can you know what a function will do? If a docstring says it does something to the "elements" of a collection, is that iteratively or indexingly? Concretely, if I have a
I cannot imagine anyone getting 6/6 correct there (but there's definitely a bug, so perhaps that's unfair). |
Obviously no obligation to answer these but I'm left wondering
|
sounds fun. I'll try to answer these based on my understanding of what Coherent Julia As Intended™️ is currently (rather than whatever I might think it "should" be)
Based only on the most common empirical design pattern I tend to see in Julia, "indexingly" seems to most commonly take precedence over "iteratively," where shape or structure or keys etc. etc. are used when able and treating something as a generic iterator occurs only as a fallback. To separate the terms a bit, I'll use
let's see the results! .... oh come on this is definitely a bug 😭
|
from the
keys
docstring:but a
Generator
does not have keys and values. it only has values. there is noget(::Generator, ...)
norgetindex(::Generator, ...)
I believe a similar problem holds for
axes(g::Generator)
andndims(g::Generator)
, but I'm focusing onkeys
since it seems the most flagrant.this leads to awful behavior with things like
where the second call should either error, or maybe a
Generator
could 1-index as if it were anenumerate
so that would becomenote that
so even the
state
initerate
is 1-indexed and not taking fromkeys(g.iter)
I think technically this is a duplicate of #48379, but I don't think the fundamental problem there has anything to do with
skipmissing
so I just made a new issue.The text was updated successfully, but these errors were encountered: