Recovering parameter type from parameter list

Suppose I want to be generic as follows:

# concepts
abstract AbstractFoo{N,T}
abstract AbstractContainer{F}

# partial specialization where we fix T = Float64
immutable Foo{N} <: AbstractFoo{N,Float64} end

# a container of AbstractFoo{N,T} where we save state in a vector of T
immutable Container{F<:AbstractFoo{N,T}} <: AbstractContainer{F}
  state::Vector{T}
end

The code above doesn’t compile because of the malformed parameter list. What is the best way to recover the type T from the type AbstractFoo{N,T} in order to define fields in Container? For instance, I would like to type:

Container([1,2,3])

and get a Container{AbstractFoo{N,Int}. Is it possible? Also, am I doing partial specialization correctly?

In C++, the common idiom for this problem is to save the type T as a field of the class template and query it when needed. Is there a cleaner way to achieve the desired interface in Julia?

1 Like

Could this problem be solved by an appropriate constructor?

function Container{T}(t::Vector{T})
   Container{AbstractFoo{T}}(t)
end

Parameterized type constructors are not my strong point, so your mileage may vary…

@Stephen_Vavasis thank you for your answer. I would like to have the type T inferred without writing extra code like constructors. I don’t know if it is possible though.

Ordinarily this is done as follows

immutable Container{F,T} <: AbstractContainer{F}
    state::Vector{T}
end

and the constraint on F (i.e. F <: AbstractFoo{T}) is checked in the constructor. See for examples the various ReshapedArray, SubArray, etc. types in Base.

1 Like

Thank you @fengyang.wang, I find this approach adopted in Base a little complicated because after all we have a container of Foo, and not a container of Foo and T.

I tried refactoring the code a la C++ as follows:

# concepts
abstract AbstractFoo{N,T}
dimension{N,T}(::AbstractFoo{N,T}) = N
coordtype{N,T}(::AbstractFoo{N,T}) = T

abstract AbstractContainer{F}

# partial specialization where we fix T = Float64
immutable Foo{N} <: AbstractFoo{N,Float64} end

# a container of AbstractFoo{N,T} where we save state in a vector of T
immutable Container{F<:AbstractFoo} <: AbstractContainer{F}
  state::Vector{coordtype(F)}
end

but it returns the error:

ERROR: MethodError: no method matching coordtype(::TypeVar)

There is any workaround for this error? What is a better approach? I believe this is a very common issue that could also be part of a FAQ somewhere.

@juliohm I’ve been having a similar issue. Best I could do was constructors.

1 Like

Thank you @pearcemc, more I play with the Julia type system, more I realize how it is still evolving and missing basic constructs. These idioms we are talking about should be well documented as they appear everywhere. I find it strange that we need to explicitly touch constructors to have a well-defined generic type.

1 Like

more I see you post, more I realize how you are quick to come to conclusions even with rudimentary knowledge of the subjects :wink:

@kristoffer.carlsson more I see your replies, more I realize how you attack people without reason when what we are discussing here is a language and not a parent of yours. Please don’t be a fan boy of Julia criticizing everyone that shows lack of satisfaction with the language. In another post of mine you attacked another guy that was just exposing his impressions of the language. This is not good practice in a forum, let’s keep comments neutral and not attack people.

It’s annoying to see a guy post about that he is just started trying out the type system one day and the next day think he should share what is missing about it. Does something like that even happen except in discussion about programming languages?

Even if your example above would in theory work, the
dimension{N,T}(::AbstractFoo{N,T}) = N
would not be called from coordtype(F) because F is not an instance of AbstractFoo.

Some relevant issues regarding calling functions to determine type of fields when creating a Type: https://github.com/JuliaLang/julia/issues/8322, https://github.com/JuliaLang/julia/issues/18466, https://github.com/JuliaLang/julia/issues/15791.

Is there any way to make this definition work where coordtype(F) evaluates with a AbstractFoo instead? That would at least give a working solution for now. I am trying to avoid touching constructors, but if it is really needed I will do it.

Recently, I am seeing more often that comments come up that are essentially metacomments on the use and scope of the forum. I think the reason is that julia is becoming more mature, so that the great openness of the julia community tends to make people forget that many discussions and great expertise has already been developed.

I don’t know how to deal with this except for maybe some clear discussion policies (e.g. having a dedicated forum section for new ideas and feedback from relative newcomers, so that this becomes separated from the help part of the forum). But I will say that for me and for many of the people I talk to one of the great attractions of julia is the friendliness of the forum and general community, whereas R for instance can have a slightly menacing tone. It would be wonderful if julia could maintain this friendliness, in spite of these challenges.

3 Likes

@kristoffer.carlsson these are all important issues on GitHub, thank you for sharing. Based on the discussion in the links, I am assuming the behavior I want is not available in Julia v0.5. I will post-pone the implementation I have in mind for one of my packages until those TypeVar-related issues are gone.

Since I already contributed earlier, I’ll add my own $0.02 to this debate. I have been using Julia for two years and am satisfied with the progress of the type system. I don’t see a problem in relying on constructors and the use of helper functions to enforce relationships among types and parameters. Indeed, I would be opposed to more complex forms of parametric types because the additional complexity seems to outweigh the benefit to the typical scientific programmer.

The recent innovation in the type system of making functions their own type is a great addition to the language. It seems that there are a few minor points that could still be addressed in the type system, e.g., people keep asking in this forum for methods to be typed objects. But I don’t think future releases of Julia should be held up in order expand the type system.

3 Likes

Through experience I have discovered that the vast majority of questions like “How do I do this in Julia?” are best answered by “You do it using this alternative, which turns out to be just as easy and powerful,” though such an answer seems rarely satisfying to the asker. Coming from a Python background, I have been on both ends of this.

In my opinion it is wise to accept that Julia, in many ways, is a unique language and to try to write it as one would Haskell, or MATLAB, or C, is often a mistake. This is not to say that the language has no limitations; indeed like any computer languages it has many. But most limitations, especially ones that are discovered in the first few weeks of learning or using a language, can be overcome by thinking about the problem in a more idiomatic way.

5 Likes

Let me say that Tim Holy and others’ work on the generic array view infrastructure is remarkable, and is by far the most sophisticated and generic array view structure I have seen in any language. To say that this approach is a little complicated may be true; it does take some learning. But I don’t know of any other approach that allows the full degree of generism (in particular, deciding a result type based on rules specified by arbitrary Julia code, not a restricted language used for deciding types) that Julia does.

4 Likes