Re: [julia-users] Flexible construction of types
How about immutable MyType{T:Real} x::T v::Vector{T} s::String function MyType(x, v, s) x = subtractpi(x) v = map(subtractpi, v) new(x, v, s) end end MyType{T1:Real, T2:Real}(x::T1, v::Vector{T2}, s::String) = (T=promote_type(T1,T2); MyType{T}(x, v, s)) T1 and T2 are both needed to fulfil 5. Otherwise calling `MyType(11.4, [1, 2, 55]) will set T to Float64 and thus error on the array On Wed, 2014-11-26 at 22:20, Marc Gallant marc.j.gall...@gmail.com wrote: Suppose I have a type called MyType that has one floating point field x. When constructed, if the value provided for x is greater than, let's say, 5, it has pi subtracted from it. For example, a = MyType(4) # x = 4.0 b = MyType(-11) # x = 11.0 c = MyType(10) # x = 6.8584 d = MyType(-1.443) # x = -1.443 What is the best way to declare MyType and its constructor(s) to ensure that: 1. You can provide MyType with any real number to construct it 2. typeof(a.x) and typeof(c.x) are both Float64 3. The pi constraint is properly applied (is an inner constructor appropriate here?) 4. The same behaviour applies to the entries of a second field y that is a vector (e.g., MyType(10, [3, 10, 11, -2]) has x = 6.8584, y = [3.0, 6.8584, 7.8584, -2.0]). 5. (if possible) You can construct MyType from a mixture of real number types (e.g., MyType(11.4, [1, 2, 55])) 6. MyType has a third field z that is a string Here is an implementation I wrote that doesn't meet 1, 5, or 6: function subtractpi(x::Real) x, y = promote(x, x - pi) return x 5 ? y : x end immutable MyType{T:FloatingPoint} x::T v::Vector{T} function MyType(x, v) x = subtractpi(x) v = map(subtractpi, v) new(x, v) end end MyType{T:FloatingPoint}(x::T, v::Vector{T}) = MyType{T}(x, v) Thanks. I am working on my understanding of types in Julia.
Re: [julia-users] Flexible construction of types
Thanks for your quick response! I have a couple questions/concerns about your implementation: - MyType(1, [2, 3], xyz) fails requirement #2 - MyType(1, [2, 10], xyz) throws InexactError() - Does the declaration s::String cause the ambiguities described in the FAQ here http://docs.julialang.org/en/latest/manual/faq/#how-do-abstract-or-ambiguous-fields-in-types-interact-with-the-compiler? More specifically, does MyType suffer from the same ambiguity as MyStillAmbiguousType in the FAQ? Thanks again! Marc
Re: [julia-users] Flexible construction of types
Thanks for your quick response! I have a couple questions/concerns about your implementation: - MyType(1, [2, 3], xyz) fails requirement #2 MyType{T1:Real, T2:Real}(x::T1, v::Vector{T2}, s::String) = (T=promote_type(T1,T2,Float64); MyType{T}(x, v, s)) If you want to keep Float16, etc this does not work. It will be at least Float64 (or BigFloat). If you need Float16 etc kept then it's going to be quite a bit more verbose as arithmetic with pi promotes to Float64. If you're fine with just Float64 and don't care about BigFloat then just do: immutable MyType x::Float64 v::Vector{Float64} s::String ... end - MyType(1, [2, 10], xyz) throws InexactError() Should be fixed as well - Does the declaration s::String cause the ambiguities described in the FAQ here http://docs.julialang.org/en/latest/manual/faq/#how-do-abstract-or-ambiguous-fields-in-types-interact-with-the-compiler? More specifically, does MyType suffer from the same ambiguity as MyStillAmbiguousType in the FAQ? I think this should only affect functions which actually use .s but not .x or .v. You can check this like so: julia f(a::MyType) = a.x+a.v[1] f (generic function with 1 methods) julia f(aa) 3.0 julia @code_typed f(aa) 1-element Array{Any,1}: :($(Expr(:lambda, {:a}, {{},{{:a,MyType{Float64},0}},{}}, :(begin # none, line 1: return (top(box))(Float64,(top(add_float))((top(getfield))(a::MyType{Float64},:x)::Float64,(top(arrayref))((top(getfield))(a::MyType{Float64},:v)::Array{Float64,1},1)::Float64))::Float64 end::Float64 This shows that Julia knows that the return type is Float64 (the last bit of the returned thingy). Compare this to: julia immutable MyType2 x v::Vector s::String end julia b=MyType2(1, [2, 10], xyz) MyType2(1,[2,10],xyz) julia g(a::MyType2) = a.x+a.v[1] g (generic function with 1 method) julia g(b) 3 julia @code_typed g(b) 1-element Array{Any,1}: :($(Expr(:lambda, {:a}, {{},{{:a,MyType2,0}},{}}, :(begin # none, line 1: return (top(getfield))(a::MyType2,:x) + (top(arrayref))((top(getfield))(a::MyType2,:v)::Array{T,1},1) end No type annotation at the end of the output here, thus Julia cannot infer the return type.
Re: [julia-users] Flexible construction of types
it should be noted that there's nothing inherently wrong or bad about using non-concrete type specifications in type declarations. it does, however, limit certain optimizations that might provide performance benefits, and may be especially important for native numerical types. On Wed Nov 26 2014 at 4:54:37 PM Marc Gallant marc.j.gall...@gmail.com wrote: Thanks for your quick response! I have a couple questions/concerns about your implementation: - MyType(1, [2, 3], xyz) fails requirement #2 - MyType(1, [2, 10], xyz) throws InexactError() - Does the declaration s::String cause the ambiguities described in the FAQ here http://docs.julialang.org/en/latest/manual/faq/#how-do-abstract-or-ambiguous-fields-in-types-interact-with-the-compiler? More specifically, does MyType suffer from the same ambiguity as MyStillAmbiguousType in the FAQ? Thanks again! Marc