Reputation: 433
(Using Julia 0.3.11)
I'm having trouble type-annotating correctly some of my code, in an initial version we've been using ASCIIString
- to annotate any String, to "avoid" abstract types, but let's start with the example, this might be related to what I've seen refereed to as "triangular dispatch" in some discussions here:
# How to type annotate this (sortof "Dictionary with default)
function pushval!(dict, key, val)
key in keys(dict) ? push!(dict[key], val) : dict[key] = [val]
return dict
end
d1 = Dict{ASCIIString, Vector{Int}}()
d2 = Dict{String, Vector{Int}}()
pushval!(d1, "a", 1)
pushval!(d2, "a", 1)
Ok (firstly - if there's a more idiomatic way to construct a dictionary with defaults, in this case an empty array, I'd love to hear about it)
So now, I've tried to type annotated it:
function pushval!{K, V} (dict::Dict{K, Vector{V}} , key, val)
Much more documenting, and works. But now comes the trickier part - I want 'key' to be any subtype of K, and val - any subtypes of V (right?) eg - I would like to make a dictionary of String - which is an abstract type, but use concrete keys - which are ASCIIString/ByteString/UTF8String,
I thought I should write one of the followings:
function pushval!{K, V} (dict::Dict{K, Vector{V}} , key::KK <: K, val:: VV <: V)
function pushval!{K, V, KK <: K, VV <: V} (dict::Dict{K, Vector{V}} , key::KK, val::VV)
One solution would be as suggest in ( Can I use a subtype of a function parameter in the function definition? ) something with 'convert'.
But this whole thing made me wonder about the Julia code I'm writing, I've started a write a system - using String, FloatingPoint, Number and such abstract types, when I actually tried running it, I've reverted to convert everything to concrete types just to get thing running for now...
Is there a recommended codebase to read as a reference to idiomatic Julia code? Like the very implementation of Julia's dictionary-assign operator even. Is there a part of the standard library considered good to start with as a reference? thanks
Upvotes: 2
Views: 306
Reputation: 2619
I know this is only partly what you asked for, but maybe you find it sufficient.
What you call pushval!
can be achieved using push!(get!(d1, "a", []), 1)
(although it will return the dictionary value that was appended to instead of the dictionary itself). If you need to constrain the type of the inner collection's values, you can, for example, use:
push!(get!(d1, "a", Number[]), 1)
If you really need to define this as a function, I am afraid that, at the moment, you cannot define the types in the way you describe. As the accepted answer to the question you referenced notes, Julia does not implement triangular dispatch yet, although it is targeted for 0.5.
Upvotes: 1
Reputation: 46
I could recommend looking at Julia Style Guide. There are some advices about using type annotations.
For your case you don't need type annotations for pushval!
function at all. Julia will get enough info from Dict
creation and deduce appropriate types for pushval!
arguments.
function pushval!(dict, key, val)
key in keys(dict) ? push!(dict[key], val) : dict[key] = [val]
return dict
end
d = Dict{String, Vector{Int} # Here is all annotations you need.
pushval!(d, "a", 1) # OK, "a" is ASCIIString which is subtype of AbstractString
pushval!(d, 1, 1) # ERROR, 1 is Int64 which is not subtype of AbstractString
Upvotes: 0
Reputation: 5746
Although I don't like this this solution very much (low performance), it can be helpful:
function pushval!{K, V} (dict::Dict{K, Vector{V}} , key , val)
fun = function inner{tt1<:K,tt2<:V}(key::tt1,val::tt2)
key in keys(dict) ? push!(dict[key], val) : dict[key] = [val]
return dict
end
return fun(key,val)
end
# => pushval! (generic function with 1 method)
d1 = Dict{ASCIIString, Vector{Int}}()
# => Dict{ASCIIString,Array{Int32,1}} with 0 entries
d2 = Dict{String, Vector{Int}}()
# => Dict{String,Array{Int32,1}} with 0 entries
pushval!(d1, "a", 1)
# => Dict{ASCIIString,Array{Int32,1}} with 1 entry:
# "a" => [1]
pushval!(d2, "a", 1)
# => Dict{String,Array{Int32,1}} with 1 entry:
# "a" => [1]
Upvotes: 2