简体   繁体   中英

Making a no parameter type have “defaults”

I essentially want to do the following:

typealias CVODE_BDF CVODE_BDF{:Newton,:Dense}

that is, allow a user to pass to my function CVODE_BDF and, if they did not set any of the type parameters, interpret it as CVODE_BDF{:Newton,:Dense} . I know that the typealias doesn't actually work, but is there a way to simulate this? Like in the function, read T.parameters[1] and somehow see that it was empty?

You can do this if the function accepts objects of that type , rather than the type itself. Eg

type MyObject{T}
end


const DefaultMyObject = MyObject{Int64}()

f{T}(x::MyObject{T}=DefaultMyObject) = T

f(), f(MyObj{Float64}())

gives

(Int64,Float64)

One possibility is setting the type parameters ( {:Newton,:Dense} ) via Constructors .

Here is an example of the rational number type defined in Julia (rational.jl):

immutable Rational{T<:Integer} <: Real
    num::T
    den::T

    function Rational(num::T, den::T)
        if num == 0 && den == 0
            error("invalid rational: 0//0")
        end
        g = gcd(den, num)
        num = div(num, g)
        den = div(den, g)
        new(num, den)
    end
end

In your example, you could define a constructor function in you CVODE_BDF type definition and check for the types and fall back to {:Newton,:Dense} if they are not set.

Would something like this work for you?

type A{T, S} end

Function implementation:

f{T, S}(::Type{A{T,S}}) = T, S  

Wrappers that set the default values:

f(::Type{A}) = f(A{1, 1})
f{T}(::Type{A{T}}) = f(A{T, 1})
f{S}(::Type{A{:default, S}}) = f(A{1, S})

Result:

f(A)                 # (1,1)
f(A{3,4})            # (3,4)
f(A{0})              # (0,1)
f(A{:default, 2})    # (1,2)

Because the last call is a bit ugly, objects are probably the better choice if maximum flexibility is needed. Additionally, constructors can enforce constraints on the parameters, so that they don't need to be checked in the function.

Edit:

If your function has more than one argument, adding methods for every combination of parameters is too much work. Instead, one can define a default method for each type (just one parameter for brevity):

type A{T} end
type B{T} end

default{T}(::Type{A{T}}) = A{T}
default(::Type{A}) = A{1}
default{T}(::Type{B{T}}) = B{T}
default(::Type{B}) = B{1}

f{T,S}(::Type{A{T}}, ::Type{B{S}}) = T*S
f{T<:A, S<:B}(a::Type{T}, b::Type{S}) = f(default(a), default(b))

On a current nightly, this has no runtime overhead:

julia> @code_llvm f(A,B)

define i64 @julia_f_62099(%jl_value_t*, %jl_value_t*) #0 {
top:
  ret i64 1
}

Yes there is. If you do Type{CVODE_BDF} you can then check the resulting object's parameters. If CVODE_BDF was 'empty' this will return a CVODE_BDF type with generic parameters, otherwise they will be the specific ones used.

Example (using Array since I don't have CVODE_BDF handy):

julia> Type{Array}.parameters
svec(Array{T,N})

julia> Type{Array{Float64, Int64}}.parameters
svec(Array{Float64,Int64})

Example function:

function f{T}(t::T)
  if Type(t).parameters == Type(Array).parameters
    t = Array{Int64, 1};
  end
  return t;
end

julia> f(Array{Int64, 1})
Array{Int64,1}

julia> f(Array{Float64, 1})
Array{Float64,1}

julia> f(Array)
Array{Int64,1}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM