In Julia 0.4.0, when I try
rand(AbstractFloat, 1)
The following error is obtained:
ERROR: MethodError: `rand` has no method matching rand(::MersenneTwister,
::Type{AbstractFloat})
Is there a reason behind the fact that I must explicitly say Float32 or Float64 for rand to work? Or is it just that, as the language is relatively new, a relevant method has yet to be defined in the Base?
one is different from rand.
when using one(AbstractFloat), all the outputs are the "same":
julia> one(Float64)
1.0
julia> one(Float32)
1.0f0
julia> 1.0 == 1.0f0
true
this is not true when using rand:
julia> rand(srand(1), Float64)
0.23603334566204692
julia> rand(srand(1), Float32)
0.5479944f0
julia> rand(srand(1), Float32) == rand(srand(1), Float64)
false
this means if rand would behave like one, one might get two different results with the same seed on two different machines(e.g. one is x86, another is x64). take a look at the code in random.jl:
#inline rand{T<:Union{Bool, Int8, UInt8, Int16, UInt16, Int32, UInt32}}(r::MersenneTwister, ::Type{T}) = rand_ui52_raw(r) % T
both rand(Signed)&rand(Unsigned) are illegal too.
Related
For the Julia manual parametric composite type example
struct Point{T}
x::T
y::T
end
it is possible to write an outer constructor such as
Point(x::T, y::T) where {T} = Point{T}(x, y)
Why is the where {T} part needed, i.e. why isn't
Point(x::T, y::T) = Point{T}(x, y)
possible? Julia complains that T is not defined, but could it not figure out that T is a type from the :: syntax? I am a newcomer to Julia so I might be missing something pretty basic.
T is a variable that has to be defined. If you do not define it in where Julia starts looking for it in an outer scope. Here is an example:
julia> struct Point{T}
x::T
y::T
end
julia> Point(x::T, y::T) = Point{T}(x, y)
ERROR: UndefVarError: T not defined
Stacktrace:
[1] top-level scope at REPL[2]:1
julia> T = Integer
Integer
julia> Point(x::T, y::T) = Point{T}(x, y)
Point
julia> Point(1,1)
Point{Integer}(1, 1)
Note that in this example you do not get what you expected to get, as probably you have hoped for Point{Int64}(1,1).
Now the most tricky part comes:
julia> Point(1.5,1.5)
Point{Float64}(1.5, 1.5)
What is going on you might ask. Well:
julia> methods(Point)
# 2 methods for type constructor:
[1] (::Type{Point})(x::Integer, y::Integer) in Main at REPL[4]:1
[2] (::Type{Point})(x::T, y::T) where T in Main at REPL[1]:2
The point is that The (::Type{Point})(x::T, y::T) where T already got defined by default when the struct as defined so with the second definition you have just added a new method for T = Integer.
In short - always use where to avoid getting surprising results. For example if you would write:
julia> T = String
String
julia> Point(1,1)
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type String
you get a problem. As the signature of Point is fixed when it is defined but in the body T is taken from a global scope, and you have changed it from Integer to String, so you get an error.
Expanding on what #Oscar Smith noted the location of where is also sensitive to scope, and tells Julia on what level the "wildcard" is introduced. For example:
ulia> T1 = Vector{Vector{T} where T<:Real}
Array{Array{T,1} where T<:Real,1}
julia> T2 = Vector{Vector{T}} where T<:Real
Array{Array{T,1},1} where T<:Real
julia> isconcretetype(T1)
true
julia> isconcretetype(T2)
false
julia> T1 isa UnionAll
false
julia> T2 isa UnionAll
true
julia> x = T1()
0-element Array{Array{T,1} where T<:Real,1}
julia> push!(x, [1,2])
1-element Array{Array{T,1} where T<:Real,1}:
[1, 2]
julia> push!(x, [1.0, 2.0])
2-element Array{Array{T,1} where T<:Real,1}:
[1, 2]
[1.0, 2.0]
and you can see that T1 is a concrete type that can have an instance, and we created one calling it x. This concrete type can hold vectors whose element type is <:Real, but their element types do not have to be the same.
On the other hand T2 is a UnionAll, i.e. some of its "widlcards" are free (not known yet). However, the restriction is that in all concrete types that match T2 all vectors must have the same element type, so:
julia> Vector{Vector{Int}} <: T2
true
julia> Vector{Vector{Real}} <: T2
true
but
julia> T1 <: T2
false
In other words in T2 the wildcard must have one concrete value that can be matched by a concrete type.
I'm going to take a different tack from BogumiĆ's excellent answer (which is 100% correct, but might be missing the crux of the confusion).
There's nothing special about the name T. It's just a common convention for a short name for an arbitrary type. Kinda like how we often use the name A for matrices or i in for loops. The fact that you happened to use the same name in the struct Point{T} and in the outer constructor is irrelevant (but handy for the readers of your code). You could have just as well done:
struct Point{SpecializedType}
x::SpecializedType
y::SpecializedType
end
Point(x::Wildcard, y::Wildcard) where {Wildcard <: Any} = Point{Wildcard}(x, y)
That behaves exactly the same as what you wrote. Both of the above syntaxes (the struct and the method) introduce a new name that will behave like a "wildcard" that specializes and matches appropriately. When you don't have a where clause, you're no longer introducing a wildcard. Instead, you're just referencing types that have already been defined. For example:
Point(x::Int, y::Int) = Point{Int}(x, y)
That is, this will reference the Int that was already defined.
I suppose you could say, but if T wasn't defined, why can't Julia just figure out that it should be used as a wildcard. That may be true, but it introduces a little bit of non-locality to the syntax, where the behavior is drastically different depending upon what happens to be defined (or even exported from a used package).
I want to get the result type of a function call in Julia without evaluating the function, and use that type. The desired usage looks somewhat like this:
foo(x::Int32) = x
foo(x::Float32) = x
y = 0.0f0
# Assert that y has the type of result of foo(Float32)
y::#resultof foo(Float32) # This apparently does not work in Julia
While in the case above, I can simply use y::typeof(foo(1.0f0)) with evaluation of a dummy variable, in more complicated cases, initializing a dummy variable might be inconvenient and expensive. For example, I want to use the iterator type returned by function eachline(filename::AbstractString; keep::Bool=false), but using the typeof really requires opening a file successfully, which looks like an overkill.
From a C++ background, what I am asking is that is there an equivalent of std::result_of in Julia. The question is almost the same as this one but the language is Julia.
After some research I see that Julia allows for return value of different types in one function, where the type inference looks very hard. For example,
foo(x::Int64) = x == 1 ? 1 : 1.0
The return type can now be Int64 or Float64, depending on the input value. Nevertheless, in this case, I am still wondering if there are some macro tricks that can deduce that the return type is of Union{ Int64, Float64 }?
To summarize, my questions are:
Fundamentally, is it possible to get the function return type by only supplying argument types in Julia?
If 1 is not possible, for functions that have one deterministic return type (as in the 1st example), is it possible to get the return type unevaluated?
(Might be unrelated with what I want but I think it can boost my understanding) When Julia codes are compiled, are the return types of the functions known? Or is the type information only determined at run time?
1) Yes, Base.return_types(foo, (Int64,)) will return an array containing the return type you're asking for, i.e. Union{ Int64, Float64 } in this case. If you drop the second argument, a tuple specifying the input argument types, you'll get all possible infered return types.
It should be noted, however, that the compiler might at any point decide to return Any or any other correct but imprecise return type.
2) see 1) ?
3) For given input argument types, the compiler tries to infer the return type at compile-time. If multiple are possible, it will infer a Union type. If it fails completely, or there are too many different return types, it will infer Any as the return type. In the latter cases, the actual return type is only known at runtime.
Demonstration of 1):
julia> foo(x::Float32) = x
foo (generic function with 1 methods)
julia> foo(x::Int32) = x
foo (generic function with 2 methods)
julia> foo(x::Int64) = x == 1 ? 1 : 1.0
foo (generic function with 3 methods)
julia> Base.return_types(foo)
3-element Array{Any,1}:
Union{Float64, Int64}
Int32
Float32
julia> Base.return_types(foo, (Int64,))
1-element Array{Any,1}:
Union{Float64, Int64}
julia> Base.return_types(foo, (Int32,))
1-element Array{Any,1}:
Int32
Given some complex object, e.g.:
> d = Dict(("a", "b")=>3, ("c", "d")=>2)
Dict{Tuple{String,String},Int64} with 2 entries:
("c","d") => 2
("a","b") => 3
I could check the type with:
> isa(d, Dict{Tuple{String, String},Int64})
true
But when I underspecify the Tuple type, it failed the check:
> isa(d, Dict{Tuple,Int64})
false
Is it possible to check for underspecified types in Julia? If so, how? If not, why?
In Julia, dictionaries, like arrays, are invariant. For example, see this question on the concept as it applies to arrays.
This means that:
julia> Int <: Number
true
but,
julia> Vector{Int} <: Vector{Number}
false
and similarly,
julia> Dict{Int, String} <: Dict{Number, String}
false
However, note that Dict on its own is abstract, so
julia> Dict{Int, String} <: Dict
true
and in the code you provide,
julia> isa(d, Dict)
true
As far as I know, if you want to reason specifically about the pair of types in your dictionary, you will need to reference them explicitly. You can do this using keytype(d) and valtype(d). For example, from your question, note that
julia> keytype(d) <: Tuple
true
Of course, if your dictionary is passed into a function, then you can use Dict{T1, T2} in the function signature, and then just reason about T1 and T2...
EDIT: See #FengyangWang's answer for a neat little syntax shortcut being introduced in v0.6
In Julia 0.6 you can simply do
isa(d, Dict{<:Tuple, Int64})
which means a Dict with key type a subtype of Tuple, and value type Int64.
Note that Dict{Tuple, Int64} is not an "underspecified" type: it is a concrete type and can have instances. However, Dict{Tuple{String, String}, Int64} is not the same thing. The former is a type that accepts all tuples as keys, whereas the latter only accepts Tuple{String, String}. This is an example of parametric invariance.
For simplicity's sake, suppose I have the following function defined:
function returnVectorOrMatrix()
vals = Array(Array{Float32,1}, 10) # vector in this definition
return vals::Array{Array{Float32},1}
end
arr = returnVectorOrMatrix()
Which to my big surprise generates the following error:
ERROR: type: typeassert: expected Array{Array{Float32,N},1},
got Array{Array{Float32,1},1}
Does anyone have a good logical reasoning as to why this is happening / was designed in such way?
Because Array{Array{Float32,1},1} is just a special case of Array{Array{Float32,N},1} with N = 1 so given that Julia is multiple-dispatch I would expect such function to work fine (and seems logical/intuitive as well)
Hint:
julia> Array{Float32,1} <: Array{Float32}
true
julia> Array{Array{Float32,1},1} <: Array{Array{Float32},1}
false
julia> Array{Array{Float32,1},1} <: Array{Array{Float32,1}}
true
could you find any clue now?
in fact, the Array{Array{Float32,1},1} is a parametric type,
julia> Array{Array{Float32,1},1} <: Array{Array{Float32},1}
false
I think the mechanism here is the same case as:
julia> Array{Int32,1} <: Array{Int,1}
false
even if Int32 is a special case of Int, julia will return a false here.
Bacause Array{Array{Float32,1},1} is just a special case of Array{Array{Float32,N},1} with N = 1
so this statement is not true because Array{Float32,1} and Array{Float32,N} are type parameters which are invariant in julia.
I think the problem is simply that Array{Float32} is really Array{Float32,N}, and not Array{Float32,1} (which is the same as Vector{Float32}).
Sorry for the basic question, googling was not too useful so far.
I am a newbie. I'd like to ask if it is possible to have Julia automatically detect incompatible types on assignments.
For example, when I write
julia> x=10;
julia> typeof(x)
Int32
julia> y=9.0;
julia> typeof(y)
Float64
julia> x=y // I'd like this to generate an error or a warning at least
9.0
julia> typeof(x) // do not want automatic type conversion
Float64
I found that if change the assignment to
julia> (x=y)::Int32
ERROR: type: typeassert: expected Int32, got Float64
But I do not want to write this all the time, and want Julia to automatically detect this.
I tried to do declarations like this below, but I seem to be doing something wrong.
julia> x::Int32=10;
julia> y::Float64=9.0
ERROR: type: typeassert: expected Float64, got Int32
For example, in Java, this generates a compile error:
public class App{
public static void main (String[] args) {
int x=10;
double y=9.0;
x=y;
}
}
error: incompatible types: possible lossy conversion from double to int x=y;
What do I need to change to make this happen? do I need to declare x,y with the correct type before? how? I am using Julia 0.3 on Linux.
Values represented by variables can be qualified to always have a particular type, and incompatible values will be checked, but the check for this violation occurs at run time. From the documentation:
When appended to a variable in a statement context, the :: operator means something a bit different: it declares the variable to always have the specified type, like a type declaration in a statically-typed language such as C. Every value assigned to the variable will be converted to the declared type using the convert function.
here is a important caveat, though
Currently, type declarations cannot be used in global scope, e.g. in the REPL, since Julia does not yet have constant-type globals.
So your experiment does not work because you're using globals. However, type assertions using variables scoped in a function do.
So taking your example
Case I
julia> main()=(x::Int64=10;y::Float64=9.0;x=y)
main (generic function with 1 method)
julia> main()
9.0
That looks like the wrong thing happened, but the result of a function is last expression evaluated. So in Case I, the assignment expression returns a Float64 value, though x is still implicitly assigned 9.0 converted to an Int64 or 9. But in Case II, the last expression is simply x which is Int64.
Case II
julia> main()=(x::Int64=10;y::Float64=9.0;x=y;x)
main (generic function with 1 method)
julia> main()
9
julia> typeof(main())
Int64
When y takes on a value that can't be converted without loss to Int64 an error is thrown
Case III
julia> main()=(x::Int64=10;y::Float64=9.9;x=y;x)
main (generic function with 1 method)
julia> main()
ERROR: InexactError()
in main at none:1
The Guts
You can use the function code_typed to see what is going to more precisely. Consider the following:
julia> f(y::Float64)=(x::Int64=y)
f (generic function with 1 method)
julia> code_typed(f,(Float64,))
1-element Array{Any,1}:
:($(Expr(:lambda, {:y}, {{:x},{{:y,Float64,0},{:x,Int64,18}},{}}, :(begin # none, line 1:
x = top(typeassert)(top(box)(Int64,top(checked_fptosi)(Int64,y::Float64))::Int64,Int64)::Int64
return y::Float64
end::Float64))))
julia> f(y::Float64)=(x::Int64=y;x)
f (generic function with 1 method)
julia> code_typed(f,(Float64,))
1-element Array{Any,1}:
:($(Expr(:lambda, {:y}, {{:x},{{:y,Float64,0},{:x,Int64,18}},{}}, :(begin # none, line 1:
x = top(typeassert)(top(box)(Int64,top(checked_fptosi)(Int64,y::Float64))::Int64,Int64)::Int64
return x::Int64
end::Int64))))