首页 > 其他分享 >Smalltalk 语言(面向对象的鼻祖语言)

Smalltalk 语言(面向对象的鼻祖语言)

时间:2023-12-22 19:01:42浏览次数:33  
标签:语言 对象 代码 ifTrue 面向对象 消息 negated Smalltalk

基础语法

看一下这些基础语法,便能够读懂大部分的代码内容。

  • 注释:用双引号包围。"这是注释"
  • 字符串:用单引号包围。'这是一个字符串'
  • 单个字符:$c
  • 符号(Symbol):#thisIsASymbol 大家也许对符号这个概念比较陌生。简单来说,只要两个符号的值一样,那么它们在内存中也是相同的对象。
  • 变量声明:| a | ,也可以一次声明多个:| a b c |
  • 赋值语句:a := 5
  • 相等性与同一性:相等性使用 = ,相当于 Java 中的 equals() 。同一性使用 == ,即判断内存地址相同。
  • 返回语句:^ a 即其他语言中的 return a
  • 级联:Smalltalk 使用 . 表示语句的末尾,而 ; 用于实现级联的功能。所谓级联,是指可以连续在同一个对象上调用方法,而不必每次都重复写出这个对象。举个例子:
| p |  p := Client new       
    name: 'Jack';        
    age: 32;        
    address: 'Earth'.

方法与类

一个 Smalltalk 中方法定义和调用的例子:

"定义一个方法:使物体围绕某个轴旋转一定角度"
rotateBy: angle around: vector
| result |
result := [...省略具体内容].
^result
"调用这个方法"t rotateBy: a around: v.

基于主流语言的语法,来看看一个方法是以何种逻辑演化成 Smalltalk 的样子的。

先从我们熟悉的形式开始:

t->rotate(a, v);  // In C++
t.rotate(a, v);   // In Java

省略掉一些不影响语义的符号:

t rotate(a, v);    // 省略掉 .
t rotate a, v;     // 省略括号

然后我们发现参数的含义不太清晰,可以给每个参数前面加一个前缀来使含义更加明确:

t rotate by a around v;

但是这样的话,哪个词语是前缀,哪个是参数就不太能分得清。因此我们给前缀加个冒号来区分:

t rotate by: a around: v;

最后,都这样了,方法名字本身也没必要单列出来,可以直接和第一个参数前缀合并起来,就成了 Smalltalk 现在的样子:

t rotateBy: a around: v;

再来看一个复杂点的例子:

a negative | (b between: c and: d)ifTrue: [a := c negated]

它相当于其他语言中的:

if (a < 0 || (c < b && b < d)) {a = -c;}

-cc negated 有所不同,前者只是进行了一次简单的数学运算,后者是在C的基础上调用了negative并返回到C,然后用这个返回的值去操作。


这体现了Smalltalk的核心概念之一:一切皆对象。对比于另一门同样号称「一切皆是对象」的语言 Java,你是不能写出 5.negated() 这种代码的。java中有 基本类型 、封装类型,而Smalltalk中对象的概念贯穿始终,保持了同一性。


在Smalltalk中有另一个重要概念:消息。在上面的例子中称这种写法为 调用对象。但实际上 Smalltalk 中并没有这个概念,而是 给对象发送消息。例如 c negatedSmalltalk 的话来说就是给对象 c 发送了一个名为negative的消息。


在 Smalltalk 中有三种消息,它们在上面的例子中都能体现:

  • 一元(unary)消息:可以理解为一个无参方法,例如上面的 negated 消息。
  • 二元(binary)消息:就是常用的一组计算符号,比如四则运算符还有上面的 | 等逻辑运算符。不过需要注意的是,它的本质还是发送消息而不是直接运算,因此没有运算符优先级的概念。+* 在 Smalltalk 中的优先级是相等的。
  • Keyword 消息:可认为是普通的有参方法,在 Smalltalk 中就是每个参数以冒号连接来表示,比如上面的 rotateBy:around: 还有 between:and: 。这样的消息在 Smalltalk 中被称为 keyword


描述词汇的不同也会带来思维方式的不同,相比于「方法调用」,「发送消息」这个说法会显得更加泛用一些,也可以带来一些更接近本质的思考。

举个例子,如果调用一个不存在的方法,那自然会报错。但如果给一个对象发送一个它不认识的消息,那非得报错吗?我大不了不处理不就行了。


继承实质是面向对象语言中实现代码重用的一种手段,但现在大部分情况下「组合优于继承」早已成为共识。

封装是为了隐藏底层或内部的实现细节,也并不是面向对象独有的概念。


多态在传统面向对象教学中的解释颇为复杂。我们定义一个父类,并让两个不同的子类 override 父类的同一个方法,并编写不同的实现,来说明多态性。但是如果用发送消息的思路来解释就很简单了。给两个不同的对象发送同一个消息,这两个对象会做出不同的反应,这就非常自然而然了,压根不需要牵扯到类的继承之类的概念。


理解 Smalltalk 的核心概念之后,再来看一下怎么声明一个类:

Object subclass: #MyClass      
  instanceVariableNames: '' “实例变量名”
  classVariableNames: ''    “类变量名”
  poolDictionaries: ''      “字典池”
  category: 'Pupeno'        “类别”

大部分编程语言都会使用 class 关键字声明一个类,并用 extends 或类似的关键字来声明继承关系。而Smalltalk 则另辟蹊径。首先,由于一切皆是对象,因此 Object 类也是一个对象;其次,Object 类可以接收名为 subclass: 的消息,创建一个新的对象。无需再引入任何特殊的语法,仅用语言本身的两个核心理念,就十分自洽地把类的概念创建了出来。


不仅仅是定义类,还有常用的分支、循环语句等,在 Smalltalk 中都可以通过发送消息的形式来实现,而无需定义额外的诸如 ifwhile 等关键字。这或许就是 Smalltalk 把类似 subclass: 之类的带参消息都称作 keyword 的原因。它们完全可以替代其他语言中各种关键字的职能。


代码块

继续回到上一节的例子:

a negative | (b between: c and: d)
ifTrue: [a := c negated]

关注这个 [a := c negated] 。这里由中括号包围的部分,大家或许会以为就像是 C++/Java 里跟在 if 语句后面的大括号——对,但不全对。在 Smalltalk 中它被称为代码块,可以放在一个变量里面,自由地控制它的调用时机,也可以把它像参数一样传递。做个简单对比:

"in Smalltalk"
a := [:x | x + 1]       "将一个代码块赋值给 a"
(a value: 10)           "运行这个代码块并传入参数 10"
// in Javascriptlet 
a = function(x) { return x + 1; };
a(10);


控制流

结合 Smalltalk 对象间发送消息的思想和代码块的能力,那么它将变得无所不能。上文中提到 Smalltalk 无需额外的关键字就能实现 ifwhile 等的功能。让我们具体地看一下如何利用这些能力来实现 if 的功能。


首先,我们需要定义出 truefalse 这两个常量:


先定义出 PBoolean 类,然后创建PTruePFalse 两个对象。PTrue 的实例就可以认为是 truefalse 也是同理。

Object subclass: #PBoolean      
  instanceVariableNames: ''      
  classVariableNames: ''      
  poolDictionaries: ''      
  category: 'Pupeno'
PBoolean subclass: #PTrue      
  instanceVariableNames: ''      
  classVariableNames: ''      
  poolDictionaries: ''      
  category: 'Pupeno'
PBoolean subclass: #PFalse      
  instanceVariableNames: ''      
  classVariableNames: ''      
  poolDictionaries: ''      
  category: 'Pupeno'

其次,我们定义 ifTrue:else: 消息。它接受两个代码块作为参数。当 PTrue 类的实例接收到消息时,它执行 ifTrue: 携带的代码块,忽略 else: 携带的代码块。反之亦然。

"PTrue 中定义"
ifTrue: do else: notdo  
  ^ do value
"PFalse 中定义"
ifTrue: notdo else: do  
  ^ do value

再次,我们定义一个 MyClass 对象用作测试,它可以接受 equals: 消息判断两个对象是否相等。为了方便起见,我们永远返回 true 。实际中可以自行实现其业务逻辑。

equals: other  
  ^ PTrue new

最后,我们就可以愉快地使用 if-else 了:

m1 := MyClass new.
m2 := MyClass new.
(m1 equals: m2) ifTrue: [  
    Transcript show: 'They are equal'
] else: [  
    Transcript show: 'They are not equal'
]


总结

本文介绍了Smalltalk中最基础的语言规则与设计思想。它引领了面向对象前沿的概念,它的语言特性直到现在也很有参考、学习的价值。

参考:https://zhuanlan.zhihu.com/p/423372660


标签:语言,对象,代码,ifTrue,面向对象,消息,negated,Smalltalk
From: https://blog.51cto.com/u_16456705/8937750

相关文章

  • 高级程序设计语言
    1.Java语言概述1.1Java与c++的区别Java中对内存的分配是动态的,C语言通过malloc()和free()这两个库函数来分别实现分配内存和释放内存空间的,C++语言中则通过运算符new和delete来分配和释放内存。Java不在所有类之外定义全局变量,而是在某个类中定义一种公用静态的变......
  • 计算机 JAVA 语言的基础小总结
    计算机JAVA语言的基础小总结一维数组和二维数组的定义及初始化在Java中,数组是一种数据结构,用于存储多个数据。数组中的元素是相同类型的数据。数组是一个引用数据类型,数组的变量只是一个引用,数组元素和数组变量在内存里是分开存放的。一维数组的定义和初始化一维数组在Jav......
  • android添加c语言的可执行程序
    在android源码的external目录下添加test目录。在test目录下新建test.c文件和Android.mk文件。test.c文件例如:#include<stdio.h>intmain(){printf("helloworld\n");return0;}Android.mk文件:LOCAL_PATH:=$(callmy-dir)include$(CLEAR_VARS)LO......
  • 自然语言处理:通过API调用各大公司的机器翻译开放平台
    国内大公司做机器翻译做的比较好的有讯飞和百度,这里给出这两个公司机器翻译的开放平台API的介绍:讯飞开放平台:链接:https://www.xfyun.cn/doc/nlp/xftrans_new/API.html#%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E百度翻译平台:链接:https://api.fanyi.baidu.com/doc/21......
  • 梭梭带你彻底搞懂YAML序列化语言
    目录前言简介yaml基本语法规则yaml支持的数据结构有三种基本语法大小写敏感用缩进表示层级关系用#表示注释一个文件中可以包含多个文件的内容数据结构与类型对象(Mapping)数组(Sequence)标量(Scalars)字符串(String)布尔值(Boolean)整数(Integer)浮点数(FloatingPoint)空(Null)时间戳(Timestamp)......
  • Go 语言实现高性能分布式锁
    Go语言实现高性能分布式锁原创 源自开发者 源自开发者 2023-12-2207:31 发表于广东 听全文源自开发者专注于提供关于Go语言的实用教程、案例分析、最新趋势,以及云原生技术的深度解析和实践经验分享。49篇原创内容公众号在分布式系统中,实现跨不同......
  • c语言回溯法实现01背包问题
    w[N],p[N]中直接装的是样例,可以修改数据,别忘记修改N。#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#defineN5//0-1背包,用三种算法实现//动态规划,贪心,回溯,分支限界voidOutput(intbestx[]);intConstraint(intt);floatBound(inti);voidB......
  • (C语言)我的第一个项目:命令行窗口下的学生成绩管理系统
    #include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>//行和列常量#defineROW20#defineCOL83typedefstructstudent{ charid[14]; charname[21]; doublechinese; doublemath; doubleenglish; doublesum;......
  • 数字化医学影像系统源码,采用C语言开发,支持MPR、CPR、MIP、SSD、VR、VE三维图像处理
    PACS系统是医院影像科室中应用的一种系统,主要用于获取、传输、存档和处理医学影像。它通过各种接口,如模拟、DICOM和网络,以数字化的方式将各种医学影像,如核磁共振、CT扫描、超声波等保存起来,并在需要时能够快速调取和使用。PACS系统还提供了辅助诊断和管理功能,可以在不同的影像设备......
  • 大语言模型说明书
    在浩瀚的信息宇宙中,大语言模型如同一颗璀璨的星星正在熠熠生辉。21世纪以来,人工智能可谓是飞速发展,从简单的神经网络到大语言模型、生成式AI,这并非仅仅是一种技术的进步,更是人类智慧的飞跃。大语言模型不仅仅是语言的演化,更是一段充满创新和探索的史诗。就和我一起踏上这场穿越知识......