GNU Smalltalk: Difference between revisions

Content added Content deleted
(from wikipedia)
 
(→‎Examples: -source)
Line 6: Line 6:
These examples only work on GNU Smalltalk 3.0 and later versions. Classic [[Hello world]] example:
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:
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 "199"
'gst is cool' size "11"
'gst is cool' size "11"
'Slick' indexOf: $c "4"
'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===
===Collections===
Constructing and using an array:
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: 3 "3.14"
a reverse "#((4 5) 2 1 3.14 'hi' 1)"
a reverse "#((4 5) 2 1 3.14 'hi' 1)"
a asSet "Set(1 'hi' 3.14 2 #(4 5))"
a asSet "Set(1 'hi' 3.14 2 #(4 5))"
</source>


Constructing and using a hash table:
Constructing and using a hash table:


hash := Dictionary from: { 'water' -> 'wet'. 'fire' -> 'hot' }.
<source lang="smalltalk">
hash := Dictionary from: { 'water' -> 'wet'. 'fire' -> 'hot' }.
hash at: 'fire' "Prints: 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===
===Blocks and iterators===
Parameter-passing a block to be a closure:
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: 'world'
"=> "Hello, world!""
"=> "Hello, world!""
</source>


Returning closures from a method:
Returning closures from a method:


Integer extend [
<source lang="smalltalk">
asClosure [
Integer extend [
| value |
asClosure [
| value |
value := self.
value := self.
^{ [ :x | value := x ]. [ value ] }
^{ [ :x | value := x ]. [ value ] }
]
]
]
]

blocks := 10 asClosure.
blocks := 10 asClosure.
setter := blocks first.
setter := blocks first.
getter := blocks second.
getter := blocks second.
getter value "=> 10"
getter value "=> 10"
setter value: 21 "=> 21"
setter value: 21 "=> 21"
getter value "=> 21"
getter value "=> 21"
</source>


Using block to send info back to the caller:
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 [
^self even
ifTrue: [ evenBlock value: self ]
ifTrue: [ evenBlock value: self ]
ifFalse: [ oddBlock 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:
Iterating over enumerations and arrays using blocks:


array := #(1 'hi' 3.14)
<source lang="smalltalk">
array := #(1 'hi' 3.14)
array do: [ :item | item displayNl ]
"=> 1"
array do: [ :item | item displayNl ]
"=> 1"
"=> hi"
"=> hi"
"=> 3.14"
"=> 3.14"
(3 to: 6) do: [ :item | item displayNl ]

"=> 3"
(3 to: 6) do: [ :item | item displayNl ]
"=> 3"
"=> 4"
"=> 4"
"=> 5"
"=> 5"
"=> 6"
"=> 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:
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.
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: Line 100:
Blocks work with many built-in methods:
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:
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===
===Classes===
Line 138: Line 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>.
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 [
| name age |
Person class >> name: name age: age [
Person class >> name: name age: age [
^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===
===Exceptions===
An exception is raised with a <code>halt</code> call:
An exception is raised with a <code>halt</code> call:

<source lang="smalltalk">
self halt
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:
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 halt: 'This is a message'
self error: 'This is a message'
self error: 'This is a message'
</source>


These are actually wrappers for the actual exception raising method, <code>signal>:
These are actually wrappers for the actual exception raising method, <code>signal>:

<source lang="smalltalk">
Error signal
Error signal
Error signal: 'Illegal arguments!'
Error signal: 'Illegal arguments!'
</source>


Exceptions are handled by <code>on:do:</code> blocks.
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):
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:
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"
[ (Warning signal: 'now what?')
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 ==
== External links ==