Dictionaries with strings as keys and any values - dictionary

I am trying to define a dictionary that takes strings as keys and any values. Thus, I try to use Dict{String, <:Any} as type. However, the return value to that expression is
> Dict{String,#s27} where #s27
Moreover, if I try to define a dictionary of that type I get an error:
For Dict{String,<:Any}() I get ERROR: MethodError: no method matching Dict{String,#s28} where #s28()
For Dict{String,<:Any}("aa"=>42) I get ERROR: MethodError: no method matching Dict{String,#s29} where #s29(::Pair{String,Int64})
I also tried using Dict{String} (which should be equivalent), with similar results.
What am I missing about types of dictionaries here?

What you are looking for is a Dict{String, Any}, not Dict{String, <:Any}. The first one is a concrete type, namely a dict that takes strings as keys and anything as values. The second, Dict{String, <:Any} is not actually a concrete type, but a unionall type. That means it is an infinite set of types. And the error you are seeing is that you can't instantiate this set of types. You can only instantiate a concrete (leaf) type.
Another way of writing Dict{String, <:Any} is Dict{String, T} where T <: Any, and that makes it a little clearer what it is. It is the set of all types of Dict that has String as they key type and a type that is a subtype of Any as their value type.
So for example we can say that Dict{String, Int} is a subtype of the infinite set Dict{String, <:Any}.
Edit: One use of unionall types is to be able to restrict the kind of type you take to fine grained level. For example, a counting function may look like this:
function count_stuff(stuff, counter::Dict{T, <:Integer}) where T
# stuff here¨
end
The second argument here is a Dict that has some subtype of Integer as a value type and any type as a key type. That's basically what you'd need to use the dict as a counter.

Related

create a structure containing an array

I want to create a structure in Julia which contains two floating point variables (coorx, velx) and one vector array of two elements which contains gradients with two elements, my idea is as follows:
struct part_struct
coorx::Float64
velx::Float64
gradx::Vector{Float64}(undef,2)
end
However, when I try to create an array of 10 of such structures:
num = 10
part = Array{part_struct,1}(undef, num)
I get the error:
TypeError: in part_struct, in type definition, expected Type, got a value of type Array{Float64,1}
How could I create such a structure in Julia?
you should put the type of the array in the struct, like that:
struct PartStruct
coorx::Float64
velx::Float64
gradx::Vector{Float64}
end
Note that you can't restrict the size of a Vector in a struct. To do so, you can use a Tuple instead (it should also have better performance):
struct PartStruct
coorx::Float64
velx::Float64
gradx::NTuple{2, Float64} # (equivalent to Tuple{Float64, Float64})
end
This is an immutable struct, which might not be what you want

How do I specify that I am returning a vector of 4 Int32 in a function?

If I want to specify that my function returns a Bool I do:
function myfunc(a,b)::Bool
What if I want to specify that I will return a vector of 4 Int32 elements?
a = Vector{Int32}(undef, 4)
You can't, and you don't have to.
The return type annotation is to declare the return type.
The length of a Vector is not part of its type.
it is part of its value, and it can change. (e.g. push! can be called on it).
Notice:
julia> typeof([1,2,3,4])
Array{Int64,1}
(Vector{T} is just a constant for Array{T,1})
So all you would do is delcare the type:
function myfunc(a,b)::Vector{Int}
Alternatively, you might want a NTuple{Int,4} i.e. a Tuple{Int, Int, Int, Int},
or a SVector{Int,4} from StaticArrays.jl
In general return type annotation is not super useful.
It basically boils down to the code automatically calling convert{RETURNTYPE, raw_return_value), which may error.
This can be helpful on occation for making your code type-stable, if you lose track of what types different are being returned from different return points (if you have multiple).
Rarely it might help the compiler type-infer. (Since convert always returns the indictated target type).
Some argue this serves a documentation purpose also.

fieldnames(x::DataType) does not work in Julia 1.0.1

I have a composite type, MyType,
struct MyType
a::Float64
b::Float64
end
When I do
a = MyType(1,2)
fieldnames(a)
I get an error
MethodError: no method matching fieldnames(::MyType)
When I do
fieldnames(MyType)
it returns
(:a,:b)
as expected. It was my understanding that the former should work as well - am I doing something wrong?
fieldnames was changed with Julia 1.0 to accept only types as its argument. The NEWS.md for 0.7 (which was the 1.0-gateway version) mentions that:
fieldnames now operates only on types. To get the names of fields in an object, use fieldnames(typeof(x))
The reasoning is essentially two-fold: (1) if it accepts both objects and types, there's an ambiguity since types are also objects themselves (so there's an artificial distinction in the old behaviour) (2) the fields are semantically an attribute of the type, not of its individual instances, so it makes more sense to have fieldnames operate on types only.

Subtype with different parameter than supertype

Let's say I have defined a Type merely as a alias for a certain array in Julia but with additional information, let's say just a string
abstract A{T,N}
foo::AbstractArray{T,N}
bar::Real
end
I would like to define a Subtype having maybe another element but also restricting the second parameter of the type to be an integer and having a value of N+1 if B is of type N.
type B{N::Int} <: A{T,N+1}
baz::Float64
end
In this example neither ::Int nor N+1 seem to be right nor are they syntactically. I'm a little new to Julia but I read a lot the last days and couldn't find a solution for that.
How can I do such a “restricted” subtype?
Edit: Maybe there's even another glitch. For the supertype N should be able to be a vector specifying the size of foo while for the subtype it should be an integer specifying the length of the vector.
Edit 2: I meant to use an abstract A which I edited now as mentioned in the comments
Edit 3: So I think one problem seems to be, that abstract types can not have fields (which I don't understand why but anyhow), then still I can't declare Type parameters to be e.g. just an Integer.
So how can I do something like
abstract A{T,N}
type B{N::Integer} <: A{Float64,N+1}
v:FixedVector{N+1,Float64}
end
I always get the problem, that N always (no matter what I do) stays a Typevar while I would like to just have an Integer. So is there a way to make a type dependent on a variable?

Can I use a subtype of a function parameter in the function definition?

I would like to use a subtype of a function parameter in my function definition. Is this possible? For example, I would like to write something like:
g{T1, T2<:T1}(x::T1, y::T2) = x + y
So that g will be defined for any x::T1 and any y that is a subtype of T1. Obviously, if I knew, for example, that T1 would always be Number, then I could write g{T<:Number}(x::Number, y::T) = x + y and this would work fine. But this question is for cases where T1 is not known until run-time.
Read on if you're wondering why I would want to do this:
A full description of what I'm trying to do would be a bit cumbersome, but what follows is a simplified example.
I have a parameterised type, and a simple method defined over that type:
type MyVectorType{T}
x::Vector{T}
end
f1!{T}(m::MyVectorType{T}, xNew::T) = (m.x[1] = xNew)
I also have another type, with an abstract super-type defined as follows
abstract MyAbstract
type MyType <: MyAbstract ; end
I create an instance of MyVectorType with vector element type set to MyAbstract using:
m1 = MyVectorType(Array(MyAbstract, 1))
I now want to place an instance of MyType in MyVectorType. I can do this, since MyType <: MyAbstract. However, I can't do this with f1!, since the function definition means that xNew must be of type T, and T will be MyAbstract, not MyType.
The two solutions I can think of to this problem are:
f2!(m::MyVectorType, xNew) = (m.x[1] = xNew)
f3!{T1, T2}(m::MyVectorType{T1}, xNew::T2) = T2 <: T1 ? (m.x[1] = xNew) : error("Oh dear!")
The first is essentially a duck-typing solution. The second performs the appropriate error check in the first step.
Which is preferred? Or is there a third, better solution I am not aware of?
The ability to define a function g{T, S<:T}(::Vector{T}, ::S) has been referred to as "triangular dispatch" as an analogy to diagonal dispatch: f{T}(::Vector{T}, ::T). (Imagine a table with a type hierarchy labelling the rows and columns, arranged such that the super types are to the top and left. The rows represent the element type of the first argument, and the columns the type of the second. Diagonal dispatch will only match the cells along the diagonal of the table, whereas triangular dispatch matches the diagonal and everything below it, forming a triangle.)
This simply isn't implemented yet. It's a complicated problem, especially once you start considering the scoping of T and S outside of function definitions and in the context of invariance. See issue #3766 and #6984 for more details.
So, practically, in this case, I think duck-typing is just fine. You're relying upon the implementation of myVectorType to do the error checking when it assigns its elements, which it should be doing in any case.
The solution in base julia for setting elements of an array is something like this:
f!{T}(A::Vector{T}, x::T) = (A[1] = x)
f!{T}(A::Vector{T}, x) = f!(A, convert(T, x))
Note that it doesn't worry about the type hierarchy or the subtype "triangle." It just tries to convert x to T… which is a no-op if x::S, S<:T. And convert will throw an error if it cannot do the conversion or doesn't know how.
UPDATE: This is now implemented on the latest development version (0.6-dev)! In this case I think I'd still recommend using convert like I originally answered, but you can now define restrictions within the static method parameters in a left-to-right manner.
julia> f!{T1, T2<:T1}(A::Vector{T1}, x::T2) = "success!"
julia> f!(Any[1,2,3], 4.)
"success!"
julia> f!(Integer[1,2,3], 4.)
ERROR: MethodError: no method matching f!(::Array{Integer,1}, ::Float64)
Closest candidates are:
f!{T1,T2<:T1}(::Array{T1,1}, ::T2<:T1) at REPL[1]:1
julia> f!([1.,2.,3.], 4.)
"success!"

Resources