GNU Smalltalk

GNU Smalltalk是Smalltalk编程语言的GNU计划实现。
这个实现不同于其他Smalltalk环境，使用文本文件作为程序输入，并将其内容解释为Smalltalk代码。在这种方式下，GNU Smalltalk表现得更像是一种解释器，而非传统Smalltalk方式下的一种环境。GNU Smalltalk包括了对很多自由软件库的绑定，包括SQLite、libSDL、cairo、gettext和等。
简单例子.
下面的例子可工作在GNU Smalltalk 3.0和以后版本上。经典的Hello, World!例子：
'Hello, World!' displayNl
GNU Smalltalk声明了三个文件：codice_1、codice_2和codice_3，作为文件串流类（codice_4）的全局实例，并绑定了适合传递给C虚拟机的值。对象类（codice_5）定义了特有于GNU Smalltalk的四个方法：codice_6、codice_7、codice_8和codice_9。它们对接收者做一次codice_10或codice_11至codice_12对象。这个对象是文本搜集器类（codice_13）的唯一实例，它通常将写操作委托给codice_2。 
一些基本的Smalltalk代码：
"所有东西，包括一个文字，都是一个对象，所以如下可行:"
-199 abs. "199"
'gst is cool' size. "11"
'Slick' indexOf: $c. "4"
'Nice Day Isn"t It?' asLowercase asSet asSortedCollection asString "' "?acdeinsty'"
两个codice_15包围的是注释；codice_16是字符常量codice_17；两个codice_18包围的是字符串，字符串中的codice_15是codice_18的转义序列。
搜集.
构造和使用一个数组：
a := #(1 'hi' 3.14e0 1 2 (4 5)).
a at: 3. "3.14"
a reverse. "((4 5) 2 1 3.14 'hi' 1)"
a asSet "Set(1 'hi' 3.14 2 (4 5))"
构造和使用一个散列表，它是散列搜集类（codice_21）的子类即字典类（codice_22）的实例：
hash := Dictionary from: { 'water' -&gt; 'wet'. 'fire' -&gt; 'hot' }.
hash at: 'fire' "'hot'".
hash keysAndValuesDo:
 [ :k :v | ('%1 is %2' % { k. v }) displayNl ].
"=&gt; fire is hot
 =&gt; water is wet"
"删除 'water' -&gt; 'wet'"
hash removeKey: 'water'
GNU Smalltalk在字符串类（codice_23），和作为它的超类的数组式搜集类（codice_24）之间，又介入了特有的字符数组类（codice_25），它的codice_26方法，将其接收者中具有的特殊转义序列，替换为由参数给出的搜集中的元素，其中codice_27被替代为这个搜集的第codice_28个元素（codice_29或codice_30）。这里给它的搜集，是在codice_31和codice_32之间包围的，当前Smalltalk变体一般都提供的动态数组，其中的元素可以在运行时间求值。
块和迭代器.
参数传递到是为闭包的一个块：
"remember被绑定到一个块."
remember := [ :name | ('Hello, %1!' % { name }) displayNl ].
"时机成熟时 -- 调用这个闭包!"
remember value: 'world'
"=&gt; Hello, world!"
从一个方法返回由两个闭包构成的一个数组：
Integer extend [
 asClosure [
 | value |
 value := self.
].
blocks := 10 asClosure.
setter := blocks first.
getter := blocks second.
getter value. "10"
setter value: 21. "21"
getter value "21"
这里用codice_33为现存的类扩展新方法是GNU Smalltalk特有的语法。
下面的考拉兹猜想例子，展示将两个块传递给接收者，并将结果信息发送回到调用者：
Integer extend [
 ifEven: evenBlock ifOdd: oddBlock [
 ^self even
 ifTrue: [ evenBlock value: self ]
 ifFalse: [ oddBlock value: self ]
].
10 ifEven: [ :n | n / 2 ] ifOdd: [ :n | n * 3 + 1 ] "5"
搜集类（codice_34）的codice_35方法，将接收者的每个元素传递给一个块来求值，返回这些结果的搜集。这类似于函数式编程语言中map函数。例如计算从codice_36到codice_37的平方：
(1 to: 10) collect: [ :x | x squared ] "(1 4 9 16 25 36 49 64 81 100 )"
可迭代类（codice_38）定义了由子类实现的codice_39方法，将一个块迭代于接收者的每个元素之上。这也被称为隐式迭代器。例如迭代于数组和区间之上：
array := #(1 'hi' 3.14e0).
array do: [ :item | item displayNl ].
"=&gt; 1"
"=&gt; hi"
"=&gt; 3.14"
(3 to: 6) do: [ :item | item displayNl ]
"=&gt; 3"
"=&gt; 4"
"=&gt; 5"
"=&gt; 6"
可迭代类的codice_40方法，接受一个参数和一个块二者；它迭代于接收者的每个元素之上，在其上执行某个函数并保持结果为一个聚集。这类似于函数式编程语言中foldl函数。这个方法是凭借调用codice_39方法实现的。例如：
在第一个趟时，这个块接受codice_37（要注入的实际参数）作为codice_43 ，和codice_36（这个数组的第一个元素）作为元素，结果为codice_45。codice_45接着成为在下一趟时的codice_43，这时向它加上codice_48得到codice_49。codice_49接着加上codice_51，最终返回codice_52。
块可以和很多内建方法一起工作，下面例子向一个文件写一行文本，然后再读取它的每一行并显示：
(File name: 'file.txt') withWriteStreamDo:
 [ :file | file nextPutAll: 'Wrote some text.'; nl ]
(File name: 'file.txt') readStream linesDo:
 [ :each | each displayNl ] ; close
"=&gt; Wrote some text."
文件类（codice_53）的特有于GNU Smalltalk的codice_54方法，返回具有绝对路径的文件名。GNU Smalltalk有特有的文件路径类（codice_55），它的codice_56方法，对接收者调用codice_57方法打开一个只写的文件串流类（codice_4）实例，在其上调用一个块，并在这个块的动态范围结束处保证（codice_59）关闭这个串流；它的codice_60方法，在接收者上打开一个只读的文件串流类（codice_4）实例。
串流类（codice_62）的特有于GNU Smalltalk的codice_63方法，对它的接收者的每一行都求值它的参数块一次。 在GNU Smalltalk中，文件串流类（codice_4）的超类，不再是作为可定位串流类（codice_65）子类的读写串流类（codice_66），而是其特有的作为串流类（codice_62）子类的文件描述符类（codice_68），它的codice_69方法关闭这个文件。
类.
GNU Smalltalk建立新类采用特有的语法形式：
超类名字 subclass: 新类名字 [
 | 诸实例变量 |
 pragmas
 消息模式1 [ 诸语句 ]
 消息模式2 [ 诸语句 ]
 类变量1 := 表达式.
 类变量2 := 表达式.
]
类似的，为现存的类扩展新方法采用特有的语法形式：
类表达式 extend [
]
在Smalltalk有关书籍中有一个常见版式约定，将一个类中的方法引用为codice_70，这不是Squeak/Pharo语法的一部份，GNU Smalltalk将codice_71作为定义类方法的语法形式。
下面的代码定义叫做codice_72的一个类，这个类有两个实例变量codice_73和codice_74，它们有各自的变异子与访问子。定义了有两个关键字参数的类方法，用来创建新的类实例。定义了单独用codice_74来进行比较的codice_76方法，通过从codice_77派生，这个类自动继承了所有的其他比较方法的定义。这个类还通过覆写codice_10的方式，定制了这个对象的打印（codice_6）/显示（codice_80）方式：
Magnitude subclass: Person [
 | name age |
 Person class » name: name age: age [
 ^self new name: name; age: age; yourself
 &lt; aPerson [ ^self age &lt; aPerson age ]
 name [ ^name ]
 name: value [ name := value ]
 age [ ^age ]
 age: value [ age := value ]
 printOn: aStream [ aStream nextPutAll: ('%1 (%2)' % { name. age }) ]
group := {
 Person name: 'Dan' age: 23.
 Person name: 'Mark' age: 63.
 Person name: 'Cod' age: 16
group asSortedCollection reverse
这里用codice_81方法对搜集进行排序，然后用codice_82方法来做反转。最终结果是按codice_74反序打印了三个人的信息：
OrderedCollection (Mark (63) Dan (23) Cod (16) )
异常.
要发起能够捕获的异常，需要调用异常类（codice_84）及其子类的codice_85或codice_86方法。错误类（codice_87）表示不可恢复的致命错误，警告类（codice_88）表示重要但可恢复的错误，停机类（codice_89）表示通常是漏洞（bug）的可恢复错误。例如：
Error signal.
Error signal: 'Illegal arguments!'
异常通过块闭包（codice_90）的codice_91方法来处理，还可以只捕获特定的异常（和它们的子类）：
[ 做些事情
] on: Exception do: [ :ex |
 处理ex中异常
[ 做些事情
] on: Warning do: [ :ex |
 处理ex中异常
处理器子句使用它能获得的异常对象，可以退出或恢复一个块；退出是缺省的，但也可以显式的指示：
[ Error signal: 'foo' 
] on: Error do: [ :ex |
 ex return: 5
(Warning signal: 'now what?') printNl "=&gt; nil"
[ (Warning signal: 'now what?') printNl
] on: Warning do: [ :ex |
 ex resume: 5 
] "=&gt; 5"
在因异常状况而要进入调试器，可以调用对象类（codice_5）的codice_93方法，或增加了一个消息参数的codice_94方法；这二者实际上调用了对象类的codice_95方法，它通过原始操作停止执行启动调试器，并展示这个错误消息：
self halt. "halt encountered"
self halt: 'This is a message'.
self error: 'This is a message'