Smalltalk Introduction

by "Blag" - Senior Developer Evangelist

Return to Geeky Thursday

What is Smalltalk?


Smalltalk is an object-oriented, dynamically typed reflective programming language.


Everything is an object...even literals...


Smalltalk had influence many programming languages like Objective-C, Java, Python, Ruby and many more...


We're going to learn by using GNU Smalltalk.

How to install Smalltalk?


Plain and simple


sudo apt-get update


sudo apt-get install gnu-smalltalk


Who uses Smalltalk?


Smalltalk has many implementations like Pharo, Cincom Smalltalk and GemTalk Visual Works for Smalltalk...


  • JPMorgan
  • Desjardins
  • Texas Instruments
  • Telecom Argentina
  • Siemens AG
  • Penn State University
  • UBS

Starting out...


Once Smalltalk is installed, we can simply call it from the terminal


Basic Concepts


Comments must be enclosed between "This is a comment".


Precedence must be enforced by parenthesis...and you will see later on who important this is...

				
(2*3+5)

=>11



(2*(3+5))

=>16
				

Basic Concepts


Printing on the screen is easy...

				
text := "This is Smalltalk!"



text printNl.



=>'This is Smalltalk'
				

Yep, print goes after the text...basically you pass it as a parameter -;)


This is another way (that gets rid of the ' too...

				
text := "This is Smalltalk!"



Transcript show: text



=>This is Smalltalk
				

Yep, print goes after the text...basically you pass it as a parameter -;)


You need to declare variables using | variableName |


You assign values using :=

				
| a b |


a := 'Hello'


a printNl.


=>'Hello'



b := 5


b printNl.


=>5
				

Precedence and parenthesis are very important...


				
'Hello' size + 3 printNl.

=> 3



('Hello' size + 3) printNl.

=> 8
				

Data Structures


Let's start with Arrays

				
| myArray |


myArray := Array new: 3.



myArray at:1 put: 1.

myArray at:2 put: 2.

myArray at:3 put: 3.



myArray printNl.

=>(1 2 3)
				

				
myArray := #(1 2 3).



myArray first.

=>1


myArray last.

=>3


myArray size.

=>3


myArray at:1.

=>1
				

				
myArray := #('Smalltalk' 'Fortran' 'Haskell').



myArray includes:'Python'.

=>false


myArray reverse.

=>('Haskell' 'Fortran' 'Smalltalk')
				

Sets

Similar to arrays but unordered and without limits


				
| aSet |

aSet := Set new.


aSet add: 'Smalltalk'.

aSet add: 'Fortran'.

aSet add: 'Haskell'.


aSet printNl.

->('Smalltalk' 'Haskell' 'Fortran')
				
				
aSet remove: 'Smalltalk'.



aSet printNl.

->('Smalltalk' 'Haskell' 'Fortran')
				

A Set cannot have duplicated values...


Dictionaries

				
| aDict |

aDict := Dictionary new.



aDict at:'Peru' put:'Spanish'.

aDict at:'Canada' put:'English'.



aDict printNl.

=> Dictionary(

           'Canada' -> 'English'

           'Peru' -> 'Spanish'
)

				
				
| aDict |

aDict := Dictionary new.


aDict := Dictionary from: {'Peru' -> 'Spanish'.
	
	                   'Canada' -> 'English'}.


aDict at:'Peru'.

=> 'Spanish'



aDict keys printNl.

=> Set('Peru' 'Canada')



aDict values printNl.

=> Set('English' 'Spanish')
				

Blocks

Something like functions or methods...but that are objects as well...

				
| myBlock |




myBlock := [:name |

   Transcript show: ('Hello ' , name , '!').

].




myBlock value: 'Blag'.


=> Hello Blag!
				

Conditionals

				
| myVar |



myVar = 'Blag'.



(myVar = 'Blag') ifTrue: [

	'Blag rocks!' printNl.

] ifFalse: [

	'Hey!, where is Blag?' printNl.

].


=> 'Hey!, where is Blag?'
				

Repetitive controlling

				
| num |



num := 1.



[ num < 11 ] whileTrue: [

   Transcript show: (num asString , ' ').

   num := num + 1.

].



=> 1 2 3 4 5 6 7 8 9 10
				
				
1 to: 10 do: [:x |
	
   Transcript show: (x asString, ' ').

].



=> 1 2 3 4 5 6 7 8 9 10





1 to: 10 by: 2 do: [:x |
	
   Transcript show: (x asString, ' ').

].



=> 1 3 5 7 9
				

Classes and objects

				
Object subclass: Person [

    | name |

    setName: newName [
	
        <category: 'accessing'>
	
        name := newName.	
	
    ]

    getName [
	
        <category: 'accessing'>
	
        ^name
	
    ]

    speak [
	
        <category: 'accessing'>
		
       'Programming is fun!' printNl.
		
    ]
]
				
				
blag := Person new.

blag setName: 'Blag'.

blag getName printNl.

blag speak.



=> 'Blag'

=> 'Programming is fun!'
				

Strings

				
| aString |

aString := 'My name is Blag.'.

aString := aString , ' I like Smalltalk'.


aString printNl.

aString reverse asUppercase printNl.

aString size printNl.


=> 'My name is Blag. I like Smalltalk'


=> 'KLATLLAMS EKIL I. GALB SI EMAN YM'


=> 33
				

Fibonacci List


Finally...we're going to make our first application...


So grab your favorite text editor and get ready...


Name your file "Fibonacci.st"


				
| number fib result |



result := ''.



fib := [:num :a :b |


   a > 0 & (num asNumber > 1) ifTrue: [

      result := result , (a + b) asString , ' ' , 

                (fib value: (num asNumber - 1) 
                
                 value: (a + b) value: a).

   ] ifFalse: [
				
				
      a = 0 ifTrue: [

         result := a asString , ' ' , b asString , 
         
                   ' ' ,  (a + b) asString , ' ' , 
                  
                  (fib value: (num asNumber - 1) 
                  
                  value: (a + b) value: b).

      ]. 

   ].

].



Transcript show: 'Enter a number: '.

num := stdin nextLine.


Transcript show: (fib value: num value: 0 value: 1); cr.
				

Open the Terminal and go to your source code folder...

gst "Name_of_File.st"


When we run it we're going to see...

Making an LED Number App


This is one of my favorite codes of all time...


Name your file "LED_Numbers.st"


				
| led line lines counter getLine number digit |



led := Dictionary new.


lines := Array new: 3.


line := ''.


counter := 1.
				
				
led := Dictionary from: {0 -> ' _  ,| | ,|_| '.

                         1 -> '  ,| ,| '.

                         2 -> ' _  , _| ,|_  '.

                         3 -> '_  ,_| ,_| '.

                         4 -> '    ,|_| ,  | '.

                         5 -> ' _  ,|_  , _| '.

                         6 -> ' _  ,|_  ,|_| '.

                         7 -> '_   , |  , |  '.

                         8 -> ' _  ,|_| ,|_| '.

                         9 -> ' _  ,|_| , _| '. }.
				
				
getLine := [:digit :dline |

   1 to: ((led at: digit) size) do: [:x |

      (((led at: digit) at: x) asString ~= ',') 
      
      ifTrue: [ 

         line := line , ((led at: digit) at: x) 
         
                        asString.

      ] ifFalse: [

         lines at: counter put: line.

         line := ''.

         counter := counter + 1

      ].

      lines at: counter put: line.

   ].
				
				
   Transcript show: ((lines at: dline) asString).

   line := ''.

   counter := 1.

].



Transcript show: 'Enter a number: '.

number := stdin nextLine.

1 to: 3 do: [:y |

   1 to: (number size) do: [:x |

      digit := ((number at:x) asString) asInteger.

      getLine value: digit value: y.

   ].

   Transcript cr.

].
				

When we run it we're going to see...


Random Names


This App will generate 100,000 random names using two 16 elements lists


We will measure the runtime


Name your file "Random_Names.st"


				
| names last_names full_names counter |



full_names := Array new: 100001.

counter := 1.



names := Array new: 16.

names := #('Anne' 'Gigi' 'Blag' 'Juergen' 'Marek'

           'Ingo' 'Lars' 'Julia' 'Danielle' 'Rocky'

           'Julien' 'Uwe' 'Myles' 'Mike' 'Steven' 
           
           'Fanny').
				
				
last_names := Array new: 16.

last_names := #('Hardy' 'Read' 'Tejada' 'Schmerder' 

                'Kowalkiewicz' 'Sauerzapf' 'Karg' 
                
                'Satsuta' 'Keene' 'Ongkowidjojo'

                'Vayssiere' 'Kylau' 'Fenlon' 'Flynn' 
                
                'Taylor' 'Tan').



1 to:100001 do: [:x |

   full_names at:x put:((names at:(1 to: 16) 
	                      
                        atRandom) , ' ' , 
	                     
                        (last_names at:(1 to: 16) 
	                     
                        atRandom)).

].
			

When we run it we're going to see...

How this behaves in Python?

And in Julia?

Decimal to Romans


This App will create a Roman Numeral based on a decimal number


This will include some nice commands...


Name your file "Decimal_to_Roman.st"


				
| number roman_Table roman_keys result flag |



roman_Table := Dictionary new.

roman_keys := Array new: 13.

result := ''.

flag := 0.



roman_Table := Dictionary 

      from: {1000 -> 'M'. 900 -> 'CM'. 500 -> 'D'.

             400 -> 'CD'. 100 -> 'C'. 90 -> 'XC'.

             50 -> 'L'. 40 -> 'XL'. 10 -> 'X'.

             9 -> 'IX'. 5->'V'. 4 -> 'IV'. 1 -> 'I'.}.
             
			
				
roman_keys := #( 1000 900 500 400 100 90 50 40 10 

                 9 5 4 1 ).



Transcript show: 'Enter a number: '.

number := stdin nextLine.



[ number asNumber > 0 ] whileTrue: [

   flag := 0.

   1 to: (roman_keys size) do: [:x | 

      (number asNumber >= (roman_keys at: x) asNumber 
      
       & flag = 0) 
       
       ifTrue: [
			
				
         result := result , (roman_Table at:
         
                             (roman_keys at: x)).

         number := number asNumber - 
         
                  (roman_keys at: x) asNumber.

         flag := 1.

       ].

   ].

].



Transcript show: result; cr.
				

When we run it we're going to see...


Count Letters


In this example we're going to read a file and count how many time a letter appears...


Call your file "countletters.st" (all in lowercase).


Create a file called "readme.txt" with the following text...


"This is a text file that we're going to read using Smalltalk"


				
| file contents letters |



letters := Dictionary new.



file := FileStream open: 'readme.txt' 

        mode: FileStream read.



file linesDo: [ :c | contents := c ].
			
				
1 to:contents size do: [:x |

   (letters includesKey:((contents at:x) asString)) 
   
    ifTrue: [

      letters at:((contents at:x) asString) 

              put:((letters at:((contents at:x) 
              
                    asString)) + 1)

   ] ifFalse: [

      letters at:((contents at:x) asString) put:1.

   ].

].
			
				
letters keysAndValuesDo: [:aKey :aValue | Transcript

   show: aKey printString; space;

   show: aValue printString; cr

].


file close
			

When we run it we're going to see...


That's it for now


Smalltalk is a pretty awesome language


And it's still being used...although people seem to have forgotten about it -:(


It will bend you mind and make you a better developer...


Contact Information


Blag --> blag@blagarts.com

@Blag on Twitter

Go back home...