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 := aValueobj1 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 ZnClientqueryAt:put: je keyword poruka sa dva argumentaget je unarna poruka; je specijalan operator koji zovemo kaskada (cascade) - šaljemo poruku
istom objektu primaocu.Integer>>factorialfactorial
"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 7Blokovi 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 argsargs 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 Truefalse je jedinstvena instanca klase FalseTrue i False nasleđuju klasu BooleanU Pharo Bulovi izrazi nisu ništa specijalno:
& | notor: 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'
selfmessageSelectorAndArgumentNames
"comment stating purpose of message"
| temporary variable names |
statements
selfGame >> 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
yourselfObject >> 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.doesNotUnderstandObject 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?notfalse not
> true
true not
> false
Rešenje ne koristi uslove.
Uslovi bi svakako morali da budu bazirani na Bulovom tipu.
Boolean (apstraktna), True i Falsetrue je singlton instanca klase Truefalse je singlton instanca klase False
U OOP, izbor iskazujemo:
Primer:
x open
x može biti fajl, prozor, alat…xnot 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 notand:, 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 Falsefalse | true −> true false | false −> false false | anything −> anything
False >> | aBoolean
"Evaluating Or −− answer with the argument, aBoolean."
^aBoolean
Or operacije u klasi Truetrue | 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