At the risk of being redundant, I would like to say a bit more, because I
remember struggling with similar constructions at first - please forgive my
lecturing :-)
Say you do include T as a parameter for Bar, then there are still several
ways to proceed. The following seems to make syntactical sense, but it is
not possible:
type Bar{T,F <: Foo{T}}
a::F
b::T
end
You can not (currently) chain parameters like this. See discussions on
'triangular dispatch', for example #3766
<https://github.com/JuliaLang/julia/issues/3766> and follow-ups.
The following is possible:
type Bar{T,F <: Foo}
a::F
b::T
end
This works, but here you don't enforce that the parameter of Foo is T. You
could accidentally write Bar(Foo(2.0), 2) and mix Ints and Floats. Perhaps
that's fine in your application, but perhaps it is not and you'll have to
be careful when coding.
One way to enforce the relation is with an inner constructor that limits F:
type Bar{T,F <: Foo}
a::F
b::T
Bar(a::Foo{T}, b::T) = new(a,b)
end
At this stage, you can only call this constructor as in
Bar{Int,Foo{Int}}(Foo(2),3).
Ideally, you can just write Bar(Foo(2),3) and that is a good reason for
providing an outer constructor:
Bar{T}(a::Foo{T},b::T) = Bar{T,typeof(a)}(a,b)
This is what I find myself writing currently in cases like this, though I
am not too fond of the 'typeof' there and I am curious about alternatives.
On Wednesday, April 29, 2015 at 1:33:06 PM UTC+2, [email protected] wrote:
>
>
>
> On Wednesday, April 29, 2015 at 9:00:00 PM UTC+10, Robert Gates wrote:
>>
>> Dear Julia users:
>>
>> I'm trying to define a parametric composite type with fields whose types
>> depend on both the type parameter as well as the parameter of the type
>> parameter. This is what I tried:
>>
>> type Foo{T}
>> a::T
>> end
>>
>> type Bar{F <: Foo}
>> a::F
>> b::F.parameters[1]
>> end
>> ERROR: type TypeVar has no field parameters
>>
>> type Bar{F <: Foo{T})
>> a::F
>> b::T
>> end
>> ERROR: UndefVarError: T not defined
>>
>> Is there any way to achieve what I am trying to do without explicitly
>> parametrizing Bar by T? Explicitly parametrizing would work, however, it
>> feels redundant since T is already contained in Foo.
>>
>>
> In neither case is T defined, in the first case you are using an abstract
> Foo for which no T has been defined. And in the second you are
> parameterising Foo by something undefined which just happens to have the
> same name as the parameter name used in the definition of Foo.
>
> So bar has to be parameterised to provide the parameter to supply to Foo,
> and to use as the field in bar.
>
> But note also that Foo{T} is a composite type, not an abstract type so
> there is no type that F can have that satisfies the subtype constraint
> (except Julia may allow Foo{T} itself, not sure).
>
> Cheers
> Lex
>
>
>> Best,
>> Robert
>>
>>
>>
>>
>>
>>
>>