O GNU Smalltalk é uma implementação da linguagem de programação Smalltalk pelo Projeto GNU.
A implementação, ao contrário de outros ambientes Smalltalk, utiliza arquivos texto para entrada do programa e interpreta os conteúdos como código Smalltalk. Dessa forma, o GNU Smalltalk atua mais como um interpretador ao invés de um ambiente na forma tradicional do Smalltalk.
0 GNU Smalltalk inclui vinculação de nomes para muitas bibliotecas de software livre, incluindo SQLite, libSDL, cairo, gettext e Expat.
Exemplos
Estes exemplos funcionam apenas no GNU Smalltalk 3.0 e versões posteriores. Exemplo do clássico programa Olá Mundo:
'Hello World!' displayNl
Alguns códigos Smalltalk básicos:
"Everything, including a literal, is an object, so this works:" -199 abs "199" 'gst is cool' size "11" 'Slick' indexOf: $c "4" 'Nice Day Isn''t It?' asLowercase asSet asSortedCollection asString "' '?acdeinsty'"
Coleções
Construir e usar uma matriz:
a := #(1 'hi' 3.14 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))"
Construir e usar uma tabela de dispersão:
hash := Dictionary from: { 'water' -> 'wet'. 'fire' -> 'hot' }. hash at: 'fire' "Prints: hot" hash keysAndValuesDo: [ :k :v | ('%1 is %2' % { k. v }) displayNl] "Prints: water is wet fire is hot" hash removeKey: 'water' "Deletes 'water' -> 'wet'"
Blocos e iteradores
Passando um bloco como um parâmetro para que ele seja uma clausura:
"remember a block." remember := [ :name | ('Hello, %1!' % { name }) displayNl]. "When the time is right -- call the closure!" remember value: 'world' "=> 'Hello, world!'"
Retornando as clausuras de um método:
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"
Usando blocos para enviar informações de volta ao chamador:
Integer extend [
ifEven: evenBlock ifOdd: oddBlock [
^self even
ifTrue: [ evenBlock value: self]
ifFalse: [ oddBlock value: self]]]
Invocar o método acima, passando-lhe um bloco:
10 ifEven: [ :n | n / 2] ifOdd: [ :n | n * 3 + 1] "=> 5"
Iterando sobre enumerações e matrizes usando blocos:
array := #(1 'hi' 3.14) array do: [ :item | item displayNl] "=> 1" "=> hi" "=> 3.14" (3 to: 6) do: [ :item | item displayNl] "=> 3" "=> 4" "=> 5" "=> 6"
Um método tal como inject:into: pode aceitar um parâmetro e um bloco. Ele itera sobre cada membro de uma lista, realizando alguma função enquanto retém um agregado. É análogo à função foldl em linguagens de programação funcional. Por exemplo:
#(1 3 5) inject: 10 into: [ :sum :element | sum + element] "=> 19"
No primeiro passo, o bloco recebe 10 (o argumento a injetar) como soma, e 1 (o primeiro elemento da matriz) como elemento. Isso retorna 11. 11, então, se torna a soma no próximo passo, no qual é adicionado 3 para obter 14. 14 é então adicionado a 5, para finalmente obter 19.
Blocos trabalham com muitos métodos embutidos:
(File name: 'file.txt') withWriteStreamDo: [ :file | file nextPutAll: 'Wrote some text.'; nl] "File is automatically closed here" (File name: 'file.txt') linesDo: [ :each | each displayNl] "=> Wrote some text."
Utilizando uma enumeração e um bloco para elevar ao quadrado os números de 1 a 10:
(1 to: 10) collect: [ :x | x squared] "=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]"
Classes
O código a seguir define uma classe chamada Person. Por ser derivada de Magnitude, ela automaticamente define todos os métodos de comparação exceto um (<). Com a adição daquele, asSortedCollection pode ordenar por idade. Note que podemos sobrepor a forma com a qual o objeto é impresso ou exibido (o padrão é compartilhar a representação da impressão do programador e da tela do usuário) ao sobrepor printOn:.
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
O código acima imprime três nomes em ordem reversa de idade:
OrderedCollection (Mark (63) Dan (23) Cod (16))
Exceções
Uma exceção é gerada com uma chamada halt:
self halt
Uma mensagem opcional pode ser adicionada à exceção; há também o error:, que gera um tipo diferente de exceção:
self halt: 'Isso é uma mensagem' self error: 'Isso é uma mensagem'
Existem atualmente invólucros para o método de geração da exceção atual, signal:
Error signal Error signal: 'Argumentos ilegais!'
As exceções são gerenciadas pelos blocos on:do:.
[ Algo a fazer] on: Exception do: [ :ex | handle exception in ex]
Você pode capturar apenas exceções particulares (e suas subclasses):
[ something to do] on: Warning do: [ :ex | handle exception in ex]
É possível usar o objeto Exceção, o qual é disponibilizado à cláusula do manipulador, para sair ou reiniciar o primeiro bloco. Sair é o padrão, mas também pode ser mencionado explicitamente:
[ 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"
