GNU Smalltalk

GNU SmalltalkSmalltalk編程語言GNU計劃實現。

GNU Smalltalk
編程範型面向對象, 腳本
語言家族Smalltalk
實作者Steve Byrne(直到1.1.5),
Paolo Bonzini(自從1.6)[1]
面市時間2003年1月12日,​21年前​(2003-01-12
當前版本
  • 3.2.5(2013年4月8日;穩定版本)[2]
  • 3.2.91(2015年11月7日;預覽版本)
編輯維基數據鏈接
操作系統UnixLinux, Cygwin, Mac OS X/Darwin
許可證GPL(針對虛擬機) + LGPL(針對類庫和映像)
文件擴展名.st
網站https://www.gnu.org/software/smalltalk/
影響語言
Smalltalk-80, Ruby[3]

這個實現不同於其他Smalltalk環境,使用文本文件作為程序輸入,並將其內容解釋為Smalltalk代碼[5]。在這種方式下,GNU Smalltalk表現得更像是一種解釋器,而非傳統Smalltalk方式下的一種環境[6]。GNU Smalltalk包括了對很多自由軟件庫的綁定,包括SQLitelibSDLcairogettextExpat英語Expat (library)[7]

簡單例子

下面的例子可工作在GNU Smalltalk 3.0和以後版本上。經典的Hello, World!例子:

'Hello, World!' displayNl

GNU Smalltalk聲明了三個文件:stdinstdoutstderr,作為文件串流類(FileStream)的全局實例,並綁定了適合傳遞給C虛擬機的值。對象類(Object)定義了特有於GNU Smalltalk的四個方法:printprintNlstorestoreNl。它們對接收者做一次printOn:storeOn:Transcript對象。這個對象是文本搜集器類(TextCollector)的唯一實例,它通常將寫操作委託給stdout

一些基本的Smalltalk代碼:

"所有东西,包括一个文字,都是一个对象,所以如下可行:"
-199 abs.                                               "199"
'gst is cool' size.                                     "11"
'Slick' indexOf: $c.                                    "4"
'Nice Day Isn''t It?' asLowercase asSet asSortedCollection asString "' ''?acdeinsty'"

兩個"包圍的是注釋;$c是字符常量c;兩個'包圍的是字符串,字符串中的'''轉義序列

搜集

構造和使用一個數組

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))"

構造和使用一個散列表,它是散列搜集類(HashedCollection)的子類即字典類(Dictionary)的實例:

hash := Dictionary from: { 'water' -> 'wet'. 'fire' -> 'hot' }.
hash at: 'fire'     "'hot'".

hash keysAndValuesDo:
       [ :k :v | ('%1 is %2' % { k. v }) displayNl ].
"=> fire is hot
 => water is wet"

"删除 'water' -> 'wet'"
hash removeKey: 'water'

GNU Smalltalk在字符串類(String),和作為它的超類的數組式搜集類(ArrayedCollection)之間,又介入了特有的字符數組類(CharacterArray),它的%方法,將其接收者中具有的特殊轉義序列,替換為由參數給出的搜集中的元素,其中%n被替代為這個搜集的第n個元素(1 <= n <= 9A <= n <= Z)。這裡給它的搜集,是在{}之間包圍的,當前Smalltalk變體一般都提供的動態數組,其中的元素可以在運行時間求值。

塊和迭代器

參數傳遞到是為閉包的一個塊:

"remember被绑定到一个块."
remember := [ :name | ('Hello, %1!' % { name }) displayNl ].

"时机成熟时 -- 调用这个闭包!"
remember value: 'world'
"=> Hello, world!"

從一個方法返回由兩個閉包構成的一個數組:

Integer extend [
    asClosure [
        | value |
        value := self.
        ^{ [ :x | value := x ]. [ value ] }
    ]
].
 
blocks := 10 asClosure.
setter := blocks first.
getter := blocks second.
getter value.       "10"
setter value: 21.   "21"
getter value        "21"

這裡用extend為現存的類擴展新方法是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"

搜集類(Collection)的collect:方法,將接收者的每個元素傳遞給一個塊來求值,返回這些結果的搜集。這類似於函數式編程語言中map函數。例如計算從110的平方:

(1 to: 10) collect: [ :x | x squared ] "(1 4 9 16 25 36 49 64 81 100 )"

可迭代類(Iterable)定義了由子類實現的do:方法,將一個塊迭代於接收者的每個元素之上。這也被稱為隱式迭代器。例如迭代於數組和區間之上:

array := #(1 'hi' 3.14e0).
array do: [ :item | item displayNl ].
"=> 1"
"=> hi"
"=> 3.14"

(3 to: 6) do: [ :item | item displayNl ]
"=> 3"
"=> 4"
"=> 5"
"=> 6"

可迭代類的inject:into:方法,接受一個參數和一個塊二者;它迭代於接收者的每個元素之上,在其上執行某個函數並保持結果為一個聚集。這類似於函數式編程語言中foldl函數。這個方法是憑藉調用do:方法實現的。例如:

#(1 3 5) inject: 10 into: [ :sum :element | sum + element ] "19"

在第一個趟時,這個塊接受10(要注入的實際參數)作為sum ,和1(這個數組的第一個元素)作為元素,結果為1111接着成為在下一趟時的sum,這時向它加上3得到1414接着加上5,最終返回19

塊可以和很多內建方法一起工作,下面例子向一個文件寫一行文本,然後再讀取它的每一行並顯示:

(File name: 'file.txt') withWriteStreamDo:
    [ :file | file nextPutAll: 'Wrote some text.'; nl ]

(File name: 'file.txt') readStream linesDo:
    [ :each | each displayNl ] ; close
"=> Wrote some text."

文件類(File)的特有於GNU Smalltalk的name:方法,返回具有絕對路徑的文件名。GNU Smalltalk有特有的文件路徑類(FilePath),它的withWriteStreamDo:方法,對接收者調用writeStream方法打開一個只寫的文件串流類(FileStream)實例,在其上調用一個塊,並在這個塊的動態範圍結束處保證(ensure:)關閉這個串流;它的readStream方法,在接收者上打開一個只讀的文件串流類(FileStream)實例。

串流類(Stream)的特有於GNU Smalltalk的linesDo:方法,對它的接收者的每一行都求值它的參數塊一次。 在GNU Smalltalk中,文件串流類(FileStream)的超類,不再是作為可定位串流類(PositionableStream)子類的讀寫串流類(ReadWriteStream),而是其特有的作為串流類(Stream)子類的文件描述符類(FileDescriptor),它的close方法關閉這個文件。

GNU Smalltalk建立新類採用特有的語法形式:

超类名字 subclass: 新类名字 [
    | 诸实例变量 |
    pragmas
    消息模式1 [ 诸语句 ]
    消息模式2 [ 诸语句 ]
    ...
    类变量1 := 表达式.
    类变量2 := 表达式.
    ...
]

類似的,為現存的類擴展新方法採用特有的語法形式:

类表达式 extend [
    ...
]

在Smalltalk有關書籍中有一個常見版式約定,將一個類中的方法引用為类名字 >> 方法名字,這不是Squeak/Pharo語法的一部份,GNU Smalltalk將类名字 class >> 方法名字作為定義類方法的語法形式。

下面的代碼定義叫做Person的一個類,這個類有兩個實例變量nameage,它們有各自的變異子與訪問子。定義了有兩個關鍵字參數的類方法,用來創建新的類實例。定義了單獨用age來進行比較的<方法,通過從Magnitude派生,這個類自動繼承了所有的其他比較方法的定義。這個類還通過覆寫printOn:的方式,定製了這個對象的打印(print)/顯示(display)方式:

Magnitude subclass: Person [
    | name age |
    Person class >> name: name age: age [
        ^self new name: name; age: age; yourself
    ]

    < aPerson [ ^self age < 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

這裡用asSortedCollection方法對搜集進行排序,然後用reverse方法來做反轉。最終結果是按age反序打印了三個人的信息:

OrderedCollection (Mark (63) Dan (23) Cod (16) )

異常

要發起能夠捕獲的異常,需要調用異常類(Exception)及其子類的signalsignal:方法。錯誤類(Error)表示不可恢復的致命錯誤,警告類(Warning)表示重要但可恢復的錯誤,停機類(Halt)表示通常是漏洞(bug)的可恢復錯誤。例如:

Error signal.
Error signal: 'Illegal arguments!'

異常通過塊閉包(BlockClosure)的on:do:方法來處理,還可以只捕獲特定的異常(和它們的子類):

[ 做些事情
] 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     "=> nil"

[ (Warning signal: 'now what?') printNl
] on: Warning do: [ :ex |
    ex resume: 5 
]                "=> 5"

在因異常狀況而要進入調試器,可以調用對象類(Object)的halt方法,或增加了一個消息參數的halt:方法;這二者實際上調用了對象類的error:方法,它通過原始操作停止執行及或英語And/or啟動調試器,並展示這個錯誤消息:

self halt. "halt encountered"
self halt: 'This is a message'.
self error: 'This is a message'

參見

引用

  1. ^ AUTHORS. [2022-02-10]. (原始內容存檔於2022-03-18). 
  2. ^ https://ftp.gnu.org/gnu/smalltalk/.
  3. ^ Regular expression matching. [2022-02-09]. (原始內容存檔於2022-02-18). The GNU Smalltalk regular expression library is derived from GNU libc, with modifications made originally for Ruby to support Perl-like syntax. 
  4. ^ index : smalltalk.git. [2022-02-10]. (原始內容存檔於2022-03-07). 
  5. ^ Syntax of GNU Smalltalk. [2022-02-09]. (原始內容存檔於2022-02-18). 
  6. ^ Computer Programming using GNU Smalltalk. [2022-02-09]. (原始內容存檔於2022-04-06). 
  7. ^ Packages. [2022-02-09]. (原始內容存檔於2022-02-18). 

外部連結