On Fri, 2016-04-15 at 07:28, Anonymous <[email protected]> wrote:
> OP here,
>
> So it looks like the consensus is to use a single type with un-used
> features set to nothing.  I've actually been playing around with this
> approach since I posted this question.  Here's what I've got:
>
> abstract AbstractCar
>
> abstract Color
> abstract Year
>
> typealias ColorOrVoid Union{Color, Void}
> typealias YearOrVoid Union{Year, Void}
>
> type Car{C<:ColorOrVoid, Y<:YearOrVoid} <: AbstractCar
>   color::typeMap(C)
>   year::typeMap(Y)
> end

This should work:

type Car{C<:ColorOrVoid, Y<:YearOrVoid} <: AbstractCar
  color::C
  year::Y
end

(Aside:
I think using a function inside the type definition is only possible if
it can be evaluated at compile time (I might be wrong though).  Consider
this example:

julia> g(T) = Vector{T}
g (generic function with 1 method)

julia> type B{T}
       b::g(T)
       end

julia> B([1,2])
B{Int64}([1,2])

julia> h(T) = string(Int.name.name)[1]=="I" ? Int : Float64
h (generic function with 1 method)

julia> h(AbstractString)
Float64

julia> type C{T}
       c::h(T)
       end
WARNING: static parameter T does not occur in signature for call at none:2.
The method will not be callable.

end-aside)

> where the function typeMap will send Void to itself, Color to ASCIIString
> and Year to Int.  However I tried doing this and I got an error, I probably
> the way to do this is with meta-programming and macros, but I'm not sure
> how since I'm a complete novice at meta-programming.
>
> I would also like to have outer constructors which allow me to avoid having
> to enter Void for all the un-used features, so if I'm only interested in
> Year, I would have an outer constructor of the form:
>
> Car{Year}(y::Int) = Car{Void, Year}(nothing, y)
>
> However this gives me an error saying that *static parameter Year does not
> occur in signature for call at none*.

Outer constructors are a bit hard to grok because type parameter feature
twice, in the same location, but have a completely different
meaning:

Car{Year}(y::Int) = Car{Void, Year}(nothing, y)
    ^^^^                ^^^^^^^^^^
 function parameter     type parameters

Function parameters need to be inferred from the arguments, whereas type
parameters are part of the type. (this might get cleared up in the future)

Consider that for just an ordinary function, you cannot do this:

f{T<:Int}(i::I) = 5
# now call it like so
f{Int}(4) # error

Anyway, the solution is just (assuming Color and Year can be
distinguished by type):

Car(y::Year) = Car{Void, Year}(nothing, y)
Car(c::Color) = Car{Color,Void}(c, nothing)
Car(c::Color, y::Year) = Car{Color,Year}(c, y)

If you want to explicate specify the type then (like is used in
Julia-Base for e.g. array constructors):

Car(T::Type{Year}, y) = Car{Void, Year}(nothing, y)
...


> On Thursday, April 14, 2016 at 10:08:53 PM UTC-7, Toivo Henningsson wrote:
>>
>> As you say, it's a lot of types. If you would really need to instantiate
>> an exponential number of types then maybe you should reconsider, because
>> the jit compiler has to do quite a lot of work for each type that is used.
>>
>> But if you're not actually going to instantiate such a humongous number of
>> them, or if you really want to be able to use specialization and dispatch
>> in this way: How about a middle road where you use a parametric type and
>> set the types of all unused fields to Void (the type of nothing)? That
>> should be able to support the cases that you mentioned.
>>
>> Also, in many cases, storage for a value worth known type of eg Void is
>> free, since it is known that there is only one instance. The exception is
>> if the value could be uninitialized as well.
>>
>>

Reply via email to