Why is it impossible to subtype a struct?

I think there is some tension between the above statement, which is both logical and desirable for performance reasons, and the actual possibility to reuse code.

In practice, it can happens that a type is completely specified for someone, but incompletely specified for someone else. The important word here is incompletely: it means that what is available is already a good starting point, but something else is missing.

While this is not a big issue for structure definitions (we can always use macros to copy/paste fields), it is a huge problem for code reuse since:

  • abstract types carry no information on the actual data representation;
  • methods operate on specific data representations, hence their arguments will be annotated with concrete types;
  • but concrete types can not be subtyped, hence those method implementations are locked, and can not be reused.

This problem might be mitigated if we could attach a specific data representation to abstract types. Besides, there are cases where an abstract type will always have one (and only one!!) concrete subtype (consider the DataFrame case, thoroughly discussed here: in this case the distinction between AbstractDataFrame and DataFrame is almost fictitious, and they are actually the same thing).

I completely agree that allowing subtyping in all cases brings more damage than advantages, but disallowing it in all cases prevents code reuse (as discussed above). It looks like we need a comporomise in the allowing/disallowing concrete subtyping and abstract/concrete dichotomy…

In ReusePatterns I explore the possibility to exploit one such compromise through the concept of quasi-abstract type, i.e. a type which:

  • can be subtyped like an abstract one;
  • can have data representation attached, like a concrete one;
  • introduce a performance penalty if used in a container, like an abstract one;
  • can be used to annotate method arguments, with no performance penalty, like a concrete one.
  • it inherits the structure fields of its ancestors, unlike both abstract and concrete types.
  • it is supposed to be subtyped, i.e. the author clearly states that it is not final and (most importantly) it fosters code reuse.

I agree there is no value added in the structure definition, but there is a huge advantage for code reuse: e.g. function mymethod(input::Rectangle) could be reused by all Rectangle subtypes, since they will all contain the width and height fields.

In summary: we may safely neglect the problem of concrete subtyping (there are macro for this), but for the purpose of code reuse it might be useful to attach data representation to an abstract type (making it a not-so-abstract one, or quasi-abstract). Incidentally, the latter condition brings the possibility of concrete subtyping, even if it was not the original goal.

As R.P. Feynman once said: sure it can give some practical results, but that’s not why we do it!. :wink:

4 Likes