Smalltalk编程语言入门






4.70/5 (35投票s)
使用最适合的语言学习面向对象编程的技巧
什么是Smalltalk?
Smalltalk是一种面向对象的编程语言,拥有悠久的历史和辉煌的传承。它诞生于20世纪70年代的Xerox PARC,由Alan Kay、Dan Ingalls和Adele Goldberg等杰出的远见卓识者团队创造。Smalltalk的诞生是为了探索如何教儿童编程。可以理解,它是一门非常小巧、简单的语言,是主流编程语言中最简单的一种。
要理解Smalltalk哲学的精髓,请观看Alan Kay致敬Ted Nelson的这段视频。Alan Kay的《Smalltalk的早期历史》(©1993 ACM)也提供了更多见解。
引用Smalltalk是对计算机本身概念的一种递归。 它没有将“计算机事务”划分为比整体弱的各个部分——例如数据结构、过程和函数(这些是编程语言的常用附属品)——而是将每个Smalltalk对象视为计算机全部可能性的递归。因此,它的语义就像有成千上万台计算机通过非常快速的网络连接在一起。
和
引用Smalltalk的贡献是一种新的设计范式——我称之为面向对象——用于解决专业程序员面临的大型问题,并使新手用户能够解决小型问题。面向对象设计是成功地定性提高建模日益复杂的动态系统和用户关系效率的尝试,而这种复杂性是由硅爆炸带来的。
以下是Smalltalk的一些伟大成就
- Smalltalk向世界介绍了语言虚拟机,Java和Ruby也是基于此的。
- Smalltalk开创了JIT(即时)编译。
- 第一个现代IDE(集成开发环境)就源于Smalltalk,它包括文本编辑器、类浏览器、对象检查器和调试器。
- Smalltalk是第一个支持实时编程和高级调试技术(如在执行过程中进行即时检查和代码更改)的图形化语言工具,并且格式非常用户友好。
- 自Smalltalk-80(1980年)以来,它就拥有了一等公民函数和闭包,这使得Smalltalk在函数式编程方面也非常出色。
- Smalltalk引入了软件架构模式MVC(模型-视图-控制器)。
- 在很大程度上,Smalltalk促成了测试驱动开发(TDD)和极限编程(XP)的出现,这两种方法在当今标准的敏捷实践中都极具影响力。
- Smalltalk使“鸭子类型”成为家喻户晓的概念。
- Smalltalk开创了面向对象数据库的发展,GemStone/S是其中的一个绝佳范例。
- Smalltalk为我们带来了第一个重构浏览器。
- Smalltalk在图形用户界面(GUI)和“所见即所得”(WYSIWYG)用户界面的开发中发挥了重要作用。
- 史蒂夫·乔布斯受到Xerox PARC的GUI和WIMP(窗口、图标、菜单、指针)的启发,彻底调整了苹果公司的战略;GUI是Smalltalk工作的直接产物。
Smalltalk曾经是一种非常流行的语言。它于1981年8月首次亮相,登上了《BYTE》杂志的封面。
从那时起,Smalltalk直接启发了一代其他OOP语言,包括Objective-C、Erlang、CLOS、Ruby、Python、Perl、PHP、Dart、Java、Groovy和Scala。苹果公司甚至为Macintosh创建了Smalltalk。
Smalltalk的流行度在20世纪90年代达到顶峰,当时它是C++之后最流行的OOP语言。根据1995年IDC的报告,OOP语言的市场份额为:
- C++ — 71.3%
- Smalltalk — 15.1%
- Objective-C — 5.7%
- Object Pascal — 4.2%
- CLOS — 2.5%
- Eiffel — 1.1%
- 其他 — 0.2%
这是《Computerworld》1995年11月6日的页面,展示了Smalltalk和C++的竞争。
Smalltalk非常适合商业用途,因此在20世纪90年代,IBM选择Smalltalk作为其VisualAge企业级计划的核心,旨在取代COBOL。:
在21世纪初,美国联合军事部门使用Smalltalk编写了一个名为JWARS的百万行代码的战争模拟程序。它的性能甚至超过了美国空军用C++编写的类似模拟程序STORM。这本身就令人惊叹地证明了该语言的能力。
如今,Smalltalk仍被全球的企事业单位使用。其中一些比较著名的用户包括:
- JP Morgan
- Desjardins
- UBS
- Florida Power & Light
- Texas Instruments
- Telecom Argentina
- Orient Overseas Container Lines
- BMW
- Siemens AG
这只是举几个例子。在我自己的国家,Smalltalk被加拿大国家密码学机构通信安全局(CSE)使用。
Cincom、Instantiations和GemTalk Systems是主要的Smalltalk供应商。
根据Namcook Analytics的这项研究(表16,以“经济生产力”衡量,即交付1000个功能点所需的工作小时数),Smalltalk是所有主流编程语言中生产力最高的。
- C — 26,273
- Fortran — 22,394
- JavaScript — 15,929
- Forth — 14,636
- Haxe — 14,636
- Lisp — 14,636
- C++ — 12,697
- Go — 12,697
- Java — 12,697
- PHP — 12,697
- Python — 12,697
- C# — 12,309
- Dart — 11,620
- F# — 11,312
- Ruby — 11,312
- Erlang — 10,758
- Elixir — 9,845
- Haskell — 9,845
- Julia — 9,465
- Perl — 9,465
- Delphi — 8,289
- Objective-C — 7,848
- Visual Basic — 7,848
- Eiffel — 7,156
- Smalltalk — 6,879
揭秘面向对象编程
正如Alan Kay所说:
Smalltalk是一种软件互联网
类似于ARPA互联网的思想:通过虚拟网络普遍连接的虚拟计算机
只有对象(对象由对象组成,网络由对象组成,等等)
(没有应用程序,没有文件系统,只有虚拟计算机的协同作用)
语言是对象之间消息的语言
有些对象充当组合对象的场所
对象可以在一个地方被查看并相互集成
这个想法也直接启发了Erlang语言的设计,Erlang语言可以根据Alan Kay的构想被称为“面向对象”语言。
一个对象非常类似于一台计算机,它拥有自己的私有内部状态和通信协议。你通过发送消息来与对象通信。你通过发送消息来要求对象为你做某事,它会做出响应,就像网络中的真实计算机服务器一样。并且,就像在真实的计算机服务器中一样,你无法窥探它的内部状态。
对象不是抽象数据类型
……其中抽象数据类型是数据结构的一种高级术语。
像Java和C++这样的OOP语言是Alan Kay的OOP构想的杂交产物。它们使得OOP比实际情况更难,并且是许多人困惑的无尽源头。 正如Robert C. Martin在《OOP vs FP》中所说,对象是函数的集合,而不是数据的集合。对象不是数据结构。
在Smalltalk中,继承不是强制的。你可以根据你的编程解决方案使用组合或聚合。关于继承“缺陷”的任何歇斯底里都只是歇斯底里……和无知。作为一种工具,继承在许多情况下是适用和恰当的,例如GUI编程。特别是当你将继承用作*专业化*的手段,而不是*代码重用*的手段时。
开始使用Pharo
Smalltalk有许多不同的版本。我将在这里讨论的是Pharo。它是Smalltalk的一个开源变体,已现代化以适应21世纪。
Pharo联盟致力于使该语言达到企业级。一些著名的联盟成员是:
- JPMorgan Chase,一家主要的美国银行和金融服务公司
- Thales,一家专注于航空航天、国防和安全领域的法国大型工程公司
- GemTalk Systems,一家领先的面向对象数据库管理系统供应商
- Inria,法国计算机科学与自动化研究所
- ESUG(欧洲Smalltalk用户组)
安装Pharo
从http://pharo.org/web/download,你可以找到适用于Windows、macOS和Linux的下载。你实际下载的是Pharo Launcher,一个强大的工具,可以让你创建各种Pharo镜像。然后你可以根据需要启动任何一个镜像。
对于Linux,你需要cd到下载Pharo Launcher的目录并执行脚本。
cd pharo-location-folder
./pharo
你可以将此放入一个shell脚本(我将其命名为start),并通过设置权限(查看脚本文件的属性)将其作为程序运行。
启动Pharo镜像
当你启动Pharo Launcher时,你会看到两个部分:“模板”和“现有镜像”(最初为空)。在“模板”方面,选择最新的稳定官方发行版(撰写本文时为Pharo 6.1)。右键单击并选择“创建镜像”。
要启动任何“现有镜像”,请右键单击并选择“启动”。非常简单。
熟悉Pharo IDE
Pharo的系统浏览器是Pharo编程系统的主要界面。它非常类似于当今的IDE,如Eclipse和IntelliJ IDEA,只是更简单、更优雅。要打开系统浏览器,请在空白处单击以调出World菜单,然后选择System Browser。
系统浏览器由几个窗格组成:
- Packages窗格:显示所有类别的逻辑分组。
- Classes窗格:显示特定软件包的所有类。
- Protocols窗格:显示特定类方法的逻辑分组。
- Methods窗格:显示特定协议的方法。
- Edit窗格:你可以在此处查看、编辑或创建新方法和类。
- Quality Assistant窗格:你可以在此处查看关于你当前正在编辑的任何内容的有用提示。
现在,你将创建经典的“Hello World”程序。首先,你需要为它创建一个软件包和类。类名应为“Greeter
”,软件包名应为“HelloWorld
”。在Edit窗格中编辑或输入以下内容:
Object subclass: #Greeter
instanceVariableNames: ''
classVariableNames: ''
package: 'HelloWorld'
别忘了按Ctrl-S或Cmd-S(Mac)保存。
现在,你需要为你的Greeter
类创建一个方法或函数。标准的第一个方法是“initialize”,它在Greeter
类被实例化时调用。为简单起见,我们跳过此步骤。
创建一个名为“sayIt
”的方法,并在该方法中打印“Hello World
”。
在Protocols窗格中选择“no messages”,这样IDE就知道你正在处理方法。在Edit窗格中编辑或输入以下内容:
sayIt Transcript show: 'Hello World'
然后保存。
你的Hello World程序将打印到Transcript(类似于控制台)。要打开Transcript,请在空白处单击以调出World菜单,选择Tools,然后选择Transcript。
最后,要运行你的程序,你需要打开Playground。要打开Playground,请在空白处单击以调出World菜单,然后选择Playground。在Playground中,输入以下文本:
Greeter new sayIt
选择文本,右键单击并选择“Do it”。你应该立即在Transcript窗口中看到“Hello World”。
恭喜!你已经创建了你的第一个Pharo程序。
特性和语法
Smalltalk的语法几乎完全基于*消息传递*:向对象发送消息。甚至其控制结构,如条件语句和循环,也是通过消息实现的。这使得该语言非常简单,其完整语法可以写在一张明信片上!
有三种消息:一元消息、二元消息和关键字消息(接收参数)。对象在前,消息在后。例如:
Date today. "unary message, which requires no other information"
1 + 3. "binary message, which sits between the receiver object and argument object"
window alert: 'hello world!'. "keyword message, which takes one or more arguments"
顺便说一句,在Smalltalk中,注释是用双引号分隔的。
优先级规则是先执行一元消息,然后是二元消息,最后是关键字消息。否则,操作从左到右执行。这可能会使算术看起来有点奇怪:
5 + 3 * 2. "produces 16, not 11. You can force conventional arithmetic precedence with parentheses:"
5 + (3 * 2). "a bit unusual but not a hardship"
为了说明Smalltalk中的控制结构,这里是几种语言中的if语句:
"Smalltalk if statement"
time > 120
ifTrue: [Transcript show: 'Time expired.'; cr.
time := 0]
ifFalse: [Transcript show: 'Time remaining: ',
(120 - time) printString, ' minutes'; cr]
# Python if statement
if time > 120:
print 'Time expired.'
time = 0
else:
print 'Time remaining: ', 120 - time, ' minutes'
/* C language if statement */
if (time > 120) {
printf("Time expired.\n");
time = 0;
}
else
printf("Time remaining: %i minutes\n", 120 - time);
(在Smalltalk中,逗号运算符执行*字符串*连接。cr
消息插入回车符。)
Smalltalk是*动态类型*的。
这使得Smalltalk与Python、JavaScript、Ruby、Perl、PHP、Clojure、Elixir、Racket等其他动态类型语言一样灵活和敏捷。
Smalltalk是*反射*的。
这意味着Smalltalk程序能够在运行时检查自身的结构和计算。这赋予了巨大的能力,允许程序通过新类和方法来扩展自身,或者询问“是谁将这条消息发送给我的?”
计算反射用于实现一种强大的错误处理方式。当一个对象接收到一个它不理解的消息时,它会收到一个doesNotUnderstand:
消息,以及对原始消息的重构。程序可以对doesNotUnderstand:
消息执行许多操作,包括用新功能扩展自身!
Smalltalk是*基于镜像*的。
Smalltalk镜像允许你在任何时候保存程序的执行状态,并在之后从你离开的地方精确地恢复执行!这与VMware和VirtualBox等系统虚拟化软件中的系统镜像工作方式非常相似。这也与Web浏览器DOM或Excel电子表格的工作方式类似。
镜像持久化可以作为一种数据库,将程序中的所有数据持久化到硬盘。无需纠结于ORM或第三方数据库产品。
Smalltalk拥有*实时编码*的IDE。
你可以在程序运行时修改它!实时编码和调试是一种强大的编程方式,也是Smalltalk生产力极高的主要原因。
Smalltalk拥有*lambda*。
这使得Smalltalk也成为一种函数式语言,只是它没有*不可变性*。(Pharo现在支持不可变性。)
摘要
在Smalltalk流行度达到顶峰两个十多年后,我们是时候重新审视这门语言了。它是学习面向对象编程的理想方式。它是提高编程生产力的绝佳途径。而且,它是你在编程中最能获得乐趣的方式。