GNU Smalltalk: Difference between revisions

From Rosetta Code
Content added Content deleted
(from wikipedia)
 
(→‎Examples: Changed wiki italics back to single quotes)
 
(5 intermediate revisions by 4 users not shown)
Line 1: Line 1:
'''GNU Smalltalk''' is an implementation of the [[:Category:Smalltalk|Smalltalk]] programming language by the GNU Project. For download, see [http://smalltalk.gnu.org/ http://smalltalk.gnu.org/].
{{implementation|Smalltalk}}'''GNU Smalltalk''' is an implementation of the [[:Category:Smalltalk|Smalltalk]] programming language by the GNU Project. For download, see [http://smalltalk.gnu.org/ http://smalltalk.gnu.org/].


The implementation, unlike other Smalltalk environments, uses text files for program input and interprets the contents as Smalltalk code. In this way, GNU Smalltalk acts more like an interpreter rather than an environment in the traditional Smalltalk manner.
The implementation, unlike other Smalltalk environments, uses text files for program input and interprets the contents as Smalltalk code. In this way, GNU Smalltalk acts more like an interpreter rather than an environment in the traditional Smalltalk manner.


==Examples==
==Examples==
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:


<pre>"Everything, including a literal, is an object, so this works:"
<source lang="smalltalk">
"Everything, including a literal, is an object, so this works:"
-199 abs "199"
-199 abs "199"
'gst is cool' size "11"
'gst is cool' size "11"
'Slick' indexOf: $c "4"
'Slick' indexOf: $c "4"
'Nice Day Isn''t It?' asLowercase asSet asSortedCollection asString "' '?acdeinsty'"
'Nice Day Isn''t It?' asLowercase asSet asSortedCollection asString "' '?acdeinsty'"</pre>

</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"
"=> 4"
"=> 5"
"=> 6"


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:
(3 to: 6) do: [ :item | item displayNl ]
"=> 3"
"=> 4"
"=> 5"
"=> 6"
</source>


#(1 3 5) inject: 10 into: [ :sum :element | sum + element ] "=> 19"
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:

<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 101:
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 ]
(File name: 'file.txt') linesDo: [ :each |
each displayNl ]
"=> Wrote some text."


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


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 (<tt>&lt;</tt>). With the addition of that one, <tt>asSortedCollection</tt> 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 <tt>printOn:</tt>.


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.
}.


===Exceptions===
group asSortedCollection reverse
An exception is raised with a <tt>halt</tt> call:
</source>


self halt
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:
An optional message can be added to the exception; there's also <tt>error:</tt> which raises a different kind of exception:
<source lang="smalltalk">
self halt: 'This is a message'
self error: 'This is a message'
</source>


self halt: 'This is a message'
These are actually wrappers for the actual exception raising method, <code>signal>:
self error: 'This is a message'
<source lang="smalltalk">

Error signal
These are actually wrappers for the actual exception raising method, <tt>signal</tt>:
Error signal: 'Illegal arguments!'

</source>
Error signal
Error signal: 'Illegal arguments!'


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 ==
Line 217: Line 185:
* [http://www.gnu.org GNU]
* [http://www.gnu.org GNU]
* [http://smalltalk.gnu.org/ GNU Smalltalk]
* [http://smalltalk.gnu.org/ GNU Smalltalk]

[[Category:Language Implementations]]
[[Category:Smalltalk]]

Latest revision as of 22:25, 6 January 2012

GNU Smalltalk is an implementation of Smalltalk. Other implementations of Smalltalk.

GNU Smalltalk is an implementation of the Smalltalk programming language by the GNU Project. For download, see http://smalltalk.gnu.org/.

The implementation, unlike other Smalltalk environments, uses text files for program input and interprets the contents as Smalltalk code. In this way, GNU Smalltalk acts more like an interpreter rather than an environment in the traditional Smalltalk manner.

Examples

These examples only work on GNU Smalltalk 3.0 and later versions. Classic Hello world example:

'Hello World!' displayNl

Some basic Smalltalk code:

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


Collections

Constructing and using an array:

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

Constructing and using a hash table:

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

Blocks and iterators

Parameter-passing a block to be a closure:

"remember a block."
remember := [ :name | ("Hello, %1!" % { name }) displayNl ].

"When the time is right -- call the closure!"
remember value: 'world'
"=> "Hello, world!""

Returning closures from a method:

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"

Using block to send info back to the caller:

Integer extend [
    ifEven: evenBlock ifOdd: oddBlock [
        ^self even
            ifTrue: [ evenBlock 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"

Iterating over enumerations and arrays using blocks:

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"

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"

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.

Blocks work with many built-in methods:

(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."

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

Classes

The following code defines a class named Person. By deriving from Magnitude, it automatically defines all comparison methods except one (<). With the addition of that one, asSortedCollection 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 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

The above prints three names in reverse age order:

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

Exceptions

An exception is raised with a halt call:

self halt

An optional message can be added to the exception; there's also error: which raises a different kind of exception:

self halt: 'This is a message'
self error: 'This is a message'

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

Error signal
Error signal: 'Illegal arguments!'

Exceptions are handled by on:do: blocks.

[ something to do ]
    on: Exception
    do: [ :ex | handle exception in ex ]

Of course you can catch only particular exceptions (and their subclasses):

[ something to do ]
    on: Warning
    do: [ :ex | handle exception in ex ]

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' ]
    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"

External links