16

Suppose I define a function on an abstract type A in Julia:

abstract A
function mysum(a::A)
  a.x + a.y
end

Implicitly any subtype should have the fields x and y for this function to work. So the functions defined on A are what set the requirements for subtypes. These functions could be written anywhere and one can imagine a situation where the functions are much more complex and the requirements are harder to spot. Is there someway to declare the requirements a subtype of an abstract type must have besides just implicitly from functions?

This seems to be related to Julia#6975 but if its not related to that could someone clarify the difference.

Finally, why would anyone want to use a type union instead of an abstract type. The abstract type is more flexible and extensible, the type union is fixed. For example

Why this:

type A
  x
end

type B
  x
end

typealias C Union{A,B}

Instead of this:

abstract C

type A <: C
  x
end

type B <: C
  x
end
mv3
  • 469
  • 5
  • 16
  • 3
    First question: I do not think there is a way to achieve this currently, but it is at the heart of the discussions about adding traits to the language. You have already found one issue discussing this, and I believe it is on the informal roadmap beyond version 1.0 (at least I've seen it mentioned.) Union types can be used (among other things) to add methods to types that do not have a common supertype. Abstract types are fine, but you cannot always shoehorn all your types into a common hierarchy, and frequently you will add methods to collections of types that you did not define yourself. – DNF Oct 24 '16 at 07:46
  • @DNF Thank you, that clarifies my confusion! If you want to write it as an answer I will be happy to accept. – mv3 Oct 24 '16 at 14:10
  • Please break this into Two questions. – Frames Catherine White Oct 24 '16 at 18:55
  • @Oxinabox its already answered, you want me to open 2 other questions? – mv3 Oct 25 '16 at 02:53
  • @mikev3 not this time, it is not worth it (I wrote that comment without refreshing the page). But for future questions, it good form to break them up. It means that if someone can answer one part really well, but the other poorly they are not kinda stuck. And it keeps each post focused. – Frames Catherine White Oct 25 '16 at 03:15
  • @Oxinabox ok thanks for the advice – mv3 Oct 25 '16 at 03:32

1 Answers1

17

First question: I do not think there is a way to achieve this currently, but it is at the heart of the discussions about adding traits to the language. You have already found one issue discussing this, and I believe it is on the informal roadmap beyond version 1.0 (at least I've seen it mentioned.)

I think the recommended way of implementing what you are looking for is something along these lines (note that type has been deprecated and replaced by struct):

abstract type A end

struct B <: A
    x
    y
end

struct C <: A
    w
    z
end

prop1(b::B) = b.x
prop2(b::B) = b.y
prop1(c::C) = c.w
prop2(c::C) = c.z  # changed from prop2(c::C)=c.w

mysum(a::A) = prop1(a) + prop2(a)

That is, instead of requiring B and C to have the same fields, you implement methods that define their behaviour. Then the actual field names remain internal implementation details of each concrete type.

As for union types, they can be used (among other things) to add methods to types that do not have a common supertype. Abstract types are fine, but you cannot always shoehorn all your types into a common hierarchy, and frequently you will add methods to collections of types that you did not define yourself.

DNF
  • 11,584
  • 1
  • 26
  • 40
  • 1
    This is exactly what I was wondering, thanks! If B and C share the same type of information but not the exact same field names then how to I implement a common method? You've cleared this up. – mv3 Oct 24 '16 at 17:38
  • +1 for using methods to access fields. I made the false assumption of assuming every subtype of my abstract type that I would ever need would have the same core 5 fields implemented in the same way, plus some others. This proved to be wrong and made my code ugly. I now think of access the field of something that is declared as am abstract type to be an antipattern. (Was talking about adding a Lint.jl rule for it) – Frames Catherine White Oct 25 '16 at 03:18
  • @DNF Unless I'm mistaken this looks very similar to Type Classes in Scala, Rust or Haskell. The functions `prop1` and `prop2` are the Type Classes and the methods `prop1(b::B)`, `prop1(c::C)` etc are the implementations of those Type Classes, is that roughly correct or did I miss-understand something? – Oli Aug 05 '20 at 10:54
  • This answer got edited on April 27 2021 but It wasn't updated fully: `abstract A` will error on post-v1.0 Julia. It should read `abstract type A end`. I suggested that edit but mods rejected it. @DNF could you update it? – aramirezreyes Jun 22 '21 at 22:16
  • Sure. Thanks for the tip. – DNF Jun 22 '21 at 22:22