在我之后重复:“这些是不同的范例”
大声说出20次左右 – 这是我们目前的口头禅.
如果我们真的必须比较苹果和橘子,那么我们至少要考虑“成果”的共同方面在哪里相交.
Java“对象”是Java程序员的基本计算单位.也就是说,一个物体(基本上是一个带有臂和腿的结构,具有封装somewhat more strictly enforced than in C++)是您用来模拟世界的主要工具.您认为“此对象知道/具有数据{X,Y,Z}并在其上执行函数{A(),B(),C()},在任何地方携带数据,并且可以通过调用与其他对象通信函数/方法被定义为它们的公共接口的一部分.它是一个名词,而名词就是东西.“也就是说,您可以围绕这些计算单位确定思维过程.默认情况是对象之间发生的事情按顺序发生,并且崩溃会中断该序列.它们被称为“对象”,因此(如果我们忽视Alan Kay的原始含义),我们得到“面向对象”.
Erlang“进程”是Erlang程序员的基本计算单位.过程(基本上是在其自己的时间和空间中运行的独立顺序程序)是厄兰格为世界建模的主要工具(1).与Java对象如何定义封装级别类似,Erlang进程也定义了封装级别,但在Erlang的情况下,计算单元完全相互隔离.您不能在另一个进程上调用方法或函数,也不能访问其中的任何数据,也不能在与任何其他进程相同的时序上下文中运行,并且无法保证相关的消息接收顺序到可能正在发送消息的其他进程.他们也可能完全在不同的星球上(而且,想到它,这实际上是合理的).它们可以彼此独立地崩溃,而其他过程只有在故意选择受到影响时才会受到影响(甚至这涉及到消息传递:基本上注册接收来自死亡过程的遗书本身并不能保证以任何形式到达相对于整个系统的顺序,您可能会或可能不会选择做出反应).
Java直接在复合算法中处理复杂性:对象如何协同工作来解决问题.它旨在在单个执行上下文中执行此操作,Java中的默认情况是顺序执行. Java中的多个线程表示多个运行的上下文,并且是一个非常复杂的主题,因为不同的时序上下文中的影响活动彼此之间(以及整个系统:因此防御性编程,异常方案等).在Java中说“多线程”意味着与Erlang不同的东西,实际上在Erlang中甚至都没有说过,因为它始终是基本情况.请注意,Java线程暗示与时间有关的隔离,而不是内存或可见引用 – 通过选择私有内容和公共内容来手动控制Java中的可见性;系统的普遍可访问元素必须设计为“线程安全”和可重入,通过排队机制顺序化,或采用锁定机制.简而言之:调度是线程/并发Java程序中的手动管理问题.
Erlang根据执行时间(调度),内存访问和参考可见性分离每个进程的运行上下文,这样做可以通过完全隔离算法来简化算法的每个组件.这不仅仅是默认情况,这是此计算模型下唯一可用的情况.这样做的代价是,一旦处理序列的一部分穿过消息屏障,就永远不知道任何给定操作的顺序 – 因为消息本质上都是网络协议,并且没有方法调用可以保证在给定的内部执行上下文.这类似于为每个对象创建一个JVM实例,并且只允许它们跨套接字进行通信 – 这在Java中会非常麻烦,但是Erlang的设计方式是工作的(顺便说一句,这也是概念的基础)编写“Java微服务”如果一个人抛弃了流行语所带来的网络化包袱 – 默认情况下,Erlang程序是成群的微服务.这完全取决于权衡.
这些是不同的范例.我们可以找到的最接近的共性是,从程序员的角度来看,Erlang进程类似于Java对象.如果我们必须找到一些东西来比较Java线程……好吧,我们根本不会在Erlang中找到类似的东西,因为在Erlang中没有这样的可比概念.击败死马:这些是不同的范例.如果你在Erlang中编写一些非平凡的程序,这将很明显.
请注意,我说“这些是不同的范例”,但甚至没有涉及OOP与FP的主题. “在Java中思考”和“在Erlang中思考”之间的区别比OOP与FP更为重要.
虽然Erlang的“并发导向”或“过程导向”基础确实更接近Alan Kay在创造“面向对象”一词时的想法(2),但这并不是真正的重点. Kay所得到的是,通过将你的同质体切割成离散的块,可以降低系统的认知复杂性,并且隔离是必要的. Java以一种基本上仍然是程序性的方式实现了这一点,但是结构代码围绕一个特殊的语法,而不是高阶调度闭包,称为“类定义”. Erlang通过按对象拆分运行上下文来实现此目的.这意味着Erlang的东西不能相互调用方法,但Java的东西可以.这意味着Erlang的东西可以孤立地崩溃,但Java的东西却不能.从这个基本差异中产生了大量的影响 – 因此“不同的范式”.权衡.
脚注:
>顺便提一下,Erlang实现了“the actor model”的版本,但我们不使用这个术语,因为Erlang早于该模型的普及.当他设计Erlang并写了his thesis时,Joe没有意识到这一点.
> Alan Kay已经说了很多关于what he meant when he coined the term“面向对象”的内容,最有趣的是his take关于消息传递(从一个独立进程单向通知,有自己的时间和内存到另一个)VS调用(顺序中的函数或方法调用)具有共享内存的执行上下文) – 以及如何在编程语言和下面的实现所呈现的编程接口之间模糊一点.