首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么ADT是好的,而继承是坏的?

为什么ADT是好的,而继承是坏的?
EN

Stack Overflow用户
提问于 2010-07-17 22:53:29
回答 4查看 3.1K关注 0票数 24

我是一个长期的面向对象程序员和函数式编程新手。从我的经验来看,代数数据类型对我来说只是一个继承的特例,你只有一个层次结构,并且超类不能扩展到模块之外。

所以我的问题(可能很愚蠢)是:如果ADT只是继承的一种特殊情况(同样,这个假设可能是错误的;请在这种情况下纠正我),那么为什么继承会受到所有的批评,而ADT会得到所有的赞扬?

谢谢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-07-17 23:01:38

我认为ADT是对继承的补充。它们都允许您创建可扩展代码,但可扩展性的工作方式是不同的:

  • ADTs使您可以轻松地添加用于处理现有类型的新功能

  • 您可以轻松地添加使用ADT的新函数,ADT具有一组固定的case
  • 另一方面,添加新case需要修改所有函数

  • Inheritance使添加新类型变得很容易当您具有固定的功能时
    • 您可以轻松地创建继承的类并实现固定的虚函数集
    • 另一方面,添加新的虚函数需要修改所有继承的虚函数

面向对象的世界和函数世界都开发了允许另一种类型的可扩展性的方法。在Haskell中,你可以使用类型类,在ML/OCaml中,人们可以使用函数字典或(?)函数来获得继承风格的可扩展性。另一方面,在OOP中,人们使用访问者模式,这本质上是一种获得类似ADT的东西的方法。

通常的编程模式在OOP和FP中是不同的,因此当您使用函数式语言编程时,您编写代码的方式更需要函数式可扩展性(在OOP中也是如此)。在实践中,我认为有一种语言可以让你根据你试图解决的问题同时使用这两种风格,这是很棒的。

票数 32
EN

Stack Overflow用户

发布于 2010-07-18 00:58:24

Tomas Petricek的基本原理是完全正确的;您可能还想看看Phil Wadler关于“表达式问题”的文章。

我们中的一些人更喜欢代数数据类型而不是继承还有另外两个原因:

  • 使用代数数据类型,编译器可以(并且确实)告诉你是忘记了大小写还是大小写是多余的。当对事物的操作比对事物种类的操作多得多时,这种能力特别有用。(例如,比代数数据类型多得多的函数,或者比面向对象构造函数多得多的方法。)在面向对象的语言中,如果您在子类中遗漏了一个方法,编译器将无法判断这是不是一个错误,或者您是否打算继承超类方法unchanged.
  • This one更加主观:许多人已经注意到,如果正确和积极地使用继承,算法的实现可以很容易地分散到六个类中,即使有一个很好的类浏览器,也很难理解程序的逻辑(数据流和控制流)。没有一个好的类浏览器,你就没有机会。如果你想看一个很好的例子,可以尝试在Smalltalk中实现bignums,在溢出时自动故障转移到bignums。这是一个很好的抽象,但是这种语言使得实现很难理解。使用代数数据类型上的函数,算法的逻辑通常都在一个地方,或者如果它被拆分,它被拆分成具有易于理解的契约的函数。

附言:你在读什么?我不知道有哪个负责任的人会说"ADTs好,OO坏“。

票数 10
EN

Stack Overflow用户

发布于 2010-07-18 02:59:11

根据我的经验,人们通常认为大多数面向对象语言实现的继承“不好”的地方不是继承本身,而是子类修改超类(方法覆盖)中定义的方法的行为,特别是在存在可变状态的情况下。这是真正的最后一部分,这是踢球。大多数面向对象语言将对象视为“封装状态”,这等同于允许对象内部状态的猖獗变化。因此,例如,当超类希望某个方法修改私有变量,但子类覆盖该方法来做完全不同的事情时,就会出现问题。这可能会引入编译器无能为力的细微bug。

请注意,在Haskell的子类多态性实现中,不允许使用可变状态,因此您不会遇到这样的问题。

另请参见this objection到子类型的概念。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3271974

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档