Appendix C: Useful Code Snippets
A collection of handy Smalltalk code snippets for common tasks. Keep this reference nearby for quick copy-paste solutions!
Collections
Creating Collections
"Array - fixed size"
#(1 2 3 4 5)
Array with: 1 with: 2 with: 3
"OrderedCollection - dynamic"
OrderedCollection new
OrderedCollection with: 1 with: 2 with: 3
{ 1. 2. 3 } asOrderedCollection
"Set - unique elements"
Set new add: 1; add: 2; add: 1; yourself "-> Set(1 2)"
"Dictionary - key-value pairs"
Dictionary new at: 'name' put: 'Alice'; yourself
{ 'name' -> 'Alice'. 'age' -> 30 } asDictionary
"Bag - counts occurrences"
Bag new add: 'apple'; add: 'apple'; add: 'banana'; yourself
Collection Operations
"Iterate"
collection do: [ :each | Transcript show: each; cr ].
"Transform"
collection collect: [ :each | each * 2 ].
"Filter"
collection select: [ :each | each even ].
collection reject: [ :each | each odd ].
"Find"
collection detect: [ :each | each > 10 ] ifNone: [ nil ].
collection anySatisfy: [ :each | each > 10 ].
collection allSatisfy: [ :each | each > 0 ].
"Reduce"
collection inject: 0 into: [ :sum :each | sum + each ].
"Chain operations"
collection
select: [ :each | each > 10 ]
thenCollect: [ :each | each squared ].
"Sort"
collection sorted.
collection sorted: [ :a :b | a > b ]. "Descending"
collection sorted: #size ascending. "By property"
"Group"
collection groupedBy: #even. "-> Dictionary with true/false keys"
"Convert"
collection asArray.
collection asSet.
collection asOrderedCollection.
collection asSortedCollection.
Working with Dictionaries
"Create"
dict := Dictionary new.
dict at: 'name' put: 'Alice'.
dict at: 'age' put: 30.
"Access"
dict at: 'name'. "-> 'Alice'"
dict at: 'missing' ifAbsent: [ 'default' ].
dict at: 'age' ifPresent: [ :v | v + 1 ].
"Check"
dict includesKey: 'name'. "-> true"
dict includes: 'Alice'. "-> true (checks values)"
"Iterate"
dict keysAndValuesDo: [ :key :value |
Transcript show: key, ': ', value asString; cr ].
dict keys. "All keys"
dict values. "All values"
dict associations. "Key-value pairs"
"Remove"
dict removeKey: 'age'.
dict removeKey: 'missing' ifAbsent: [ ].
"Get with default"
dict at: 'count' ifAbsentPut: [ 0 ].
Strings
String Manipulation
"Concatenation"
'Hello', ' ', 'World'.
String streamContents: [ :s |
s nextPutAll: 'Hello';
space;
nextPutAll: 'World' ].
"Formatting"
'Hello {1}!' format: { 'Alice' }.
'x={1}, y={2}' format: { 10. 20 }.
"Case"
'hello' asUppercase. "-> 'HELLO'"
'WORLD' asLowercase. "-> 'world'"
'hello world' capitalized. "-> 'Hello world'"
"Trimming"
' hello ' trimBoth. "-> 'hello'"
' hello ' trimLeft. "-> 'hello '"
' hello ' trimRight. "-> ' hello'"
"Splitting"
'one,two,three' splitOn: $,. "-> #('one' 'two' 'three')"
'one two three' substrings. "-> #('one' 'two' 'three')"
'a-b-c' splitOn: '-'.
"Substring"
'Hello World' copyFrom: 1 to: 5. "-> 'Hello'"
'Hello World' allButFirst: 6. "-> 'World'"
'Hello World' first: 5. "-> 'Hello'"
'Hello World' last: 5. "-> 'World'"
"Search"
'Hello World' includesSubstring: 'World'.
'Hello World' findString: 'World'. "-> 7 (index)"
'Hello World' beginsWith: 'Hello'.
'Hello World' endsWith: 'World'.
"Replace"
'Hello World' copyReplaceAll: 'World' with: 'Universe'.
String Building
"Efficient string building"
String streamContents: [ :stream |
1 to: 100 do: [ :n |
stream
nextPutAll: 'Number: ';
print: n;
cr ] ].
"Join collection"
#('one' 'two' 'three') joinUsing: ', '. "-> 'one, two, three'"
"Repeat"
'abc' repeat: 3. "-> 'abcabcabc'"
Numbers
Arithmetic
"Basic operations"
5 + 3. "-> 8"
5 - 3. "-> 2"
5 * 3. "-> 15"
5 / 3. "-> 1.66666... (Float)"
5 // 3. "-> 1 (Integer division)"
5 \\ 3. "-> 2 (Modulo/remainder)"
2 ** 8. "-> 256 (Power)"
"Rounding"
3.7 rounded. "-> 4"
3.7 floor. "-> 3"
3.2 ceiling. "-> 4"
3.7 truncated. "-> 3"
3.14159 roundTo: 0.01. "-> 3.14"
"Testing"
5 even. "-> false"
4 even. "-> true"
5 odd. "-> true"
7 isPrime. "-> true"
"Range"
5 max: 10. "-> 10"
5 min: 10. "-> 5"
5 between: 1 and: 10. "-> true"
"Absolute value"
-5 abs. "-> 5"
"Sign"
-5 sign. "-> -1"
5 sign. "-> 1"
0 sign. "-> 0"
Random Numbers
"Random integer"
100 atRandom. "1 to 100"
Random new nextInt: 100. "0 to 99"
"Random float"
Random new next. "0.0 to 1.0"
Random new next: 5. "Array of 5 random floats"
"Random from collection"
#(1 2 3 4 5) atRandom.
Math Functions
"Trigonometry"
45 degreesToRadians sin.
Float pi cos.
1 arcTan.
"Exponential"
2.718281828 ln. "Natural log"
100 log. "Base 10 log"
Float e. "Euler's number"
"Square root"
25 sqrt. "-> 5"
2 sqrt. "-> 1.41421..."
"Other"
5 squared. "-> 25"
5 factorial. "-> 120"
Dates and Times
Current Date/Time
"Now"
DateAndTime now.
Date today.
Time now.
"Components"
DateAndTime now hour.
DateAndTime now minute.
DateAndTime now dayOfWeek.
DateAndTime now monthName.
Creating Dates
"Specific date"
Date year: 2024 month: 12 day: 25.
Date fromString: '2024-12-25'.
"Specific time"
Time hour: 14 minute: 30 second: 0.
Time fromString: '14:30:00'.
"Date and time"
DateAndTime
year: 2024 month: 12 day: 25
hour: 14 minute: 30 second: 0.
Date Arithmetic
"Add/subtract"
Date today + 7 days.
Date today - 1 week.
Date today + 1 month.
Date today + 1 year.
"Difference"
(Date today - Date yesterday) days. "-> 1"
"Comparison"
Date today < Date tomorrow. "-> true"
Date today between: Date yesterday and: Date tomorrow.
Formatting
"Print formats"
Date today printFormat: #(1 2 3 $- 1 1). "YYYY-MM-DD"
Date today mmddyyyy. "MM/DD/YYYY"
DateAndTime now asString.
Files and Streams
File Operations
"Read entire file"
'data.txt' asFileReference contents.
"Read lines"
'data.txt' asFileReference readStreamDo: [ :stream |
stream contents lines ].
"Write file"
'output.txt' asFileReference writeStreamDo: [ :stream |
stream nextPutAll: 'Hello, World!' ].
"Append to file"
'log.txt' asFileReference appendStreamDo: [ :stream |
stream
nextPutAll: DateAndTime now asString;
nextPutAll: ': Log entry';
cr ].
"File info"
'data.txt' asFileReference exists.
'data.txt' asFileReference size.
'data.txt' asFileReference modificationTime.
"Delete file"
'temp.txt' asFileReference ensureDelete.
Directory Operations
"List files"
'.' asFileReference children.
'.' asFileReference files.
'.' asFileReference directories.
"Create directory"
'new-folder' asFileReference ensureCreateDirectory.
"Recursive list"
'.' asFileReference allFiles.
'.' asFileReference allDirectories.
"Navigate"
FileLocator home / 'Documents' / 'data.txt'.
FileLocator workingDirectory / 'src' / 'Main.st'.
Stream Processing
"Line by line"
'large-file.txt' asFileReference readStreamDo: [ :stream |
[ stream atEnd ] whileFalse: [
| line |
line := stream nextLine.
"Process line..." ] ].
"Build string"
String streamContents: [ :stream |
stream
nextPutAll: 'Name: ';
nextPutAll: person name;
cr;
nextPutAll: 'Age: ';
print: person age ].
Blocks
Common Block Patterns
"Simple block"
[ 2 + 2 ] value. "-> 4"
"Block with arguments"
[ :x | x * 2 ] value: 5. "-> 10"
[ :x :y | x + y ] value: 3 value: 4. "-> 7"
"Multiple statements"
[
| result |
result := 10 * 2.
result + 5
] value. "-> 25"
"Conditional execution"
condition ifTrue: [ "do this" ] ifFalse: [ "do that" ].
"Error handling"
[ riskyOperation ] on: Error do: [ :ex |
Transcript show: 'Error: ', ex messageText; cr ].
"Cleanup"
[ doWork ] ensure: [ cleanup ].
"Timing"
[ expensiveOperation ] timeToRun.
[ operation ] bench.
Error Handling
Try-Catch Pattern
"Basic try-catch"
[ self dangerousOperation ]
on: Error
do: [ :ex |
Transcript show: 'Error: ', ex messageText; cr ].
"Specific exceptions"
[ self parseNumber: input ]
on: NumberParserError
do: [ :ex | 0 ].
"Multiple exception types"
[ self operation ]
on: NetworkError, TimeoutError
do: [ :ex | self handleNetworkIssue: ex ].
"Re-raise"
[ self operation ]
on: Error
do: [ :ex |
self logError: ex.
ex pass ]. "Re-raise"
Custom Exceptions
"Define"
Error subclass: #ValidationError
instanceVariableNames: 'field'
classVariableNames: ''
package: 'MyApp'
"Raise"
ValidationError signal: 'Invalid email format'.
(ValidationError new field: 'email') signal.
"Catch specific"
[ self validateUser ]
on: ValidationError
do: [ :ex | self showError: ex field ].
Testing
SUnit Test Template
TestCase subclass: #MyClassTest
instanceVariableNames: 'fixture'
classVariableNames: ''
package: 'MyApp-Tests'
setUp
"Run before each test"
fixture := MyClass new
tearDown
"Run after each test"
fixture := nil
testSomething
"Test that something works"
| result |
result := fixture doSomething: 42.
self assert: result equals: 84
testError
"Test that error is raised"
self should: [ fixture badOperation ] raise: Error
testNoError
"Test that no error is raised"
self shouldnt: [ fixture goodOperation ] raise: Error
Common Assertions
"Equality"
self assert: actual equals: expected.
self deny: actual equals: notExpected.
"Boolean"
self assert: condition.
self deny: negativeCondition.
"Nil"
self assert: result isNil.
self deny: result isNil.
"Collections"
self assert: collection isEmpty.
self assert: collection size equals: 3.
self assert: (collection includes: item).
"Exceptions"
self should: [ code ] raise: ErrorClass.
self shouldnt: [ code ] raise: ErrorClass.
"Floats (with tolerance)"
self assert: 3.14159 closeTo: Float pi.
Object Inspection
Debugging Snippets
"Inspect object"
myObject inspect.
"Halt execution"
self halt.
self halt: 'Breakpoint here'.
"Trace execution"
Transcript show: 'Value: ', value asString; cr.
Transcript show: self printString; cr.
"Log to Transcript"
[ heavyOperation ] timeToRun. "See how long it takes"
"Check type"
object class.
object class name.
object isKindOf: Array.
object respondsTo: #size.
Object Creation Patterns
"Basic instantiation"
MyClass new.
"With initialization"
MyClass new initialize; yourself.
"With setup"
MyClass new
name: 'Alice';
age: 30;
yourself.
"Copy"
original copy.
original deepCopy.
"Singleton"
MyClass uniqueInstance.
System Queries
Finding Code
"Find implementors"
SystemNavigation default allImplementorsOf: #size.
"Find senders"
SystemNavigation default allSendersOf: #collect:.
"Find references"
SystemNavigation default allReferencesTo: Array.
"Find classes"
Smalltalk globals allClasses select: [ :c |
c name includesSubstring: 'Test' ].
"Browse class"
Array browse.
Object browse.
System Information
"Image info"
SystemVersion current version.
Smalltalk platform name.
Smalltalk vm version.
"Memory"
Smalltalk garbageCollect.
Smalltalk vm totalMemory.
Smalltalk vm freeMemory.
"Performance"
Time millisecondsToRun: [ heavyOperation ].
Useful One-Liners
Data Processing
"Word frequency"
text substrings asBag sortedCounts.
"Unique elements"
collection asSet.
"Remove duplicates preserving order"
collection asOrderedCollection removeDuplicates.
"Transpose 2D array"
matrix first size timesCollect: [ :i |
matrix collect: [ :row | row at: i ] ].
"Flatten nested collection"
nested flattened.
Quick Utilities
"Generate UUID"
UUID new asString.
"Random password"
(String newFrom: ((1 to: 16) collect: [ :i |
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' atRandom ])).
"Benchmark comparison"
{ [ method1 ]. [ method2 ] } collect: #timeToRun.
"Quick web fetch"
ZnClient new get: 'https://api.example.com/data'.
Common Idioms
Lazy Initialization
accessor
accessor ifNil: [ accessor := self computeExpensiveValue ].
^ accessor
Cascading Messages
collection
add: item1;
add: item2;
add: item3;
yourself.
Safe Navigation
object ifNotNil: [ :o | o doSomething ].
object ifNil: [ default ] ifNotNil: [ :o | o value ].
Builder Pattern
User new
name: 'Alice';
email: 'alice@example.com';
role: #admin;
yourself.
Ensuring Resources
file := 'data.txt' asFileReference.
[
stream := file readStream.
stream contents
] ensure: [
stream ifNotNil: [ stream close ] ].
Performance Patterns
Pre-sizing Collections
"Slow"
result := OrderedCollection new.
1 to: 10000 do: [ :i | result add: i ].
"Fast"
result := OrderedCollection new: 10000.
1 to: 10000 do: [ :i | result add: i ].
Using Streams for Strings
"Slow"
result := ''.
1 to: 1000 do: [ :i | result := result, i asString ].
"Fast"
result := String streamContents: [ :s |
1 to: 1000 do: [ :i | s nextPutAll: i asString ] ].
Caching
expensiveResult
"Cache the result"
^ expensiveResult ifNil: [
expensiveResult := self computeExpensiveResult ]
Quick Reference
Keep this handy:
"Execute code"
Ctrl+D "Do it"
Ctrl+P "Print it"
Ctrl+I "Inspect it"
"Common collections"
#(1 2 3) "Array"
{ 1. 2. 3 } "Dynamic array"
OrderedCollection new "Mutable list"
Set new "Unique elements"
Dictionary new "Key-value"
"Iteration"
do: [ :each | ... ]
collect: [ :each | ... ]
select: [ :each | ... ]
reject: [ :each | ... ]
detect: [ :each | ... ]
inject: 0 into: [ :sum :each | ... ]
"Conditionals"
ifTrue: [ ... ]
ifFalse: [ ... ]
ifNil: [ ... ]
ifNotNil: [ :value | ... ]
"Loops"
timesRepeat: [ ... ]
to:do: [ :i | ... ]
whileTrue: [ ... ]
"Files"
'file.txt' asFileReference contents
'file.txt' asFileReference writeStream: 'text'
| Previous: Appendix B - Keyboard Shortcuts Reference | Next: Appendix D - Glossary |