Why avoid subtyping?

2019-01-10 05:48发布

I have seen many people in the Scala community advise on avoiding subtyping "like a plague". What are the various reasons against the use of subtyping? What are the alternatives?

8条回答
趁早两清
2楼-- · 2019-01-10 06:01

My answer does not answer why it is avoided but tries to give another hint at why it can be avoided.

Using "type classes" you can add an abstraction over existing types/classes without modifying them. Inheritance is used to express that some classes are specializations of a more abstract class. But with type classes you can take any existing classes and express that they all share a common property, for example they are Comparable. And as long as you are not concerned with them being Comparable you don't even notice it. The classes don't inherit any methods from some abstract Comparable type as long as you don't use them. It's a bit like programming in dynamic languages.

Further reads:

http://blog.tmorris.net/the-power-of-type-classes-with-scala-implicit-defs/

http://debasishg.blogspot.com/2010/07/refactoring-into-scala-type-classes.html

查看更多
淡お忘
3楼-- · 2019-01-10 06:02

I think lots of Scala programmers are former Java programmers. They are used to think in term of Object Oriented subtyping and they should be able to easily find OO-like solution for most problems. But Functional Programing is a new paradigm to discover, so people ask for a different kind of solutions.

查看更多
家丑人穷心不美
4楼-- · 2019-01-10 06:06

Focusing on subtyping, ignoring the issues related to classes, inheritance, OOP, etc.. We have the idea subtyping represents a isa relation between types. For example, types A and B have different operations but if A isa B we then can use any of B's operations on an A.

OTOH, using another traditional relation, if C hasa B then we can reuse any of B's operations on a C. Usually languages let you write one with a nicer syntax, a.opOnB instead of a.super.opOnB as it would be in the case of composition, c.b.opOnB

The problem is that in many cases there's more than one way to relate two types. For example Real can be embedded in Complex assuming 0 on the imaginary part, but Complex can be embedded in Real by ignoring the imaginary part, so both can be seen as subtypes of the other and subtyping forces one relation to be viewed as preferred. Also, there are more possible relations (e.g. view Complex as a Real using theta component of polar representation).

In formal terminology we usually say morphism to such relations between types and there are special kinds of morphisms for relations with different properties (e.g. isomorphism, homomorphism).

In a language with subtyping usually there's much more sugar on isa relations and given many possible embeddings we tend to see unnecessary friction whenever we're using the unpreferred relation. If we bring inheritance, classes and OOP to the mix the problem becomes much more visible and messy.

查看更多
霸刀☆藐视天下
5楼-- · 2019-01-10 06:07

I think the general context is for the lanaguage to be as "pure" as possible (ie using as much as possible pure functions), and comes from the comparison with Haskell.
From "Ruminations of a Programmer"

Scala, being a hybrid OO-FP language has to take care of issues like subtyping (which Haskell does not have).

As mentioned in this PSE answer:

no way to restrict a subtype so that it can't do more than the type it inherits from.
For example, if the base class is immutable and defines a pure method foo(...), derived classes must not be mutable or override foo() with a function that is not pure

But the actual recommendation would be to use the best solution adapted to the program you are currently developing.

查看更多
看我几分像从前
6楼-- · 2019-01-10 06:09

This is the best paper I have found on the subject. A motivating quote from the paper –

We argue that while some of the simpler aspects of object-oriented languages are compatible with ML, adding a full-fledged class-based object system to ML leads to an excessively complex type system and relatively little expressive gain

查看更多
家丑人穷心不美
7楼-- · 2019-01-10 06:25

I don't know Scala, but I think the mantra 'prefer composition over inheritance' applies for Scala exactly the way it does for every other OO programming language (and subtyping is often used with the same meaning as 'inheritance'). Here

Prefer composition over inheritance?

you will find some more information.

查看更多
登录 后发表回答