英文原文:What’s Wrong with OOP and FP
我不理解为什么人们会对面向对象编程和函数式编程做无休无止的争论。就好象这类问题已经超越了人类智力极限,所以你可以几个世纪的这样讨论下去。经过这些年对编程语言的研究,我已经清楚的看到了问题的答案,所以,我经常的发现,人们对这些问题做的都是一些抓不住要领、无意义的争论。
简言之,不论是面向对象编程还是函数式编程,如果你走了极端,那都是错误的。面向对象编程的极端是一切都是对象(纯面向对象)。函数式编程的极端是纯函数式编程语言。
面向对象编程的问题
面向对象的问题在于它对“对象”的定义,它试图将所有事情就纳入到这个概念里。这种做法极端化后,你就得出来一个一切皆为对象思想。但这种思想是错误的,因为
有些东西不是对象。函数就不是对象。
也许你会反驳,在 Python 和 Scala 语言里,函数也是对象。在 Python 中,所有的含有一个叫做__call__的方法的对象其实都是函数。类似的,在 Scala 语言里,函数是拥有一个叫做apply方法的对象。但是,经过认真的思考后,你会发现,它混淆了源祖和衍生物的概念。函数是源祖,包含函数的对象实际是衍生物。__call__
和apply
它们自身首先就是要定义的所谓“函数对象”。Python 和 Scala 实际上是绑架了函数,把它们监禁在“对象”里,然后打上“__call__” 和 “apply” 标签,把它们称作“方法”。当然,如果你把一个函数封装到对象里,你可以像使用一个函数那样使用对象,但这并不意味着你可以说”函数也是对象“。
大多数的面向对象语言里都缺乏正确的实现一等(first-class)函数的机制。Java 语言是一个极致,它完全不允许将函数当作数据来传递。你可以将全部的函数都封装进对象,然后称它们为“方法”,但就像我说的,这是绑架。缺乏一等函数是为什么 Java 里需要这么多“设计模式”的主要原因。一旦有了一等函数,你将不再需要大部分的这些设计模式。
函数式编程的问题
相似的,函数式编程走向极端、成为一种纯函数式编程语言后,也是有问题的。为了讨论这个问题,我们最好先理解一下什么是纯函数式编程语言。出于这个目的,你可能需要阅读一下 Amr Sabry 先生(他是我的博士导师)的 What is a Purely Functional Language。概述一下就是,纯函数式编程语言是错误的,因为
有些东西不是纯的。副作用是真实存在的。
所谓纯函数,基本上就是忽略了物质基础(硅片、晶体等)表现的特性。纯函数式的编程语言试图通过函数——在函数中传入传出整个宇宙——来重新实现整个宇宙。但物理的和模拟的是有区别的。“副作用”是物理的。它们真实的存在于自然界中,对计算机的效用的实现起着不可或缺的作用。利用纯函数来模拟它们是注定低效的、复杂的、甚至是丑陋的。你是否发现,在C语言里实现一个环形数据结构或随机数发生器是多么的简单?但使用 Haskell 语言就不是这样了。
还有,纯函数编程语言会带来巨大的认知成本。如果你深入观察它们,你会看到monads
使程序变得复杂,难于编写,而且 monad 的变体都是拙劣的修改。monads 跟 Java 的“设计模式”具有相同的精神本质。使用 monad 来表现副作用就像是 visitor 模式来写解释器。你是否发现,在很多其它语言里很简单的事情,放到 Haskell 语言就变成了一个课题来研究如何实现?你是否经常会看到一些有着诸如“用 Monadic 的方式解决一个已经解决的问题”这样标题的论文?有趣的是,Amr Sabry 先生一起合著了这样一篇论文。他试图用 Haskell 语言重新实现 Dan Friedman 的 miniKanren,但他不知道如何构造这些monads
。他向 Oleg Kiselyov——公认的世界上对 Haskell 类型系统知识最渊博的人——求教。而且你可能不知道,Amr Sabry 先生应该是世界上对纯函数编程语言知识最渊博的人了。他们在 Oleg 的帮助下解决了疑难后一起合著了这篇论文。讽刺的是,Dan Friedman——这个程序的原作者——在使用 Scheme 语言开发时却没有遇到任何问题。我在 Dan 的代码基础上重新实现了 miniKanren,增加了一个复杂的负操作。为了实现这个,我需要使用约束式逻辑编程和其它一些高级的技巧。鉴于用 Haskell 语言重写基本的 miniKanren 将两位世界级程序员都难倒了的事实,我不敢想象如果用 Haskell 的monads
如何能实现这些。
有些人认为monads
的价值在于,它们“圈定”了副作用的范围。但如果monads
不能真正的使程序变得易于分析或更安全,这种“圈定”有什么用呢?事实上就是没用处。本身就跟副作用一样难于分析理解。没有一种东西可以说monads
能使其简单而静态分析办不到的。所有的静态分析研究者都知道这点。静态分析利用了monads
的本质,但却去除了程序员编写monads
代码的负担——而不是增加负担。当然,过度的副作用会使程序很难分析,但你也可以使用C语言写出纯函数,例如:
int f (int x) { int y = 0; int z = 0; y = 2 * x; z = y + 1; return z / 3;}
你用汇编语言也能做到这些。纯函数并不专属于纯函数式编程语言。你可以用任何语言写出纯函数,但重要的是,你必须也应该允许副作用的存在。
回首历史,你会发现,数学上的理想主义是纯函数编程语言的背后推动力。数学函数简单漂亮,但不幸的是,它们只是在你构建原始纯粹的模型时才好用。否者它们会变得很丑陋。不要被“范畴论”等标语吓倒。我对范畴论了解很多。即使是范畴理论学家自己也称其为“抽象无意义”,因为它们基本上就是用一种怪诞的方式告诉你一些你已经知道的事情!如果你读过 Gottlob Frege 的文章 Function and concept,你会吃惊的发现,在他的这篇论文前的大多数数学家都错误的理解了函数,而这仅仅是刚刚 100 多年前的事。事实上,数学语言上的很多事情都是有问题的。特别是微积分方面。编程语言的设计者们没有理由要盲目的学习数学界。
不要盲目的爱上你的模型
无论任何事情,当走向极端时都是有害的。极端化时,面向对象编程和函数式编程都试图把整个世界装入它们的特有模型中,但这个世界是在完全不依赖我们的大脑思考的情况下运转的。如果以为你有一个锤子,就把所有东西都当成钉子,这明显是不对的。只有通过认清我们的真实世界,才能摆脱信仰对我们的束缚。
不要让世界适应你的模型。让你的模型适应世界。
相关推荐
基于JavaScript的面向对象程序设计研究 本文对基于JavaScript的面向对象程序设计进行了深入研究。研究发现,JavaScript语言具有良好的面向对象特性,特别是在封装性、继承性和多态性等方面。本文对JavaScript的面向...
在《戏说面向对象设计原理》一文中,作者通过一个生动的故事引入了面向对象编程的核心思想:可维护性、可复用性、可扩展性和灵活性。故事发生在三国时期,曹操命令工匠刻版印刷其诗词,但由于多次修改导致工匠不得不...
测绘专业的学生在学习《测绘程序设计》课程时,通常需要学习 C 或 VB 程序设计作为公共基础课,但测绘编程主要采用 C++ 或者 C# 等面向对象编程语言,这两者在编程思想方面存在明显的差异,导致学生在学习过程中存在...
在Java编程语言中,面向...综上所述,多态性是Java面向对象编程中的重要特性,它增强了代码的灵活性和可扩展性,但也需要开发者合理地权衡其带来的好处和潜在问题。理解和掌握多态性对于编写高质量的Java代码至关重要。
面向对象编程(OOP)则是以对象为中心,对象是包含数据(属性)和操作这些数据的方法(函数)的封装体。这种设计方法更加符合人类对世界的认知方式,因为我们在日常生活中也是通过对象来理解和操作世界的。例如,在...
面向对象编程是Java的核心特性,它使得代码更加模块化、可维护和易于扩展。本篇主要探讨了Java中面向对象的高级概念,包括包、抽象类、接口以及多态。 首先,包(Package)是Java中组织类的一种方式,它可以看作是...
多态是面向对象编程(OOP)中的一个核心概念,它允许我们编写更加灵活和可扩展的代码。 一、多态的体现 多态的体现是指父类的引用指向了自己的子类对象。这意味着,我们可以使用父类的引用来指向子类的对象,从而...
在面向对象编程中,类是定义对象属性和行为的基本单元。定义一个类的基本格式如下: ```java public class 类名 { // 可编写0至n个属性 数据类型 变量名1; 数据类型 变量名2; // 可编写0至n个方法 修饰符 ...
比如,文章中提到了一个简单的HelloWorld项目,展示了图形编程界面与对应的Python代码,通过这样的对照学习,学生更容易理解编程思维和面向对象编程思想。 总的来说,文章所探讨的是一种结合人工智能、软硬件实践和...
具体实践案例中,以通信工程专业的《C++面向对象程序设计》课程为例,可以将项目管理的各个环节融入课程考核,让学生参与实际项目开发,锻炼他们自主解决问题和协同合作的能力。这种方式不仅提高了学生的动手能力,...
C++程序设计是一门涵盖知识广泛、抽象度高、功能强大的面向对象编程语言。教学目标在于让学生掌握面向对象设计的基本理念、编程技巧和算法,以提升他们利用计算机解决实际问题的能力。但因为语法复杂,教学难度较大...
C语言是一种功能丰富、表达力强、应用面广、目标程序效率高、可移植性好的高级程序设计语言,同时也是《数据结构》、《面向对象程序设计语言C++》等课程的前导课。然而,由于C语言繁多数据类型和复杂语法结构,使得...
课程内容涵盖了面向对象编程、内存管理、Windows API等复杂主题,需要学生具备较强的逻辑思维和问题解决能力。 针对以上问题,作者提出了教学改革的思路。改革主要包括以下几个方面: 1. 教学方法:鼓励采用案例...
Java 程序设计课程是高高职Java程序设计课程线上线下混合式教学研究的主要对象,课程的教学目标是通过对 Java语言基础知识的系统学习、熟练掌握编程技术和方法,使学生理解和掌握面向对象的程序设计方法。...
2. 继承:继承是面向对象编程中的一种机制,通过继承,可以创建一个新的类,继承自已经存在的类。继承可以使得子类拥有父类的所有特征和行为。 3. 多态:多态是指一种事物具有多种形态,比方猫具有猫类的形态,也...
“Java程序设计”课程是计算机相关专业的一门专业核心课程,它要求学生不仅要掌握面向对象编程的基本思想,还要具备运用Java语言编写程序以解决实际问题的能力。然而,传统的大班教学模式存在诸多问题,如教学内容...
JavaSE(Java Standard Edition)是Java平台的标准版,提供了面向对象编程语言的基本特征和机制。本篇文章总结了JavaSE的主要知识点,涵盖面向对象、类和对象、继承、多态、抽象类和接口、异常处理、IO流等方面。 ...
这本书深入浅出地介绍了Java语言的各个方面,包括基础语法、面向对象编程、集合框架、多线程、网络编程、异常处理等核心概念。源代码是学习这本书的重要辅助资源,可以帮助读者更好地理解和实践书中的例子。 1. **...
在三层结构的系统设计中,通常采用面向对象的软件设计方法。面向对象的设计方法强调数据和功能的封装性、继承性和多态性。通过面向对象的技术,可以将复杂的系统分解为相对独立的对象,每个对象都具有自己的属性和...
C# 是微软公司发布的一种面向对象的、运行于 .NET Framework 之上的高级程序设计语言。它是一种安全的、稳定的、简单的、优雅的,由 C 和 C++衍生出来的面向对象的编程语言。C# 综合了 VB 简单的可视化操作和 C++ 的...