![]() | This article includes a list of references, related reading, or external links, but its sources remain unclear because it lacks inline citations .(June 2013) |
![]() | |
Original author(s) | Steve Byrne, Paolo Bonzini |
---|---|
Initial release | January 12, 2003 |
Stable release | 3.2.5 / April 8, 2013 |
Repository | |
Operating system | Unix (Linux, Cygwin, Mac OS X/Darwin) |
Type | Programming language |
License | GPL + LGPL |
Website | https://www.gnu.org/software/smalltalk/ |
GNU Smalltalk is an implementation of the Smalltalk programming language by the GNU Project.
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.
GNU Smalltalk includes bindings for many free software libraries including SQLite, libSDL, cairo, gettext, and Expat.
These examples work only 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:"-199abs"199"'gstiscool'size"11"'Slick'indexOf:$c"4"'NiceDayIsn''tIt?'asLowercaseasSetasSortedCollectionasString"′?acdeinsty"
Constructing and using an array:
a:=#(1'hi'3.1412(45))aat:3"3.14"areverse"((4 5) 2 1 3.14 'hi' 1)"aasSet"Set(1 'hi' 3.14 2 (4 5))"
Constructing and using a hash:
hash:=Dictionaryfrom: { 'water'->'wet'.'fire'->'hot' }.hashat:'fire'"Prints: hot"hashkeysAndValuesDo: [ :k:v| ('%1 is %2'% { k.v }) displayNl ] "Prints: water is wet fire is hot"hashremoveKey:'water'"Deletes 'water' -> 'wet'"
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!"remembervalue:'world'"=> 'Hello, world!'"
Returning closures from a method:
Integerextend [ asClosure [ | value |value:=self.^{ [ :x|value:=x ]. [ value ] } ] ] blocks:=10asClosure.setter:=blocksfirst.getter:=blockssecond.gettervalue"=> 10"settervalue:21"=> 21"gettervalue"=> 21"
Using block to send info back to the caller:
Integerextend [ ifEven:evenBlockifOdd:oddBlock [ ^selfevenifTrue: [ evenBlockvalue:self ] ifFalse: [ oddBlockvalue:self ] ] ]
Invoke the above method, passing it a block:
10ifEven: [ :n|n/2 ] ifOdd: [ :n|n*3+1 ] "=> 5"
Iterating over enumerations and arrays using blocks:
array:=#(1'hi'3.14)arraydo: [ :item|itemdisplayNl ] "=> 1""=> hi""=> 3.14" (3to:6) do: [ :item|itemdisplayNl ] "=> 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 functional programming languages. For example:
#(135)inject:10into: [ :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:
(Filename:'file.txt') withWriteStreamDo: [ :file|filenextPutAll:'Wrote some text.';nl ] "File is automatically closed here" (Filename:'file.txt') linesDo: [ :each|eachdisplayNl ] "=> Wrote some text."
Using an enumeration and a block to square the numbers 1 to 10:
(1to:10) collect: [ :x|xsquared ] "=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]"
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:
.
Magnitudesubclass:Person [ | name age |Personclass>>name:nameage:age [ ^selfnewname:name;age:age;yourself ] <aPerson [ ^selfage<aPersonage ] name [ ^name ] name:value [ name:=value ] age [ ^age ] age:value [ age:=value ] printOn:aStream [ aStreamnextPutAll: ('%1 (%2)'% { name.age }) ] ] group:= { Personname:'Dan'age:23.Personname:'Mark'age:63.Personname:'Cod'age:16. }. groupasSortedCollectionreverse
The above prints three names in reverse age order:
OrderedCollection (Mark (63) Dan (23) Cod (16) )
An exception is raised with a halt
call:
selfhalt
An optional message can be added to the exception; there's also error:
which raises a different kind of exception:
selfhalt:'This is a message'selferror:'This is a message'
These are actually wrappers for the actual exception raising method, signal
:
ErrorsignalErrorsignal:'Illegal arguments!'
Exceptions are handled by on:do:
blocks.
[ somethingtodo ] on:Exceptiondo: [ :ex|handleexceptioninex ]
Of course you can catch only particular exceptions (and their subclasses):
[ somethingtodo ] on:Warningdo: [ :ex|handleexceptioninex ]
It is possible to use the exception object, which is made available to the handler clause, to exit or resume the first block; exiting is the default, but can also be mentioned explicitly:
[ Errorsignal:'foo' ] on:Errordo: [ :ex|exreturn:5 ] (Warningsignal:'now what?') printNl"=> nil" [ (Warningsignal:'now what?') printNl ] on:Warningdo: [ :ex|exresume:5 ] "=> 5"