Hlavní navigace

Squeak: návrat do budoucnosti (10)

13. 4. 2004
Doba čtení: 7 minut

Sdílet

Dnes si mimo jiné řekneme, jak vyhledávat metody podle toho, co po nich skutečně chceme, prohlédneme si podrobnou analýzu běhu našich programů, budeme měnit za běhu definici tříd živým objektům a zkusíme jim třídu dokonce úplně zrušit. Prošťouráme se trochu v objektové paměti a naučíme se používat ladící nástroje. Aby nám to lépe utíkalo, necháme si při tom od Squeaku zazpívat.

Smalltalk je komplexní systém s obrovským množstvím již vytvořeného kódu, který můžete libovolně používat, kopírovat a upravovat. Naučit se v něm rychle orientovat a vyhledat to, co právě potřebujete, je pro efektivní práci naprosto nezbytné.

Vyhledávače metod

Squeak má dva nástroje pro rychlé vyhledávání metod. Prvním z nich se jmenuje Message names a je určen jen k vyhledávání metod podle části selektoru. Má editační pole pro vložení vyhledávaného textu (nebere ohled na velikost písmen), okno se seznamem nalezených zpráv, dále okno se seznamem implementátorů těchto zpráv a ve spodní části okno pro přímé zobrazení a editaci metod.

Jako domácí úlohu si můžete zkusit najít např. jak přimět Squeak, aby vám po HALově vzoru zazpíval písničku Daisy. Pokud najdete dostatečnou odvahu, můžete si vychutnat i duet tiché noci nebo píseň great pretender (úplně jako od Mercuryho).

Druhý nástroj se jmenuje Selector Browser a v zásadě umí to samé. Navíc umožňuje ještě vyhledávat metody podle toho, co mají skutečně dělat. Například by se vám hodila metoda, která vrátí pro dané datum jméno dne v týdnu. Tušíte, že by něco takového už někdo do Squeaku mohl udělat. Dnes je úterý, tak do Selector Browseru zkusíte napsat

Date today. 'Tuesday'

a on vyplivne jméno metody weekday třídy Date. Selector Browseru jsme řekli, že chceme najít metodu, která vrátí jako výsledek úterý, když jako první parametr dostane výraz Date today(dnešní datum). Nalezení vhodných aritmetických operací je pak hračka. Například pro zadání

3. 4. 7

získáme metody +, bitOr: a bitXor:. Musíme si dávat pozor na mezery za tečkami, aby naše zadání nebylo považováno za čísla 3.4 a 7.

Message Tally

Nástroj Message Tally slouží k protokolování běhu programu. Používá se nejčastěji nad blokem programu nebo procesem.

MessageTally tallySends: [ 10 timesRepeat: [ 'hello word' reverse ] ].
MessageTally spyOn: [ Browser fullOnClass: MessageTally ]. 

V prvním případě mimo jiné zjistíme seznam volaných metod a počet opakování každé z nich. Ve druhém případě obdržíme kompletní strom volání včetně absolutní a procentuální doby trvání jednotlivých zanoření doplněný informacemi o využívání paměti. Stejné výsledky, ale v použitelnější formě, vygeneruje třída TimeProfileBrowser.

TimeProfileBrowser onBlock: [ 20 timesRepeat:
    [ Transcript show: 100 factorial printString]
  ]

Nástroj Message Tally můžete nalézt také pod položkou debug ve World menu. Nad procesy se analýza pouští na stanovený počet sekund v nástroji Process Browser příkazem profile messages. O procesech bude ještě řeč později.

Space Tally

Tento nástroj slouží k prostorové analýze instancí tříd. Např.:

SpaceTally new spaceTally: { Morph. Symbol }.

vypíše velikost kódu, počet instancí a prostor alokovaný instancemi tříd Morph a Symbol. Výraz

SpaceTally new printSpaceAnalysis

do externího souboru vygeneruje přehledný prostorový rozbor celé vaší image.

Možnosti, které Squeak nabízí pro práci se zdrojovými kódy, jsou skutečně obrovské a občas mu je mohou závidět i robustní komerční vývojová prostředí konvenčních jazyků, jež musí nasazovat velmi náročné sofistikované prostředky, aby dosáhly téhož. Na poli práce s živými objekty už se smalltalkovské systémy vznáší ve svém balónu vysoko nad nimi.

Reflexe

Reflexe je něco, co je obecně považováno za třešničku na dortu určenou především pro bizarní kousky, kterým se programátoři snaží spíše vyhnout. Smalltalk je oproti tomu plně reflektivní systém, ve kterém reflexe představuje jeden ze základních pilířů jeho funkčnosti.

Jak jsme si již nesčetněkrát zdůraznili, mohou mezi sebou objekty komunikovat pouze prostřednictvím zpráv. Vtip je v tom, že i ten nejjednodušší objekt rozumí zprávám, díky nimž svému okolí dokáže dát vyčerpávající informace o sobě samém. Můžete se zeptat objektu na počet jeho instančních proměnných (class instSize), zjistit hodnotu některé z nich (instVarNamed:) apod. Toho masivně využívá mnoho smalltalkovských nástrojů.

Inspector

Pokud se díváme na Smalltalk jako na objektovou databázi, pak Inspector je ideální nástroj pro její procházení. Spustíte jej nejjednoduššeji pomocí příkazu inspect it vyvolaného nad nějakým výrazem např. ve Workspace. Otevře se jednoduché okno se třemi částmi. V prvním podokně je seznam instančních proměnných. Ten předchází výraz selfzobrazující ve druhém okně textovou reprezentaci objektu a nápis all inst vars zobrazující souhrnnou textovou reprezentaci všech instančních proměnných.

Po vybrání nějaké instanční proměnné z jejich seznamu můžete ve druhém okně její hodnotu libovolně upravovat (aplikuje se příkazem accept). Spodní okno slouží jako konzole s kontextem zkoumaného objektu, tzn. že v ní výraz self tento objekt referencuje. Tedy např. self inspect otevře úplně stejný Inspector. Touto konzolí s objektem můžeme libovolně komunikovat za použití starých známých příkazů do it, print it atd.

Pokud dvakrát kliknete na nějakou instanční proměnnou v jejich seznamu, otevře se další Inspector nad objektem, který referencuje. Takto lze procházet postupně vazby mezi objekty, zkoumat je, měnit, prostě dělat si s objekty cokoliv, co vás napadne.

Explorer

Explorer je nástroj funkčností velmi podobný Inspectoru. Na rozdíl od něj však zobrazuje objekty ve stromové struktuře. Obsahuje rovněž konzoli pro komunikaci s nimi, která má vždy kontext označeného objektu ve stromu. Oproti Inspectoru však nedovoluje přímo měnit hodnotu instančních proměnných.

Inspector i Explorer umožňují i další kousky, například vyhledávat v systému reference na zkoumaný objekt atd.

Debugger

Tento ladící nástroj se nijak výrazně neliší od toho, na co můžete být zvyklí z ostatních vývojových prostředí. Obsahuje laděný kód, který lze postupně krokovat, zanořovat se ve voláních, restartovat krokovanou metodu apod. Nad oknem s kódem je vypsán zásobník volání, v němž je možno se libovolně pohybovat.

Ve spodní části Debuggeru jsou dva inspektory. Levý zkoumá objekt, v jehož kontextu je daná metoda volána, tzn. že zde naleznete seznam instančních proměnných. Pravý inspektor zkoumá kontext krokované metody. Obsahuje proto seznam lokálních proměnných a hodnotu thisContext.

Debuggerů může být samozřejmě otevřeno i několik zároveň, což výrazně usnadňuje ladění vícevláknových aplikací. Kód prováděných metod můžete samozřejmě editovat. Protože po akceptování změn dojde k rekompilaci metody, je opětovně restartována a vnořená volání zrušena.

Nejjednodušší způsob vyvolání debuggeru je provést nad vyhodnocovaným výrazem příkaz debug it.

Netradičně jsou řešeny breakpointy. Ve Squeaku totiž vůbec nejsou. Místo nich se na patřičné místo umístí volání.

self halt.

popřípadě volání metod notify: či error: s vysvětlujícím textem. Metoda halt zapříčiní otevření okna s výpisem zásobníku volání a s tlačítky pro pokračování ve výpočtu, jeho přerušení nebo krokování. Některé jiné implementace Smalltalku (např. VisualWorks) breakpointy mají, ovšem ve skutečnosti jsou jen zástěrkou editoru pro prakticky stejné chování.

Může se to jevit hodně nezvykle, nicméně tento systém přerušování výpočtu oceníte v okamžiku, kdy při něm budete potřebovat provést nějakou dodatečnou akci. Například pokud si usurpujete senzor pro uživatelské vstupy, budete jej potřebovat při ladění uvolnit, k čemuž vám postačí metodu halt vhodně přetížit.

Všimněte si jednoho zásadního rysu Smalltalku. Pro ladění programu se nepoužívá žádný speciální režim. Z tohoto úhlu pohledu Smalltalk ladění vlastně vůbec nezná. Vše řeší svými vlastními prostředky a nerozlišuje mezi během programu, jeho vytvářením a laděním.

Dynamičnost

Smalltalk se nějak musí vypořádávat se situací, kdy upravujete třídy, které mají již fungující živé instance. S metodami není žádná potíž, protože každá se kompiluje zvlášť a jsou potřeba až v okamžiku, kdy jsou skutečně volány. Trochu složitější situace je s definicí samotných tříd. Mějme například následující dvě třídy:

Object subclass: #MyClass1
        instanceVariableNames: 'a b '
        classVariableNames: ''
        poolDictionaries: ''
        category: 'MyClasses'

MyClass1 subclass: #MyClass2
        instanceVariableNames: 'c d '
        classVariableNames: ''
        poolDictionaries: ''
        category: 'MyClasses'

Vytvořme si instanci druhé z nich a spusťme nad ní Inspector.

MyClass2 new inspect

V Inspectoru uvidíme, že má čtyři instanční proměnné. V okamžiku, kdy z definice druhé třídy odstraníme kupříkladu proměnnou d a tuto změnu akceptujeme, okamžitě se projeví i v otevřeném Inspectoru, tzn. že nyní bude mít zkoumaná instance již jen tři instanční proměnné.

Když jsme upravili definici třídy MyClass2, stalo se hned několik věcí. Byly rekompilovány všechny metody této třídy a jejích podtříd. Další věc, kterou Smalltalk musel udělat, bylo, že pro každou dotčenou instanci vytvořil její kopii odpovídající nové struktuře třídy a se starou verzí prohodil její identitu.

V případě, že bychom ve třídě MyClass2 měli metodu, která k instanční proměnné d přistupuje, např.:

d
   ^d

odstranění této proměnné by rovněž proběhlo, ovšem do okna Transcriptu bychom obdrželi varování (d is Undeclared).

Podobně jako lze proměnné odebírat, lze je i přidávat. Po celou dobu byl náš zkoumaný objekt při životě a připraven pracovat. Méně příznivá situace nastane v okamžiku, kdy pod naší instancí uřežeme větev a třídu MyClass2 zcela zrušíme.

Objekt takovou situaci kupodivu přežije. Nicméně jeho třída se změní na AnObsoleteMyClass2. Tato třída a jí podobné mají několik specifik. V první řadě nemá referenci v systémovém slovníku, tzn. že její jméno nelze využít např. pro vytvoření dalších instancí. Její další zvláštností je, že dědí, světe div se, sama od sebe. To, že vůbec ničemu nerozumí, asi nikoho nepřekvapí.

K seznamu zastaralých tříd se lze dopracovat příkazem

Smalltalk obsoleteClasses.

S jejich vznikem se lze setkat především při necitlivém ořezávání image.

CS24 tip temata

Na závěr ještě jednu poznámku. Povšimněte si, že naprostá většina změn (např. editace textu metody, vytvoření třídy apod.) se okamžitě projeví všude tam, kde by se projevit měly, tzn. i v několika oknech různých nástrojů zároveň. To je důsledek masivního využívání návrhového vzoru Observer (Pozorovatel), jímž je celý Smalltalk doslova prolezlý.

Používání vývojových nástrojů ve Squeaku rozhodně není vyčerpávajícím způsobem zdokumentováno. Proto jsem považoval za vhodné tuto problematiku alespoň v krátkosti zmínit. V následujících dílech se opět vrátíme k výkladu jazyka Smalltalk.