Inner constructor of parametric type - julia

I am a bit confused about the type annotations in inner constructor of parametric type.
Are there any difference in the following 4 approaches, in terms of JIT inference efficiency, and runtime efficiency?
immutable MyType{T}
x::T
MyType{T}(x::T) = new{T}(x + x)
end
immutable MyType{T}
x::T
MyType(x::T) = new{T}(x + x)
end
immutable MyType{T}
x::T
MyType(x::T) = new(x + x)
end
immutable MyType{T}
x::T
MyType{T}(x::T) = new(x + x)
end
They all work for x = MyType{Int}(1)

I declared MyType using the above 4 approaches:
immutable MyType1{T}
x::T
MyType1{T}(x::T) = new{T}(x + x)
end
immutable MyType2{T}
x::T
MyType2(x::T) = new{T}(x + x)
end
immutable MyType3{T}
x::T
MyType3{T}(x::T) = new(x + x)
end
immutable MyType4{T}
x::T
MyType4(x::T) = new(x + x)
end
then printed their LLVM bytecode: code_llvm(MyType1{Int},Int) and compared the outputs, they are exactly the same, so I think there are no difference between 4 approaches.

According to Jeff's answer here:
Question 1: If the name of the type is X, and the constructor has the
form function X{...}(...) then the contents of the curly braces right
after the X are passed to new.
Question 2: To make an instance, type parameters must have definite
values, so new(...) is always equivalent to some new{...}(...). They
will lower to the exact same thing.
they're exact the same thing. Your last example is a canonical pattern:
struct MyType{T}
x::T
MyType{T}(x::T) = new(x + x)
end

Related

[julia]syntax: invalid assignment location "getproperty(f, n)"

My julia version is 1.7.1.
These code can recurrent my problem:
struct Foo1
sixsix
aa
bb
disposion
end
struct Foo2
aa
bb
end
function Base.:+(f1::Foo1, f2 :: Foo2)
newf = f1
for n in fieldnames(typeof(f2))
getproperty(newf, n) += getproperty(f2, n)
end
return newf
end
returned LoadError: syntax: invalid assignment location "getproperty(newf, n)"
same LoadError happened when I try to use getfield:
function Base.:+(f1::Foo1, f2 :: Foo2)
newf = f1
for n in fieldnames(typeof(f2))
getfield(newf, n) += getfield(f2, n)
end
return newf
end
Firstly, you must make your structs mutable for this to work.
Secondly, this:
getproperty(newf, n) += getproperty(f2, n)
is expanded into
getproperty(newf, n) = getproperty(newf, n) + getproperty(f2, n)
In other words you are apparently trying to assign a value into a function call. In Julia you can only assign to variables, not to values. The only thing this syntax is allowed for is function definition. From the manual:
There is a second, more terse syntax for defining a function in Julia.
The traditional function declaration syntax demonstrated above is
equivalent to the following compact "assignment form":
julia> f(x,y) = x + y
f (generic function with 1 method)
So the syntax you are using doesn't do what you want, and what you want to do is not possible anyway, since you can only assign to variables, not to values.
What you are trying to do can be achieved like this (assuming n is a Symbol):
setfield!(newf, n, getfield(newf, n) + getfield(f2, n))
I would rather recommend you to do the following:
Base.:+(f1::Foo1, f2 :: Foo2) =
Foo1(f1.sixsix, f1.aa+f2.aa, f1.bb+f2.bb, f1.disposion)
Your code is wrong for the following reasons:
Foo1 is not mutable, so you cannot change values of its elements
to set a field of mutable struct (which your struct is not) you use setfield!
You mix properties and fields of a struct which are not the same.
fieldnames works on types not on instances of type.
If you wanted to be more fancy and do automatic detection of matching fields you could do:
Base.:+(f1::Foo1, f2 :: Foo2) =
Foo1((n in fieldnames(Foo2) ?
getfield(f1, n) + getfield(f2, n) :
getfield(f1, n) for n in fieldnames(Foo1))...)
However, I would not recommend it, as I feel that it is overly complicated.

Restricting function signatures while using ForwardDiff in Julia

I am trying to use ForwardDiff in a library where almost all functions are restricted to only take in Floats. I want to generalise these function signatures so that ForwardDiff can be used while still being restrictive enough so functions only take numeric values and not things like Dates. I have alot of functions with the same name but different types (ie functions that take in "time" as either a float or a Date with the same function name) and do not want to remove the type qualifiers throughout.
Minimal Working Example
using ForwardDiff
x = [1.0, 2.0, 3.0, 4.0 ,5.0]
typeof(x) # Array{Float64,1}
function G(x::Array{Real,1})
return sum(exp.(x))
end
function grad_F(x::Array)
return ForwardDiff.gradient(G, x)
end
G(x) # Method Error
grad_F(x) # Method error
function G(x::Array{Float64,1})
return sum(exp.(x))
end
G(x) # This works
grad_F(x) # This has a method error
function G(x)
return sum(exp.(x))
end
G(x) # This works
grad_F(x) # This works
# But now I cannot restrict the function G to only take numeric arrays and not for instance arrays of Dates.
Is there are a way to restict functions to only take numeric values (Ints and Floats) and whatever dual number structs that ForwardDiff uses but not allow Symbols, Dates, etc.
ForwardDiff.Dual is a subtype of the abstract type Real. The issue you have, however, is that Julia's type parameters are invariant, not covariant. The following, then, returns false.
# check if `Array{Float64, 1}` is a subtype of `Array{Real, 1}`
julia> Array{Float64, 1} <: Array{Real, 1}
false
That makes your function definition
function G(x::Array{Real,1})
return sum(exp.(x))
end
incorrect (not suitable for your use). That's why you get the following error.
julia> G(x)
ERROR: MethodError: no method matching G(::Array{Float64,1})
The correct definition should rather be
function G(x::Array{<:Real,1})
return sum(exp.(x))
end
or if you somehow need an easy access to the concrete element type of the array
function G(x::Array{T,1}) where {T<:Real}
return sum(exp.(x))
end
The same goes for your grad_F function.
You might find it useful to read the relevant section of the Julia documentation for types.
You might also want to type annotate your functions for AbstractArray{<:Real,1} type rather than Array{<:Real, 1} so that your functions can work other types of arrays, like StaticArrays, OffsetArrays etc., without a need for redefinitions.
This would accept any kind of array parameterized by any kind of number:
function foo(xs::AbstractArray{<:Number})
#show typeof(xs)
end
or:
function foo(xs::AbstractArray{T}) where T<:Number
#show typeof(xs)
end
In case you need to refer to the type parameter T inside the body function.
x1 = [1.0, 2.0, 3.0, 4.0 ,5.0]
x2 = [1, 2, 3,4, 5]
x3 = 1:5
x4 = 1.0:5.0
x5 = [1//2, 1//4, 1//8]
xss = [x1, x2, x3, x4, x5]
function foo(xs::AbstractArray{T}) where T<:Number
#show xs typeof(xs) T
println()
end
for xs in xss
foo(xs)
end
Outputs:
xs = [1.0, 2.0, 3.0, 4.0, 5.0]
typeof(xs) = Array{Float64,1}
T = Float64
xs = [1, 2, 3, 4, 5]
typeof(xs) = Array{Int64,1}
T = Int64
xs = 1:5
typeof(xs) = UnitRange{Int64}
T = Int64
xs = 1.0:1.0:5.0
typeof(xs) = StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}
T = Float64
xs = Rational{Int64}[1//2, 1//4, 1//8]
typeof(xs) = Array{Rational{Int64},1}
T = Rational{Int64}
You can run the example code here: https://repl.it/#SalchiPapa/Restricting-function-signatures-in-Julia

How to get a `Ptr` to an element of an `NTuple`?

Say I have a tuple of Cchar like
str = ('f', 'o', 'o', '\0', '\0')
and I want to convert it to a more traditional string. If str were a Vector, I could create Ptr and do all sorts of things with that. I've tried various ways of passing str to methods of pointer, Ptr, Ref, and unsafe_string without success since those normally work on arrays rather than tuples. Any suggestions?
Note: what I really have is a C struct that looks like
typedef struct foo {
char str[FOO_STR_MAX_SZ];
...
} foo_t;
which Clang.jl wrapped as
struct foo_t
str :: NTuple{FOO_STR_MAX_SZ, UInt8}
...
end
I also played around with NTuple of Cchar (ie, Int8) instead of UInt8, and I tried to use SVector instead of NTuple as well. But I still couldn't find a way to generate a Ptr from the str field. Am I missing something?
Since you asked the question, I think collecting it to an array a = collect(x.str) is not the answer you are expecting...
You could use ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), a) to get the pointer of a even if a is immutable. However, blindly using it will produce some confusing results:
julia> struct foo_t
str::NTuple{2, UInt8}
end
julia> a = foo_t((2, 3))
foo_t((0x02, 0x03))
julia> ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), a.str)
Ptr{Nothing} #0x00007f4302c4f670
julia> ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), a.str)
Ptr{Nothing} #0x00007f4302cc47e0
We got two different pointers from the same object! The reason is that since NTuple is immutable, the compiler will do many "optimizations" for it, for example, coping it every time you use it. This is why getting pointers from immutable objects is explicitly forbidden in the source code:
function pointer_from_objref(#nospecialize(x))
#_inline_meta
typeof(x).mutable || error("pointer_from_objref cannot be used on immutable objects")
ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), x)
end
However, there are several workarounds for it. First, since the expression a.str copies the tuple, you can avoid this expressoin and calculate the address of it directly using the address of a and fieldoffset(typeof(a), 1). (1 means str is the first field of foo_t)
julia> p = Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), a)) + fieldoffset(typeof(a), 1)
Ptr{UInt8} #0x00007f4304901df0
julia> p2 = Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), a)) + fieldoffset(typeof(a), 1)
Ptr{UInt8} #0x00007f4304901df0
julia> p === p2
true
julia> unsafe_store!(p, 5)
Ptr{UInt8} #0x00007f4304901df0
julia> a
foo_t((0x05, 0x03))
It now works. However, there are still caveats: when you try to wrap the code in a function, it became wrong again:
julia> mut!(a) = unsafe_store!(Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), a)) + fieldoffset(typeof(a), 1), 8)
mut! (generic function with 1 method)
julia> mut!(a)
Ptr{UInt8} #0x00007f42ec560294
julia> a
foo_t((0x05, 0x03))
a is not changed because, well, foo_t itself is also immutable and will be copied to mut!, so the change made within the function will not be visible outside. To solve this, we need to wrap a in a mutable object to give it a stable address in the heap. Base.RefValue can be used for this purpose:
julia> b = Base.RefValue(a)
Base.RefValue{foo_t}(foo_t((0x05, 0x03)))
julia> mut!(b) = unsafe_store!(Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), b)) + fieldoffset(typeof(b), 1) + fieldoffset(typeof(a), 1), 8)
mut! (generic function with 1 method)
julia> mut!(b)
Ptr{UInt8} #0x00007f43057b3820
julia> b
Base.RefValue{foo_t}(foo_t((0x08, 0x03)))
julia> b[]
foo_t((0x08, 0x03))
As explained by #张实唯, str is a constant array which is stack-allocated, so you need to use pointer arithmetics to access the field. There is a package called Blobs.jl for this kinda purpose. As for the mutability, you could also use Setfield.jl for convenience.
BTW, Clang.jl do support generating mutable structs via ctx.options["is_struct_mutable"] = true.

How to specify conditions within Julia's composite types?

I am trying to create a composite type in Julia representing points on an elliptic curve.
Point are valid if satisfying y^2 == x^3 + a*x + b OR both x and y are equal to nothing. Note that the later case represents point at infinity.
I have come up with the below code but can't figure out how to account for point at infinity.
Is there a way to handle different exceptions in struct?
Can exception simply return a valid type instead of an error? e.g. if x == nothing && y == nothing then Point(nothing,nothing,a,b)
IntOrNothing = Union{Int,Nothing}
struct Point
x::IntOrNothing
y::IntOrNothing
a::Int
b::Int
Point(x,y,a,b) = x == nothing || y == nothing || y^2 != x^3 + a*x + b ? error("Point is not on curve") : new(x,y,a,b)
end
I would define two inner constructors for Point like this:
IntOrNothing = Union{Int,Nothing}
struct Point
x::IntOrNothing
y::IntOrNothing
a::Int
b::Int
Point(x::Nothing,y::Nothing,a,b) = new(x,y,a,b)
Point(x,y,a,b) = y^2 != x^3 + a*x + b ? error("Point is not on curve") : new(x,y,a,b)
end
as this would be most readable in my opinion.
Note that you will get MethodError if you call Point(nothing,2,1,3) but I guess from your code you do not care about the type of exception thrown as long as it is thrown on invalid data.
Does it solve your problem?

julia-lang Check element type of arbitrarily nested array

How could I check the element type of a nested array assumming I don't know the level of nesting?:
julia> a = [[[[1]]]]
1-element Array{Array{Array{Array{Int64,1},1},1},1}:
Array{Array{Int64,1},1}[Array{Int64,1}[[1]]]
julia> etype(a)
Int64?
As it is often the case for type computations, a recursive approach works very well:
nested_eltype(x) = nested_eltype(typeof(x))
nested_eltype{T<:AbstractArray}(::Type{T}) = nested_eltype(eltype(T))
nested_eltype{T}(::Type{T}) = T
This has no runtime overhead:
julia> #code_llvm nested_eltype([[[[[[[[[[1]]]]]]]]]])
define %jl_value_t* #julia_nested_eltype_71712(%jl_value_t*) #0 {
top:
ret %jl_value_t* inttoptr (i64 140658266768816 to %jl_value_t*)
}
There is probably a clever way to do this with one line, but in the meantime, you can use recursive calls to eltype to do this inside a while loop:
function nested_eltype(x::AbstractArray)
y = eltype(x)
while y <: AbstractArray
y = eltype(y)
end
return(y)
end
Note that this works for nested arrays of any dimension, ie it doesn't just have to be Vector like the example in your question...
This is a generated version using .depth attribute:
#generated function etype{T}(x::T)
ex = :(x)
for i = 1:T.depth
ex = :($ex |> eltype)
end
ex
end
julia> a = [[[[1]]]]
1-element Array{Array{Array{Array{Int64,1},1},1},1}:
Array{Array{Int64,1},1}[Array{Int64,1}[[1]]]
julia> etype(a)
Int64

Resources