Subtyping parametric composite types

I am struggling to understand how I can reuse methods which have been defined as composite parametric types. I am working with the LinearMaps.jl package which defines a FunctionMap as

struct FunctionMap{T,F1,F2} <: LinearMap{T}
    f::F1
    fc::F2
    M::Int
    N::Int
    _ismutating::Bool
    _issymmetric::Bool
    _ishermitian::Bool
    _isposdef::Bool
end

What I would like to do is create my own map which shares the same fields and methods as a FunctionMap, but to which I can add other methods (e.g. an inverse). For example, I would like to do something like this

import Base: \
struct MyMap{T,F1,F2} <: FunctionMap{T,F1,F2}
    f::F1
    fc::F2
    M::Int
    N::Int
    _ismutating::Bool
    _issymmetric::Bool
    _ishermitian::Bool
    _isposdef::Bool
end
\(A::MyMap, b::AbstractVector) = myinverse(A, b)

where MyMap inherits all methods from FunctionMap except \, which I define myself. The above code does not work, and I get a complaint of LoadError: LoadError: invalid subtyping in definition of MyMap.

Any suggestions?

You can only subtype from abstract types. Besides reading the manual, maybe these posts can give some insights Search results for 'composition inheritance' - JuliaLang.

3 Likes

For some more relevant information on why this is intentionally disallowed, see the Types section in the manual:

One particularly distinctive feature of Julia’s type system is that concrete types may not subtype each other: all concrete types are final and may only have abstract types as their supertypes. While this might at first seem unduly restrictive, it has many beneficial consequences with surprisingly few drawbacks. It turns out that being able to inherit behavior is much more important than being able to inherit structure, and inheriting both causes significant difficulties in traditional object-oriented languages.

1 Like

Yes it’s a good idea and the problem is that the library should be dispatching on an abstract type. I didn’t want to keep asking for it, but please revive the issue. Or just PR the solution.

2 Likes

Thanks both of you. For now I have just copied the methods, but I will take this up with the developer or LinearMaps.jl

I missed that paragraph in the manual and was puzzling over the “invalid subtyping” error, because I tried to subtype from a concrete type. Can the compiler message be made more specific?

1 Like

It’s been over 2 years since this thread, and “invalid subtyping” is still about the most useless Julia error I’ve seen. The stracktrace has come a LONG way since pre 1.0 releases in terms of info and speed, but this error seriously needs addressed, considering it’s at the root of OOP practices.

I am not sure why you think this. The error message is telling you that you are trying to define a subtype relationship that is not allowed in Julia (so it is invalid). I find it concise and informative.

What would you prefer instead?

(also, please don’t necro very old topics in the future)

Such as: “Subtyping from a concrete type is strictly forbidden. Please see (doc link).”

2 Likes

Invalid subtyping seems like it could mean any number of things, such as “subtyping concrete types is perfectly ok, but you did it the wrong way, somehow.” Or that there’s something special or weird about that particular parent type that prevented subtyping, and that could be fixed. I would think that I had to tweak things a bit and try again, look through examples somewhere, and scratch my head a lot.

“Subtyping from concrete types is not possible” makes it really clear what’s wrong.

3 Likes

@liuyxpp, @DNF: excellent points. Please consider making a PR.

4 Likes

I don’t really know much (barely any) C, but I suspect that this is where it happens

https://github.com/JuliaLang/julia/blob/e84fec4d67945e50a31b8a15cc23e42c4e124a41/src/builtins.c#L1265

This error message seems to trigger on several different criteria, such as if it isn’t a type at all, if it’s a vararg type, a tuple type, and some other things.

This function needs some re-writing in that case. C is a foreign language, but it still looks like it shouldn’t be too hard.

Something like:
“Invalid subtyping in definition of %s” + one of

  • “Parent is not a type”
  • “Subtyping concrete types is not possible.”
  • “Subtyping NULL is not possible?”
  • “Parent and child types cannot have the same name”
  • “Subtyping a vararg type is not possible”
  • “Subtyping a tuple type is not possible”
  • “Subtyping a named tuple type is not possible”
  • “Subtyping a type type(?!) is not possible” Is this something like Type{T}?
  • “Subtyping a built-in type is not possible” (okay?)

So it needs an extra string variable that is assigned one of these strings somewhere inside the function. So re-writing is needed, indeed.

I think that because it is. I’m not saying there’s an easy fix, I but I don’t see how you can just say

The error message is telling you that you are trying to define a subtype relationship that is not allowed in Julia (so it is invalid).

You may as well have just read off the error statement. By that logic, a seg fault is just as informative. There are plenty of ways to “invalidly” subtype an abstract type. It would be helpful to see a more descriptive stack trace in this case, where possible.

I could start a new topic, sure, but why? It’s the same error, and it hasn’t been addressed AFAIC. Creating a new thread would create two unique pages for others to find eventual answers / solutions / etc.