I am having some issues understanding the concept of parametric constructors in Julia. I am looking at the standard example in the Julia docs:
struct Point{T<:Real}
x::T
y::T
end
To my understanding, this means I can generate a Point-datatype with an input that is subtype of Real, i.e., AbstractFloat, AbstractIrrational, ..., Integer, Rational, ..., StatsBase.TestStat.
However, both of the examples below result in errors:
Point(Integer(12))
Point(Rational(12))
Why does the above fail given that both integer and rational are subtypes of real?
The type parameter goes inside the curly braces in the constructor call, just like it does in the struct definition:
julia> Point{Integer}(12, 12)
Point{Integer}(12, 12)
julia> Point{Rational}(12, 10//3)
Point{Rational}(12//1, 10//3)
The arguments supplied are the values for the fields of the struct i.e. x and y. If the arguments are already of the type you want, you can leave out explicitly specifying the type parameter:
julia> Point(12, 6)
Point{Int64}(12, 6)
julia> Point(12.0, 6.0)
Point{Float64}(12.0, 6.0)
julia> Point(12, 6.0) #no automatic type promotion happens though
ERROR: MethodError: no method matching Point(::Int64, ::Float64)
Closest candidates are:
Point(::T, ::T) where T<:Real at REPL[1]:2
Stacktrace:
[1] top-level scope
# REPL[9]:1
julia> Point{Float64}(12, 6.0) #unless you explicitly specify the type
Point{Float64}(12.0, 6.0)
Related
I have a module, say, called Constants,
module Constants
const zero = 0.0 :: Float64
const czero = 0.0 + 0.0im :: Complex
end
I know like I can define like zero as Float64. But How do I define a "Complex" and "Float64" variable such as czero? Currently I use Complex, but I want to be more specific. If I use ComplexF64
const czero = 0.0 + 0.0im :: ComplexF64
it gives me an error,
ERROR: LoadError: TypeError: in typeassert, expected Complex{Float64}, got a value of type Complex{Bool}
So what concrete type of Complex should I use?
I give each variable a concrete type is because I heard that if the code looks like Fortran it can run like Fortran, because I define the type first so Julia do not have to convert the type which can be very slow.
This question is not quite clear, but perhpas what you need is zero:
julia> zero(ComplexF64)
0.0 + 0.0im
julia> dump(zero(ComplexF64))
ComplexF64
re: Float64 0.0
im: Float64 0.0
Other options include using the constructor such as ComplexF64(0.0) or ComplexF64(0.0,0.0) or using the complex(0.0) function. These are all type stable.
::
With the ::-operator type annotations are attached to expressions and variables in programs. See the manual section on Type Declarations.
Outside of declarations :: is used to assert that expressions and variables in programs have a given type.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> (1+2)::AbstractFloat
ERROR: TypeError: typeassert: expected AbstractFloat, got a value of type Int64
julia> (1+2)::Int
3
With this in mind, obviously julia considers the declaration invalid because of operator precedence, so just put parentheses if you want to do the declaration this way
const czero = (0.0 + 0.0im) ::ComplexF64
I also second the opinion above: if you're just trying to declare zeros then what you need is zero
I have about 50 functions which should consume only even positive numbers. Right now I am checking each time with an "if" whether the number put in is zero or not:
function grof(x::Int)
if (x % 2) == 0
println("good")
else
throw("x is not an even number!!!!!!!!!!!!! Stupid programmer!")
end
end
Ideally, I would like to have a datatype which produces this automatically, i.e.
function grof(x::EvenInt)
println("good")
end
However, I am not able to produce this datatype by my own since I am unable to understand the documentary. Thanks for your help!
Best, v.
I don't think creating a type is warranted in such a situation: I would simply #assert that the condition is verified at the beginning of the function(s). (Funnily enough, checking the whether a number is even is the example that was chosen in the documentation to illustrate the effect of #assert)
For example:
julia> function grof(x::Int)
#assert iseven(x) "Stupid programmer!"
println("good")
end
grof (generic function with 1 method)
julia> grof(2)
good
julia> grof(3)
ERROR: AssertionError: Stupid programmer!
Stacktrace:
[1] grof(::Int64) at ./REPL[5]:2
[2] top-level scope at REPL[7]:1
EDIT: If you really want to create a type enforcing such a constraint, it is possible. The way to do this would be to
create a type (possibly subtyping one of the Number abstract types; maybe Signed)
define an inner constructor ensuring that such a type cannot hold an odd value
A very simple example to build upon would be along the lines of:
# A wrapper around an even integer value
struct EvenInt
val :: Int
# inner constructor
function EvenInt(val)
#assert iseven(val)
new(val)
end
end
# Accessor to the value of an EvenInt
val(x::EvenInt) = x.val
# A method working only on even numbers
grof(x::EvenInt) = println("good: $(val(x)) is even")
You'd use this like so:
julia> x = EvenInt(42)
EvenInt(42)
julia> grof(x)
good: 42 is even
julia> y = EvenInt(1)
ERROR: AssertionError: iseven(val)
Stacktrace:
[1] EvenInt(::Int64) at ./REPL[1]:5
[2] top-level scope at REPL[6]:1
but note that you can't do anything on EvenInts yet: you need to either unwrap them (using val() in this case), or define operations on them (a task which can be vastly simplified if you make EvenInt a subtype of one of the abstract number types and follow the relevant interface).
All integers multiplied by two are even, so redefine your function to take half the number it currently takes.
function grof2(halfx::Int)
x=2*halfx
println("good")
end
I am getting an error while running the following Julia snippet
using GR, Interact
t = 0:0.01:1
#manipulate for phi=0:0.1:6.28
plot(cos.(2π*t+phi))
end
LoadError: MethodError: no method matching +(::StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}, ::Float64)
Closest candidates are:
+(::Any, ::Any, !Matched::Any, !Matched::Any...) at operators.jl:529
+(!Matched::Bool, ::T<:AbstractFloat) where T<:AbstractFloat at bool.jl:104
+(!Matched::Float64, ::Float64) at float.jl:395
...
in expression starting at C:\Users\W.Aftab\Desktop\Julia_Codes\src\003.jl:3
(::getfield(Main, Symbol("##9#10")))(::Float64) at 003.jl:4
map(::Function, ::Widget{:slider,Float64}) at Observables.jl:174
top-level scope at manipulate.jl:25
Any idea what is wrong?
The following should work better:
using GR, Interact
t = 0:0.01:1
#manipulate for phi=0:0.1:6.28
plot(cos.(2π*t.+phi)) #note the dot in ".+"
end
This is because in that expression, t is a range, and therefore 2pi*t is also a range, because in Julia the product between a scalar and a collection of value is defined to perform the product of each element of the collection by the scalar.
At each iteration in the loop, phi is a scalar. And the operation + is not defined between a scalar and a collection. It has to be explicitly broadcasted, for example using the .+ notation.
Julia permits function and method definitions with unnamed arguments.
This is not mentioned in the functions documentation, nor is it explicitly discussed in the methods documentation. For example:
function myfunc(::Int)
println("Hello!")
end
How should I describe this behavior (I've googled "anonymous arguments" without success), and when is it useful?
This behavior is useful for method dispatch, when you care only about argument type not argument value. Most often this is a case when what you dispatch on is a singleton type.
An example is:
julia> Vector{String}(undef, 3)
3-element Array{String,1}:
#undef
#undef
#undef
This function is defined in the following way:
Array{T,1}(::UndefInitializer, m::Int) where {T} =
ccall(:jl_alloc_array_1d, Array{T,1}, (Any, Int), Array{T,1}, m)
And you can see that we only care that the first argument was of UndefInitializer type, which is in turn defined as:
struct UndefInitializer end
const undef = UndefInitializer()
We see that UndefInitializer is a singleton type, so we do not care about the value of a variable of this type, but only about its type.
Another common singleton type in Base is Missing. Here are example definitions from Base of standard functions getting a Missing as an argument:
for f in (:(acos), :(acosh), :(asin), :(asinh), :(atan), :(atanh),
:(sin), :(sinh), :(cos), :(cosh), :(tan), :(tanh),
:(exp), :(exp2), :(expm1), :(log), :(log10), :(log1p),
:(log2), :(exponent), :(sqrt))
#eval $(f)(::Missing) = missing
end
(again - you can see that we do not care about the value of the variable - we know its type is Missing so we return missing)
In the Julia manual you have examples of such methods e.g. here but admittedly as far as I can tell the manual does not give a name for this style of method definition.
I'm new to Julia and it's an exciting language. I just come across some weird behavior that I cannot find an explanation online. I appreciate your help.
versioninfo()
Julia Version 0.4.0
Commit 0ff703b* (2015-10-08 06:20 UTC)
Platform Info:
System: Darwin (x86_64-apple-darwin13.4.0)
CPU: Intel(R) Core(TM) i5-4258U CPU # 2.40GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
LAPACK: libopenblas64_
LIBM: libopenlibm
LLVM: libLLVM-3.3
I defined a structure
type mytype
x :: UInt8
y :: UInt8
mytype(n::UInt8) = new(n, 0)
end
The type contains a constructor that has a default value for one field and takes input for the other. Then I test it
mytype(1)
LoadError: MethodError: `convert` has no method matching convert(::Type{mytype}, ::Int64)
This may have arisen from a call to the constructor mytype(...),
since type constructors fall back to convert methods.
Closest candidates are:
call{T}(::Type{T}, ::Any)
convert{T}(::Type{T}, !Matched::T)
mytype(!Matched::UInt8)
while loading In[56], in expression starting on line 1
in call at essentials.jl:56
The error message is very confusing and I can't understand it. I tested that if I provide default values to the two parameters or take the two inputs, the code works well.
Thanks.
I get
julia> mytype(1)
ERROR: MethodError: `convert` has no method matching convert(::Type{mytype}, ::Int64)
This may have arisen from a call to the constructor mytype(...),
since type constructors fall back to convert methods.
Closest candidates are:
call{T}(::Type{T}, ::Any)
convert{T}(::Type{T}, ::T)
mytype(::UInt8)
in call at essentials.jl:56
To break it down, it says it tried to call the constructor, but no constructor matched. Why did no constructor match? Because there is no automatic conversion defined from Int64 (the 1) to UInt8.
It then tried converting a Int64 into mytype, but that method isn't defined either. It then gave up, and displayed the closest things to the thing it originally tried (mytype(::Int64)).
You might want to provide additional methods to handle this, or accept any integer in your constructor and use convert to force it to UInt8 - if it fails, it'll throw an exception:
julia> type mynewtype
x :: UInt8
y :: UInt8
mynewtype(n::Integer) = new(n, 0)
end
julia> mynewtype(5)
mynewtype(0x05,0x00)
In the original question,mytype 's member y will always be 0 because the type inner constructor is called with the second argument 0.
They way to construct an instance in this case is : mytype(UInt8(25)) which yields mytype2(0x19,0x00).
However, it cannot accept values for y: mytype(UInt8(5), UInt8(23)) yields an error.
In the answer, mynewtype can handle normal Int64 through the inner constructor however, it will always initialize the y with 0 as well ...
In Julia, the inner constructor initializes the members of the type.The way to properly handle different argument signatures is by defining the type:
type mytype2
x::UInt8
y::UInt8
end
and an outer constructor: mytype2(n::Integer) = mytype2(n,0) which calls the default, implicit (and invisible), inner constructor mytype2(x,y) = new(x,y).
mytype2 can be verified by mytype2(1,2) which yields mytype2(0x01,0x02) and, mytype2(1) which yields mytype2(0x01,0x00).
More info at : Julia 0.4 constructors documentation page, "Inner Constructor Methods" (recommendations for safe type definitions at the end of the section)