I am in doubt about how to restrict type parameters for parametric types with abstract types in julia 0.6, using the where
syntax.
Consider the example where I want to make a parametric abstract type that takes integers, and define structs inheriting from that. If I try:
abstract type AbstractFoo{T} where T<: Integer end
it fails, but instead I can use the non-where
syntax
abstract type AbstractFoo{T<:Integer} end
Given this, how do I implement my subtype
mutable struct Foo{T} <: AbstractFoo{T} where T <: Integer
bar::T
end
fails too (Invalid subtyping
). I can bypass the where
syntax again with
mutable struct Foo{T<:Integer} <: AbstractFoo{T}
bar::T
end
But that seems to be redundant (because T is already restricted to be an Integer). 2. Could I leave it out?:
mutable struct Foo{T} <: AbstractFoo{T}
bar::T
end
Finally, with the deprecation of inner constructor syntax, is there any way around defining the inner constructor as:
mutable struct Foo{T} <: AbstractFoo{T}
bar::T
Foo{T}(x::T) where T = new(x)
end
This makes Foo(3)
impossible - requiring me to use Foo{Int}(3)
. 3. Is this intentional or is there a better way around this?
EDIT: I guess for the inner constructor question I can always define an outer constructor Foo(x::T) where {T} = Foo{T}(x)
.
I would write:
abstract type AbstractFoo{T<:Integer} end
mutable struct Foo{T} <: AbstractFoo{T}
bar::T
Foo(x::T) where T = new{T}(x)
end
this 1) limit x to Integer
2) allow write Foo(2)
About the questions:
Integer
, but you may get a worse error message since it is arised from AbstractFoo
, not Foo
. Your user may not notice that Foo
is a subtype of AbstractFoo
and get confused.where
syntax. In the new syntax, T{S}
always specify the type parameter of T
and where S
is introducing type parameter of the function. So Foo{T}(x) where T =
defines what Foo{Int}(2)
should do, and Foo(x::T) where T =
defines what Foo(2)
should do. After where
was introduced, there are no "inner constructor" anymore. You can define any function inside any struct (not necessarily constructors of that type), and define any constructor outside type definition - the only difference is inside type definition, you have access of new
.I am on slightly shaky ground here, but I had a similar question not long ago. Based on what I learned from that, I suggest that you try this and see how it works for you:
abstract type AbstractFoo{T} end
mutable struct Foo{T<:Integer} <: AbstractFoo{T}
bar::T
end
It seems most reasonable to me to restrict the parameter on the concrete type rather than on the abstract one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With