GNU Smalltalk: Difference between revisions

(from wikipedia)
 
(→‎Examples: -source)
Line 6:
These examples only work on GNU Smalltalk 3.0 and later versions. Classic [[Hello world]] example:
 
'Hello World!' displayNl
<source lang="smalltalk">
'Hello World!' displayNl
</source>
 
Some basic Smalltalk code:
 
"Everything, including a literal, is an object, so this works:"
<source lang="smalltalk">
-199 abs "199"
"Everything, including a literal, is an object, so this works:"
-199 abs 'gst is cool' size "19911"
'gst is coolSlick' sizeindexOf: $c "114"
'Nice Day Isn''t It?' asLowercase asSet asSortedCollection asString "' '?acdeinsty'"
'Slick' indexOf: $c "4"
'Nice Day Isn''t It?' asLowercase asSet asSortedCollection asString "' '?acdeinsty'"
</source>
 
===Collections===
Constructing and using an array:
 
a := #(1 'hi' 3.14 1 2 #(4 5))
<source lang="smalltalk">
a := #(1 'hi' 3.14 1 2 #(4 5))
a at: 3 "3.14"
 
a at:reverse 3 "#((4 5) 2 1 "3.14 'hi' 1)"
a reverseasSet "#((4 5) 2 "Set(1 'hi' 3.14 'hi'2 1#(4 5))"
a asSet "Set(1 'hi' 3.14 2 #(4 5))"
</source>
 
Constructing and using a hash table:
 
hash := Dictionary from: { 'water' -> 'wet'. 'fire' -> 'hot' }.
<source lang="smalltalk">
hash at:= Dictionary'fire' from: { 'water' -> 'wet'."Prints: 'fire' -> 'hot' }."
hash at: 'fire' "Prints: hot"
hash keysAndValuesDo: [ :k :v |
 
('%1 is %2' % { k. v }) displayNl ]
hash keysAndValuesDo: [ :k :v |
('%1 is %2' % { k. v }) displayNl ]
"Prints: water is wet
 
fire is hot"
"Prints: water is wet
fire is hot"
hash removeKey: 'water' "Deletes 'water' -> 'wet'"
 
hash removeKey: 'water' "Deletes 'water' -> 'wet'"
</source>
 
===Blocks and iterators===
Parameter-passing a block to be a closure:
 
"remember a block."
<source lang="smalltalk">
remember := [ :name | ("Hello, %1!" % { name }) displayNl ].
"remember a block."
remember := [ :name | ("Hello, %1!" % { name }) displayNl ].
"When the time is right -- call the closure!"
 
remember value: 'world'
"When the time is right -- call the closure!"
remember "=> value:"Hello, 'world'!""
"=> "Hello, world!""
</source>
 
Returning closures from a method:
 
Integer extend [
<source lang="smalltalk">
asClosure [
Integer extend [
| value |
asClosure [
| value |:= self.
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"
</source>
 
Using block to send info back to the caller:
 
Integer extend [
<source lang="smalltalk">
ifEven: evenBlock ifOdd: oddBlock [
Integer extend [
^self even
ifEven: evenBlock ifOdd: oddBlock [
^ ifTrue: [ evenBlock value: self even]
ifTrue ifFalse: [ evenBlockoddBlock value: self ]
]
ifFalse: [ oddBlock value: self ]
]
]
]
"Invoke the above method, passing it a block."
 
10 ifEven: [ :n | n / 2 ] ifOdd: [ :n | n * 3 + 1 ] "=> 5"
"Invoke the above method, passing it a block."
10 ifEven: [ :n | n / 2 ] ifOdd: [ :n | n * 3 + 1 ] "=> 5"
</source>
 
Iterating over enumerations and arrays using blocks:
 
array := #(1 'hi' 3.14)
<source lang="smalltalk">
array do:= #(1[ 'hi':item | item displayNl 3.14)]
"=> 1"
array do: [ :item | item displayNl ]
"=> 1hi"
"=> hi3.14"
"=> 3.14"
(3 to: 6) do: [ :item | item displayNl ]
 
"=> 3"
(3 to: 6) do: [ :item | item displayNl ]
"=> 34"
"=> 45"
"=> 56"
"=> 6"
</source>
 
A method such as ''inject:into:'' can accept both a parameter and a block. It iterates over each member of a list, performing some function on while retaining an aggregate. This is analogous to the [[foldl]] function in [[Haskell]]. For example:
 
#(1 3 5) inject: 10 into: [ :sum :element | sum + element ] "=> 19"
<source lang="smalltalk">
#(1 3 5) inject: 10 into: [ :sum :element | sum + element ] "=> 19"
</source>
 
On the first pass, the block receives 10 (the argument to inject) as sum, and 1 (the first element of the array) as element, This returns 11. 11 then becomes sum on the next pass, which is added to 3 to get 14. 14 is then added to 5, to finally return 19.
Line 118 ⟶ 100:
Blocks work with many built-in methods:
 
(File name: 'file.txt') withWriteStreamDo: [ :file |
<source lang="smalltalk">
file nextPutAll: 'Wrote some text.'; nl ]
(File name: 'file.txt') withWriteStreamDo: [ :file |
"File is automatically closed here"
file nextPutAll: 'Wrote some text.'; nl ]
"File is automatically closed here"
(File name: 'file.txt') linesDo: [ :each |
each displayNl ]
"=> Wrote some text."
 
(File name: 'file.txt') linesDo: [ :each |
each displayNl ]
 
"=> Wrote some text."
</source>
Using an enumeration and a block to square the numbers 1 to 10:
 
(1 to: 10) collect: [ :x | x squared ] "=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]"
<source lang="smalltalk">
(1 to: 10) collect: [ :x | x squared ] "=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]"
</source>
 
===Classes===
Line 138 ⟶ 117:
The following code defines a class named Person. By deriving from Magnitude, it automatically defines all comparison methods except one (<code>&lt;</code>). With the addition of that one, <code>asSortedCollection</code> can sort by age. Note that we can override the way the object is printed/displayed (the default is to share the programmer-print and user-display representation) by overriding <code>printOn:</code>.
 
Magnitude subclass: Person [
<source lang="smalltalk">
| name age |
Magnitude subclass: Person [
| Person class >> name: name age: age |[
Person class >> ^self new name: name; age: age; [yourself
]
^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
 
The above prints three names in reverse age order:
< 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 }) ]
]
 
OrderedCollection (Mark (63) Dan (23) Cod (16) )
group := {
Person name: 'Dan' age: 23.
Person name: 'Mark' age: 63.
Person name: 'Cod' age: 16.
}.
 
group asSortedCollection reverse
</source>
 
The above prints three names in reverse age order:
<source lang="text">
OrderedCollection (Mark (63) Dan (23) Cod (16) )
</source>
===Exceptions===
An exception is raised with a <code>halt</code> call:
 
<source lang="smalltalk">
self halt
</source>
 
An optional message can be added to the exception; there's also <code>error:</code> which raises a different kind of exception:
 
<source lang="smalltalk">
self halt: 'This is a message'
self error: 'This is a message'
</source>
 
These are actually wrappers for the actual exception raising method, <code>signal>:
 
<source lang="smalltalk">
Error signal
Error signal: 'Illegal arguments!'
</source>
 
Exceptions are handled by <code>on:do:</code> blocks.
 
[ something to do ]
<source lang="smalltalk">
on: Exception
[ something to do ]
do: [ :ex | handle exception in ex ]
on: Exception
do: [ :ex | handle exception in ex ]
</source>
 
Of course you can catch only particular exceptions (and their subclasses):
 
[ something to do ]
<source lang="smalltalk">
on: Warning
[ something to do ]
do: [ :ex | handle exception in ex ]
on: Warning
do: [ :ex | handle exception in ex ]
</source>
 
It is possible to use the exception object, which is made available to the handler clause, to exit or resume the first block:
 
[ Error signal: 'foo' ]
<source lang="smalltalk">
on: Error
[ Error signal: 'foo' ]
do: [ :ex | ex return: 5 ]
on: Error
do: [ :ex | ex return: 5 ]
(Warning signal: 'now what?') printNl "=> nil"
 
[ (Warning signal: 'now what?') printNl "=> nil"
printNl ] on: Warning do: [ :ex | ex resume: 5 ] "=> 5"
[ (Warning signal: 'now what?')
printNl ] on: Warning do: [ :ex | ex resume: 5 ] "=> 5"
</source>
 
 
== External links ==
Anonymous user