Hlavní navigace

Squeak: návrat do budoucnosti (5)

Pavel Křivánek 9. 3. 2004

"Never forget class struggle [Mao Ce-tung]," aneb dnes se podíváme na zoubek třídám ve Smalltalku.

Smalltalk je velmi konzistentní jazyk. Definuje několik základních pravidel, která jsou bez výjimky dodržována.

  • vše je objekt
  • objekty komunikují pouze zasíláním zpráv
  • každý objekt má svou třídu
  • každá třída má svého předka

Díky striktnímu dodržování těchto pravidel si Smalltalk udržuje svou jednoduchost a eleganci. Zmíněná pravidla předurčují celou třídní organizaci Smalltalku a velmi transparentně a jakoby mimochodem přinášejí do tohoto jazyka řadu užitečných vlastností, se kterými se většina ostatních programovacích jazyků vypořádává jen stěží.

V minulém dílu jsme se zmínili o tom, že každý objekt má svou příslušnost ke třídě trvale přiřazenu a nelze ji běžným způsobem změnit. Jedná se o referenci v rámci fyzického uložení objektu v objektové paměti. Je-li objekt reprezentací konkrétních dat, pak třída definuje operace nad těmito daty, přičemž konkrétní data jsou velmi silně zapouzdřena a jsou přístupná pouze pomocí poskytnutých operací.

Data objektu jsou reprezentována jeho instančními proměnnými, což jsou v podstatě reference na další objekty. Instanční proměnné jsou osobním majetkem objektu a pouze on rozhoduje o tom, jak a zda vůbec tato data zveřejní. Instanční proměnné jsou výhradně privátní.

Objety jedné třídy mají možnost společně sdílet data pomocí třídních proměnných. Jedná se o data společná všem instancím dané třídy a mají rovněž privátní charakter.

Nyní již máme základní informace pro to, abychom se pokusili vytvořit si svoji první třídu. Asi vás již moc nepřekvapí, že se nejedná o syntakticky specifickou operaci. Třídy se prostě vytvářejí obyčejným zasíláním zpráv.

Object subclass: #MyClass
instanceVariableNames: 'instVar1 instVar2 '
classVariableNames: 'ClassVar1 ClassVar2 '
poolDictionaries: ''
category: 'MyClasses'

Zkusíme si nyní podrobně rozepsat, čeho jsme to vlastně docílili.

Třídě Object jsme poslali zprávu pro vytvoření potomka, která má pět parametrů. Prvním parametrem je jméno nové třídy, které je předáváno jako symbol. Jméno třídy musí začínat velkým písmenem a musí být v celém prostředí Squeaku unikátní.

Dalším parametrem je seznam instančních proměnných uvedený v řetězci, kde identifikátory jednotlivých proměnných jsou odděleny mezerami. Jejich jména by měla začínat malým písmenem. Stejně jako u lokálních proměnných se neuvádějí typy.

Následujícím parametrem je řetězcový seznam identifikátorů třídních proměnných, z nichž každá začíná velkým písmenem.

Posledním parametrem je kategorie třídy. Třídy jsou organizovány do tzv. systémových kategorií. Na jejich pojmenování příliš nezáleží a ani sémanticky nehrají žádnou úlohu. Slouží pouze pro lepší orientaci programátorů ve standardních třídách a vlastních projektech. Rovněž usnadňují export a import zdrojových kódů. Třídy obsažené v jedné kategorii spolu nějakým způsobem souvisejí, většinou tvoří určitý logický celek, projekt či jeho část.

Záměrně jsem vynechal parametr definující sdílené slovníky (poolDictionaries). Nechávejte jej prázdný (prázdný řetězec). Sdílené slovníky nejsou příliš významným rysem jazyka Smalltalk a povíme si o nich později.

Jak můžete vidět, Smalltalk používá pouze jednoduchou dědičnost. Nezná ani pojem rozhraní (interface) známý např. z Javy nebo C#. Díky dynamické typové kontrole jsou vícetypovostní koncepty podstatně méně potřebné a Smalltalk je natolik flexibilní, že je lze poměrně snadno doplnit. To pro případ, že by vám skutečně chyběly. Smalltalk nepoužívá vnořené třídy.

Možná zatím marně hledáte něco jako jmenné prostory. Prozatím můžeme zůstat u tvrzení, že Squeak jmenné prostory nemá. Není to sice tak úplně pravda, ovšem prostředky, které Squeak v tomto ohledu nabízí, se používají v praxi jen minimálně. Absence jmenných prostorů krom pár výhod samozřejmě přináší i některé problémy, které se programátoři snaží omezit například specifickými prefixy jmen tříd (B3D pro třídy projektu Balloon3D apod.). Nutno dodat, že vzhledem k odlišnému přístupu výstavby programů se problémy s duplicitou globálních identifikátorů objevují jen minimálně, a jak bylo řečeno, Squeak má prostředky, jak je v případě nouze řešit.

Podobně jako jsou třídy organizovány v systémových kategoriích, jsou i jednotlivé metody v rámci tříd organizovány do kategorií. Kategorie metod mají rovněž pouze informativní charakter a nemají žádný sémantický význam. Jejich pojmenování je zcela v rukou programátora, ovšem je vhodné se držet některých konvencí, aby se ve vašem kódu mohl snadno kdokoliv rychle zorientovat. Často používanými jmény kategorií jsou například:

Tabulka č. 550
accessing přístup k vlastnostem objektů
instance creation
initialize
metody související s vytvářením a inicializací objektů
copying kopírovací konstruktory
printing výpisy textové reprezentace objektu do streamu
fileIn/Out serializace
testing metody typu isSomething apod.
convrting konverze objektů (asSomething)
private neveřejné metody
examples příklady

Snaha řešit věci co nejjednoduššeji se dotkla i organizace metod. Smalltalk nepoužívá přístupová práva k metodám (public, protected, private apod.). Všechny metody dané třídy včetně metod v kategorii private jsou veřejné (public). Připomeňme, že objekty mezi sebou mohou komunikovat pouze zasíláním zpráv, a tudíž si nelze žádným jiným způsobem zajistit přístup k instančním a třídním proměnným. Data objektu mohou zprostředkovávat pouze jeho metody.

Jedno ze základních pravidel Smalltalku říká, že každá třída má svého předka. Jak je tomu ale u nejobecnějších tříd? Například základní třída třídní hierarchie – Object – musí tím pádem být také potomkem nějaké třídy. Ano, i třída Object má svého předka. Je jím třída ProtoObject, která definuje naprosté minimum vlastností, které musí mít všechny objekty ve Smalltalku (např. metody isNil:,ifNil: apod.). Nicméně podle daných pravidel Smalltalku musí i třída ProtoObject dědit z nějaké třídy. Abychom také někdy skončili, použije se zde zacyklení. Třída ProtoObject dědí sama ze sebe. Znamená to, že je popsána natolik obecně, že dokáže popsat i sebe samu.

Při vytváření vlastních tříd používejte třídu Object a její potomky a nepokoušejte se vytvořit vlastní smyčky v dědičnosti. Standardním způsobem by se vám to nepovedlo, protože jejich vznik je kontrolován a zakázán.

Pro dědění speciálních tříd se používá ještě metoda, jejíž jméno nezačíná na subclass:, ale na variableSubclass:. Vyskytuje se například u odvozování tříd ze třídy Array apod. Pokud je tento speciální druh dědičnosti třeba využít, upraví Squeak vaši definici třídy sám dle potřeby.

Metatřídy

Další ze základních pravidel Smalltalku definuje, že každý objekt má svoji třídu. Protože ve Smalltalku jsou vše objekty, a tudíž i třídy jsou objekty, musí to nutně znamenat, že rovněž třídy mají svoje třídy. Tyto třídy se označují jako metatřídy.

Význam tříd spočívá v tom, že popisují chování objektů (svých instancí). Podobně metatřídy popisují chování tříd. Jak jsme již jednou poznamenali, jsou třídy v podstatě globálně přístupné proměnné (objekty).

Na první pohled může být existence metatříd poměrně matoucí, ale není třeba v nich hledat nic záhadného. Jejich význam snad osvětlí následující příklad:

Mějme třídu Time uchovávající informace o čase pomocí jedné instanční proměnné seconds. Třída Time má mimo jiné metody hours a minutes, které vracejí hodnotu vypočítanou z počtu sekund uloženého v instanční proměnné seconds. Jsou to metody, jejichž výsledek závisí na aktuálních datech konkrétní instance a jsou popsány ve třídě. My ovšem potřebujeme konkrétní instanci nějakým způsobem vytvořit a referenci na ni vložit do proměnné, kterou si pojmenujeme třeba time. Chtěli bychom, aby to vypadalo například nějak takhle.

| time |
time new: Time.

Problém je v tom, že se pokoušíme zavolat zprávu neinicializovaného objektu time (má hodnotu nil). Potřebovali bychom mít už alespoň jednu existující inicializovanou instanci. Vyřešíme to tak, že o vytvoření instance požádáme přímo třídu Time.

| time |
time := Time new.

Nyní už je vše v pořádku, ovšem kam umístit metodu new, když ve třídě Time být nemůže, protože by popisovala chování instance? Zde využijeme právě metatřídu. Jak konkrétně, to si ukážeme příště.

Třída implementuje zprávy, které budou vykonávat její instance, metatřídy implementují zprávy, které budou vykonávat třídy. Jak jsme si minule řekli, třídu konkrétního objektu zjistíme pomocí metody class, tedy

time class = Time

Podobně se můžeme zeptat na třídu i třídy Time. To, co obdržíme, je právě její metatřída

Time class = Time class

Tedy metatřída třídy Time se jmenuje Time class(pravá strana rovnosti). Výraz pro získání metatřídy a její jméno jsou si rovny. Protože samozřejmě i metatřídy jsou objekty, i ony mají svoji třídu, která má rovněž svoji třídu.

Time class class = Metaclass
Time class class class = Metaclass class
Time class class class class = Metaclass class

Jak vidíte, narazili jsme na další elegantní smyčku.

Metatřída může implementovat celou řadu metod. Nejčastější jsou konstruktory, což jsou libovolné metody metatřídy vytvářející nějakým způsobem instance. Například metatřída třídy Time má konstruktor now, který vytvoří instanci obsahující aktuální čas.

Time now asString = '3:43:25 pm'

Další příklad konstruktoru můžete vidět v našem starém známém prográmku Hello world:

Speaker woman say: 'hello world'.

Třídě Speaker zašleme zprávu woman, čímž se vytvoří objekt reprezentující hlasovou syntézu ženského hlasu, kterému následně pošleme zprávu say: s požadovanou frází.

Asi vás napadá celá řada nových otázek. Jak a kam se ve Smalltalku píší zdrojové kódy, když třídy se vytvářejí pomocí metody. Jak a kam se píší metody? Jak vlastně metody vypadají? Jak se vytvářejí metatřídy? Jak je to s destruktory nebo třeba kopírovacími konstruktory? Pokud jste se již pokusili si Squeak nainstalovat, možná začínáte některé odpovědi tušit. Pokud ne, budete si na ně muset počkat do dalších dílů.

Našli jste v článku chybu?

17. 5. 2012 22:20

elendil (neregistrovaný)

Je to jednoduche :)

scitej: prvyScitanec s: druhyScitanec
Transcript show: (prvyScitanec + druhyScitanec).

Su tri druhy metod v ST - unarne, binarne a keyword. Unarne su bez parametra (ako napr #factorial pri triede Number), binarne je klasicke #+ a keyword su prave tie co som popisal - seria klucovych slov. Tych slov moze byt viacero, aj ked viac ako 5 sa povazuje za chybu designu. Keyword metody sa deklaruju takto:

keyWord1: parameter1 keyWord2: parameter2 ... keyWordN: parameterN

Aj ked s…


21. 10. 2008 5:59

lnx_bfu (neregistrovaný)
"Objety jedné třídy mají" - objeKty.
120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

Root.cz: 250 Mbit/s po telefonní lince, když máte štěstí

250 Mbit/s po telefonní lince, když máte štěstí

Podnikatel.cz: Víme první výsledky doby odezvy #EET

Víme první výsledky doby odezvy #EET

Vitalia.cz: Znáte „černý detox“? Ani to nezkoušejte

Znáte „černý detox“? Ani to nezkoušejte

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

DigiZone.cz: Flix TV má set-top box s HEVC

Flix TV má set-top box s HEVC

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Vitalia.cz: Manželka je bio, ale na sex moc není

Manželka je bio, ale na sex moc není

Vitalia.cz: To není kašel! Správná diagnóza zachrání život

To není kašel! Správná diagnóza zachrání život

Lupa.cz: Google měl výpadek, nejel Gmail ani YouTube

Google měl výpadek, nejel Gmail ani YouTube

Podnikatel.cz: Podnikatelům dorazí varování od BSA

Podnikatelům dorazí varování od BSA

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

Root.cz: Vypadl Google a rozbilo se toho hodně

Vypadl Google a rozbilo se toho hodně

Vitalia.cz: Často čůrá a má žízeň? Příznaky dětské cukrovky

Často čůrá a má žízeň? Příznaky dětské cukrovky

DigiZone.cz: Rádio Šlágr má licenci pro digi vysílání

Rádio Šlágr má licenci pro digi vysílání

Měšec.cz: Jak vymáhat výživné zadarmo?

Jak vymáhat výživné zadarmo?

Podnikatel.cz: Babiš: E-shopy z EET možná vyjmeme

Babiš: E-shopy z EET možná vyjmeme

Vitalia.cz: Mondelez stahuje rizikovou čokoládu Milka

Mondelez stahuje rizikovou čokoládu Milka

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0