Kreirano 2024-09-30 Mon 14:28, pritisni ESC za mapu, m za meni, Ctrl+Shift+F za pretragu
http://courses.cs.washington.edu/courses/cse341/04wi/lectures/16-smalltalk-intro.html
# 64bit version
mkdir pharo
cd pharo
curl -L https://get.pharo.org/64/ | bash
# or if curl is not available:
wget -O- https://get.pharo.org/64 | bash
# 32bit version
curl -L https://get.pharo.org | bash
# or if curl is not available:
wget -O- https://get.pharo.org | bash
pharo Pharo8.0-32bit-a153e04 Pharo.changes Pharo.image pharo-ui pharo-vm
pharo-vm
- Pharo virtuelna mašina (OS-specific)Pharo.image
- Perzistirano stanje/objektiPharo...sources
- Izvorni kod izdanjaPharo.changes
- Promene u izvornom kodu od početka upotrebePharo.image
i Pharo.changes
su fajlovi gde dolazi do promenaPharo.changes
se menja kada menjamo kodPharo.image
se menja kada eksplicitno tražimo perzistenciju stanjaStaje na jedan slajd:
exampleWithNumber: x
"A method that illustrates every part of Smalltalk method syntax."
<menu>
| y |
true & false not & (nil isNil) ifFalse: [self halt].
y := self size + super size.
#($a #a "a" 1 1.0)
do: [ :each |
Transcript show: (each class name);
show: (each printString);
show: ' '].
^x < y
Jednostavna sintaksa/model za pristup svemu.
Alt+Shift+Click
-> Halo hendleri!
size
, +
, at:put:
, do:
, collect:
,
ifTrue:ifFalse:
…4 timesRepeat:
[ Transcript show: 'Hello World!']
[]
.Date today
Date today + 3 days
2 + 3
(point1 x * point2 y) - (point1 y * point2 x)
Obavlja se slanjem poruke drugom objektu
10@20
Nova instanca klase Point
se kreira:
@
10
(SmallInteger
)20
(SmallInteger
)'Pharo', 'is cool!'
=> 'Pharo is cool!'
Novi string se kreira spajanjem dva stringa tako što:
,
'Pharo'
'is cool!'
Slanjem poruke new
ili new:
klasi
Monster new
=> aMonster
U prethodnom primeru Monster
je ime klase a new
je poruka koja se šalje ovoj
klasi. Rezultat je nova instanca klase Monster
.
Kreiranje niza dužine 6.
Array new: 6
=> #(nil nil nil nil nil nil)
Slanjem poruke klasi izvršava se metoda klase (class method).
Tamagoshi withHunger: 10
'Hello World' asMorph openInWindow
Šaljemo poruku asMorph
stringu Hello World
i dobijamo grafički element
(Morph). Dobijenom grafičkom elementu šaljemo poruku openInWindow
da bi ga
prikazali u prozoru.
(ZnEasy getPng: 'http://pharo.org/web/files/pharo.png') asMorph openInWindow
ZnEasy
je ime klase. Klase su globalno dostupe i nazivi počinju sa velikim
slovom.getPng:
je poruka koju šaljemo klasi ZnEasy
. Ova poruka ima argument. U
ovom slučaju to je string 'http://pharo.org/web/files/pharo.png'
:
na kraju naziva i mogu biti
višesložne. Ovakve poruke nazivamo keyword message
.asMorph
šalje se objektu koji vraća poruka getPng:
. Ovo je obična
unarna poruka bez argumenata.openInWindow
se šalje objektu koji vraća poruka asMorph
.Vrsta | Primer |
---|---|
Komentar | "Ovo je komentar" |
Karakteri | $c $# $@ |
String | 'Ovo je string' |
Simbol (jedinstveni string) | #prvi #+ |
Literal niz | #(23 56 89) |
Integer | 45 , 2r10100 |
Real | 1.5 , 6.03e-34 , 4 , 2.4e7 |
Vrsta | Primer |
---|---|
Boolean | true , false |
(instanca True i False ) |
|
Undefined | nil (instanca UndefinedObject ) |
Point | 10@120 |
| var |
var := aValue
obj1 message1. obj2 message2.
^ aValue
[ :x | x + 2 ] value: 5
=> 7
Unarne poruke:
receiver selector
9 squared
Date today
Binarne poruke:
receiver selector argument
2 + 3
3 @ 4
Keyword poruke:
receiver key1: arg1 key2: arg2
2 between: 10 and: 20
5 to: 10 do: [ :i | Transcript show: i ]
receiver selector
Primer:
10000 factorial
Šaljemo poruku factorial
objektu 10000
.
receiver selector argument
Primer:
1 + 3
Šaljemo poruku +
objektu 1
sa parametrom 3
.
receiver keyword1: arg1 keyword2: arg2
Ekvivalentno u Javi ili C-like jezicima:
receiver.keyword1keyword2(arg1, arg2)
U Javi
postman.send(mail, recipient);
postman . send ( mail , recipient );
postman send mail recipient
postman send mail to recipient
U Pharo/Smalltalk-u
postman send: mail to: recipient
ZnClient new
url: 'https://en.wikipedia.org/w/index.php';
queryAt:'title' put:'Pharo';
queryAt:'action' put:'edit';
get
new
je unarna poruka koja se šalje klasi ZnClient
queryAt:put:
je keyword poruka sa dva argumentaget
je unarna poruka;
je specijalan operator koji zovemo kaskada (cascade) - šaljemo poruku
istom objektu primaocu.Integer>>factorial
factorial
"Answer the factorial of the receiver."
self = 0 ifTrue: [^ 1].
self > 0 ifTrue: [^ self * (self - 1) factorial].
self error: 'Not valid for negative integers'
ifTrue:
je poruka koja se šalje Boolean
objektu koji vraća poruka =
poslata objektu self
sa parametrom 0
.ifTrue:ifFalse:
, ifFalse:ifTrue:
i ifFalse:
True
i False
i možete ih pročitati. Ne postoji
ništa specijalno u vezi ovih poruka!Šta se dešava kada imamo sukcesivne poruke istog tipa?
1000 factorial class name
> 'LargePositiveInteger'
ekvivalentno je sa:
(((1000 factorial) class) name)
(Msg) > Unary > Binary > Keywords
Ova pravila redukuju potrebu za navođenjem zagrada.
2 + 3 squared
> 2 + 9
> 11
squared
+
2 raisedTo: 3 + 2
> 2 raisedTo: 5
> 32
+
raisedTo:
Color gray - Color white = Color black
> aGray - aWhite = aBlack
> aBlack = aBlack
> true
-
pa onda =
1 class maxVal + 1
> 1073741824
class
, unarna maxVal
, binarna +
1 class
> SmallInteger
1 class maxVal
> 1073741823
1 class maxVal + 1
> 1073741824
(1 class maxVal + 1) class
> LargePositiveInteger
0@0 extent: 100@100 bottomRight
> Message not understood
> 100 does not understand bottomRight
Moramo koristiti zagrade:
(0@0 extent: 100@100) bottomRight
> (aPoint extent: anotherPoint) bottomRight
> aRectangle bottomRight
> 100@100
Samo poruke:
+
3 + 2 * 10
> 5 * 10
> 50
Moramo pisati sa zagradama:
3 + (2 * 10)
> 3 + 20
> 23
1/3 + 2/3
> 7/3 /3
> 7/9
Moramo pisati:
(1/3) + (2/3)
>1
.
je separator:
expression1.
expression2.
expression3
Primer:
Transcript cr.
Transcript show: 1.
Transcript show: 2
.
je separator a ne terminacija.| macNode pcNode |
macNode := Workstation withName: #mac.
macNode sendPacket: 'Hello World'
;
)|c|
c := OrderedCollection new.
c add: 1.
c add: 2
Ekvivalentno je sa:
OrderedCollection new
add: 1;
add: 2
add: 2
se šalje istom prijemniku poruke add: 1
a to je objekat vraćen
porukom new
.fct(x) = x*x + 3
fct := [ :x | x * x + 3 ]
fct(2)
fct value: 2
[ :each | Transcript show: each abs printString; cr ]
#(1 2 -4 -86) do: [ :each | Transcript show: each abs printString; cr ]
> 1
> 2
> 4
> 86
[]
|
(:each
):each
dobija redom
vrednosti niza.value:
poruka se koristi za evaluaciju bloka.(1/0)
-> Greška
Ali nema greške pri definiciji bloka:
[1/0]
> [1/0]
[1/0].
1 + 2
> 3
Obavlja se eksplicitno slanjem poruke value
.
[2 + 6] value
> 8
[1/0] value
> Error
Blokovi mogu imati argumente (kao i metode):
[ :x | x + 2 ]
:x
predstavlja argument blokax + 2
je telo bloka[ :x | x + 2 ] value: 5
> 7
value:
izvršava blok sa parametrom 5
.
x
dobija vrednost 5
za vreme izvršavanja bloka.Evaluacija bloka vraća vrednost poslednjeg izraza u bloku:
[:x|
x + 33.
x + 2] value: 5
> 7
| add2 |
add2 := [ :x | x + 2 ].
add2 value: 5.
>7
add2 value: 33
> 35
Primer:
[ :x :y | x + y ]
:x :y
su argumenti bloka.
Kako se izvršava blok sa dva argumenta?
[ :x :y | x + y ] ??? 5 7
> 12
[ :x :y | x + y ] value: 5 value: 7
> 12
value:value:
je poruka sa dva argumenta koja se šalje bloku sa parametrima
5
i 7
Blokovi mogu definisati lokalne privremene varijable (kao i metode):
Collection>>affect: anObject when: aBoolean
self do: [ :index | | args |
args := ....
aBoolean
ifTrue: [ anObject do: args ]
ifFalse: [ anObject doDifferently: args ] ].
| args |
definiše privremenu varijablu args
args
postoji samo za vreme izvršavanja bloka
Kada se ^
izvrši unutar bloka dolazi do povratka iz metode u kojoj je blok
definisan:
Integer>>factorial
"Answer the factorial of the receiver."
self = 0 ifTrue: [ ^ 1 ].
self > 0 ifTrue: [ ^ self * (self − 1) factorial ].
self error: 'Not valid for negative integers'
0 factorial
>1
42 factorial
>1405006117752879898543142606244511569936384000000000
1 to: 4 do: [ :i | Transcript << i ]
> 1
> 2
> 3
> 4
to:do:
je poruka poslata broju (instanci Integer
klase)timesRepeat:
, to:by:do:
, whileTrue:
,
whileFalse:
…4 timesRepeat: [self doSomething ]
0 to: 100 by: 3 do: [ :i | ... ]
whileTrue:
[ ... ] whileTrue: [ ... ]
Izvršava argument dok god je vrednost prijemnika true
Color >> atLeastAsLuminentAs: aFloat
| revisedColor |
revisedColor := self.
[ revisedColor luminance < aFloat ]
whileTrue: [ revisedColor := revisedColor slightlyLighter ].
^ revisedColor
whileTrue
Izvršava blok prijemnik sve dok je vrednost true
:
[ ... ] whileTrue
Analogno, postoje i whileFalse
i whileFalse:
Implementirane kao poruke.
Pitamo kolekciju da uradi iteraciju svojih elemenata:
#(1 2 -4 -86) do: [ :each | Transcript show: each abs printString; cr ]
> 1
> 2
> 4
> 86
do:
- iteracijacollect:
- iteracija i mapiranje elemenataselect:
- selekcija elemenata na osnovu predikatareject:
- eliminacija elemenata na osnovu predikatadetect:
- vraća prvi koji zadovoljava uslovdetect:ifNone:
- vraća prvi koji zadovoljava uslov ili podrazumevanu
vrednost ukoliko takvog nema u kolekcijiincludes:
- test da li elemenat pripada kolekciji#(2 3 7) collect: [ :each | each raisedTo: 2 ]
> #(4 9 49)
#(2 9 7) detect: [ :i | (i \\ 3) = 0 ]
> 9
3 timesRepeat: [ Transcript show: 'Hello' ; cr ].
Date today + 12 days.
Point linesOfCode.
Smalltalk allClasses size.
Smalltalk allClasses inject: 0 into: [ :sum :each | sum + each linesOfCode ].
VGTigerDemo runDemo.
SystemNavigation new browseAllSelect:
[:m| m primitive isZero and: [m pragmas notEmpty]].
true
je jedinstvena instanca klase True
false
je jedinstvena instanca klase False
True
i False
nasleđuju klasu Boolean
U Pharo Bulovi izrazi nisu ništa specijalno:
& | not
or:
and:
- lazyxor:
ifTrue:ifFalse:
ifFalse:ifTrue:
false & (1 error: 'crazy')
−> an error
Argument (1 error: 'crazy')
se evaluira jer ova operacija ne koristi “lenju
evaluaciju” (lazy).
false and: [ 1 error: 'crazy' ]
−> false "no error!"
Argument [ 1 error: 'crazy' ]
se ne evaluira jer nije neophodno za određivanje
vrednosti izraza - koristi se “lenja evaluacija”.
U Pharo uslovi su poruke koje se šalju Bulovim vrednostima i blokovima.
ifTrue:ifFalse
je porukaWeather isRaining
ifTrue: [ self takeMyUmbrella ]
ifFalse: [ self takeMySunglasses ]
ifTrue:ifFalse
je poruka koja se šalje objektu koji ima Bulovu
vrednost (ili je true
ili je false
).ifTrue
i ifTrue:ifFalse:
ifTrue: []
i ifTrue: [] ifFalse: []
su različite poruke.
LogicalFont>>forceItalicOrOblique
self slantValue = 0
ifTrue: [ slantValue := 1 ]
Analogno, ifFalse:[]
i ifFalse: [] ifTrue: []
su različite poruke.
ifEmpty
i ifNotEmpty:
Implementirano za kolekcije.
myProtocol
ifEmpty: [ 'As yet unclassified' ]
> 'As yet unclassified' ili myProtocol
Implementacija:
Collection>>ifEmpty: aBlock
^ self isEmpty
ifTrue: [ aBlock value ]
ifFalse: [ self ]
self listItems
ifNotEmpty: [ :aList | aList at: index ]
> element liste na indeksu "index" ili sama lista ukoliko je prazna
Implementacija:
Collection>>ifNotEmpty: aBlock
^self isEmpty
ifTrue: [self]
ifFalse: [aBlock cull: self]
cull:
- evaluira prijemnik sa jednim ili nula parametara u zavisnosti od toga
koliko parametara prijemnik prihvata.
Slanje poruke nadklasi
Object subclass: #Point
instanceVariableNames: 'x y'
classVariableNames: ''
package: 'Kernel-BasicObjects'
self
messageSelectorAndArgumentNames
"comment stating purpose of message"
| temporary variable names |
statements
self
Game >> initializePlayers
self players
at: 'tileAction'
put: ( MITileAction director: self )
je ekvivalentno sa:
Game >> initializePlayers
self players
at: 'tileAction'
put: ( MITileAction director: self ).
^ self "<−− optional"
Class
služi za pregled i definiciju metoda klase.Point class >> x: xInteger y: yInteger
"Answer an instance of me with coordinates xInteger and yInteger."
^ self basicNew setX: xInteger setY: yInteger
Dodajemo 2 u skup:
Set new add: 2
>2
Rezultat izraza je 2 a ne skup!
Set>>add: newObject
"Include newObject as one of the receiver's elements, but
only if not already present. Answer newObject."
[...]
^ newObject
add:
vraća argument a ne objekatSet new add: 2
>2
|s|
s := Set new.
s add: 2.
s
yourself
Object >> yourself
^ self
Set new
add: 2;
yourself
> aSet
add:
i yourself
se šalju skupu;
vraća objekat koji vraća poruka yourself
- u našem slučaju skup.Counter class >> withValue: anInteger
self new
value: anInteger;
yourself
Counter withValue: 10
vraća Counter
klasu umesto njenu instancu.Counter class >> withValue: anInteger
self new
value: anInteger;
yourself
je ekvivalentno sa:
Counter class >> withValue: anInteger
self new
value: anInteger;
yourself.
^self
Gde je self
prijemnik poruke withValue:
tj. klasa Counter
.
Counter class >> withValue: anInteger
^self new
value: anInteger;
yourself
Podklasa:
Object
korenska klasa svake klase.ProtoObject
ali je njena upotreba specijalna pa je nećemo
razmatrati.
Nasleđivanje je:
Obrada poruke se obavlja u dva koraka:
self
ključne rečiself
ključna reč se koristi u implementaciji metoda i uvek predstavlja
objekat prijemnik.
A new foo
a šta izraza B new foo
?A new bar
a šta izraza B new bar
?super
ključne reči
super
predstavlja objekat prijemnik ali pretraga poruka započinje u nadklasi
klase u kojoj se super
nalazi.A new bar
, B new bar
i C new bar
?self
se određuje dinamički
U metodi A>>bar
kod ^self foo
ne znamo do vremena izvršavanja na koji foo
se poziv odnosi. To zavisi od klase konkretnog objekta prijemnika.
super
se određuje statički
B>>foo
referencira A>>foo
putem super
.super
.doesNotUnderstand
Object
klasi signalizira izuzetak
MessageNotUnderstood
.
Boolean
tipaU Pharo Boolean tip ima odličan dizajn:
&, |, not
- eageror:, and:
- lazyifTrue:, ifTrue:ifFalse, ...
U svetu gde imate samo dve vrednosti: true
i false
i razmenu poruka
not
?or
?not
false not
> true
true not
> false
Rešenje ne koristi uslove.
Uslovi bi svakako morali da budu bazirani na Bulovom tipu.
Boolean
(apstraktna), True
i False
true
je singlton instanca klase True
false
je singlton instanca klase False
U OOP, izbor iskazujemo:
Primer:
x open
x
može biti fajl, prozor, alat…x
not
operacijeFalse >> not
"Negation −− answer true since the receiver is false."
^ true
True >> not
"Negation −− answer false since the receiver is true."
^ false
Boolean
klaseBoolean
je abstraktna klasaTrue
i False
koje implementiraju:
&
i not
and:
, or:
, ifTrue:
, ifFalse:
, ifTrue:ifFalse:
,
ifFalse:ifTrue:
Boolean>>not
"Abstract method. Negation: Answer true if the receiver is
false, answer false if the receiver is true."
self subclassResponsibility
Or
operacijetrue | true −> true true | false −> true true | anything −> true
false | true −> true false | false −> false false | anything −> anything
Or
operacije u Boolean
klasiBoolean >> | aBoolean
"Abstract method. Evaluating Or: Evaluate the argument.
Answer true if either the receiver or the argument is true."
self subclassResponsibility
Or
operacije u klasi False
false | true −> true false | false −> false false | anything −> anything
False >> | aBoolean
"Evaluating Or −− answer with the argument, aBoolean."
^aBoolean
Or
operacije u klasi True
true | true −> true true | false −> true true | anything −> true
True >> | aBoolean
"Evaluating Or −− answer true since the receiver is true."
^true
A pošto je prijemnik true
možemo uraditi sledeće:
True >> | aBoolean
"Evaluating Or −− answer true since the receiver is true."
^self