Julia: keytype/valtype not defined for Pair{K, V}

Created on 8 Aug 2020  路  11Comments  路  Source: JuliaLang/julia

julia> D = Dict{Int32, Float32}
Dict{Int32,Float32}

julia> keytype(D)
Int32

julia> valtype(D)
Float32

julia> P = Pair{Int32, Float32}
Pair{Int32,Float32}

julia> keytype(P)
ERROR: MethodError: no method matching keytype(::Type{Pair{Int32,Float32}})
Closest candidates are:
  keytype(::AbstractArray) at abstractarray.jl:124
  keytype(::Type{Arrow.Map{K,V,A,B}}) where {K, V, A, B} at /Users/jacobquinn/.julia/dev/Arrow/src/arraytypes.jl:110
  keytype(::Type{var"#s91"} where var"#s91"<:(AbstractArray{T,1} where T)) at abstractarray.jl:127
  ...
Stacktrace:
 [1] top-level scope at REPL[83]:1

julia> valtype(P)
ERROR: MethodError: no method matching valtype(::Type{Pair{Int32,Float32}})
Closest candidates are:
  valtype(::AbstractArray) at abstractarray.jl:129
  valtype(::Type{Arrow.Map{K,V,A,B}}) where {K, V, A, B} at /Users/jacobquinn/.julia/dev/Arrow/src/arraytypes.jl:111
  valtype(::Type{var"#s91"} where var"#s91"<:AbstractArray) at abstractarray.jl:147
  ...
Stacktrace:
 [1] top-level scope at REPL[84]:1

Would be a good intro issue if someone wants to take a stab at it.

breaking

Most helpful comment

We may have whiffed a bit here since having a Pair type is an opportunity to make a really lightweight single-pair dict-like object, whereas treating a pair as a two-element collection is relatively less useful, especially since we already have tuples for this. Marking as 2.0 to consider changing this.

All 11 comments

The intended behavior being keytype(P)= = Int32 and valtype(P) == Float32?

I will try to make a PR for this tonight or tomorrow.

Are the keys not the things one can index with and the values you get by indexing with the keys? How does this fit here?

I see that it would be good to have functions to get those types, but I don't understand how this proposal fits into the concept of keys and values.

Yeah, wouldn't the keytype always be Int? Because you index into a pair foo with foo[1] and foo[2]?

So even if you have Pair{String, Float32}, the keytype would still be Int. And the valtype would be Union{String, Float32}.

Oh dear, yeah, I guess it isn't as straightforward as I thought. What I was originally posting/wanting is a way to get the K and V from Pair{K, V}, which led me to keytype and valtype. In my mind, that was because a Pair is like a 1-element Dict, but I didn't think about how it's indexing behavior was so different. @andyferris, any thoughts here?

We may have whiffed a bit here since having a Pair type is an opportunity to make a really lightweight single-pair dict-like object, whereas treating a pair as a two-element collection is relatively less useful, especially since we already have tuples for this. Marking as 2.0 to consider changing this.

Hmm yeah that鈥檚 interesting, I never considered that option @StefanKarpinski.

I know I _do_ like to destructure pairs like for (k,v) in dict so how might we handle that case? (I always wondered why we don鈥檛 support for k=>v in dict so maybe there鈥檚 a bit of syntactic space to play in).

I'm not as big a fan of for (k,v) in dict. I'd prefer for v in dict and for (k,v) in pairs(dict).

My guess is that people will disagree whether a dict should iterate values or key-value pairs.

That's why I always use for k in keys(dict) or for v in values(dict) or for (k, v) in pairs(dict).

So personally if it were up to me, I would actually make iteration over dicts undefined, and make people use keys(dict) or values(dict) or pairs(dict).

But that's just my personal opinion, and I don't think it is relevant to what the language should implement. I don't feel strongly; I'll support whatever the consensus is.

In any of the possible cases I think it would be useful if something equivalent to for (k, v) in pairs(dict) worked even if we implemented @StefanKarpinski's idea.

Personally, I feel it would be a shame not implementing iteration for dictionaries - there's so much useful stuff you can do via iteration-based APIs. The added boilerplate of wrapping each dictionary in a values or pairs every time is a pain, however, and things that are less convenient simply get used less. I favor iterating values mostly because it matches the array interface and minimizes congnitive overhead in reading and understanding code (which for me at least frequently involves both arrays and dictionaries), and I find that it's the more common access pattern for me whenever doing "data science" oriented work (especially when using Dictionaries.jl where I have access to map, broadcast, reduce, filter, etc - but I'm biased :slightly_smiling_face:).

If I can try to summarize, a conflict arises with the three-way desire of

  1. Have Pair behave like anAbstractDict with one pair. keytype(::Pair) and valuetype(::Pair) of Julia 2.0 would be typeof(first(::Pair)) and typeof(last(::Pair)) of Julia 1.0.
  2. Have destructuring work as in for (k, v) in pairs(dict)
  3. iterating an AbstractDict is defined for dicts with more than one pair (regardless of whether it's defined to iterate keys, values, or pairs)

Is that right?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tkoolen picture tkoolen  路  3Comments

TotalVerb picture TotalVerb  路  3Comments

ararslan picture ararslan  路  3Comments

felixrehren picture felixrehren  路  3Comments

i-apellaniz picture i-apellaniz  路  3Comments