Pět IT technologií, které nejvíce ovlivnily mou tvorbu

Pět IT technologií, které za poslední dobu v pozitivním slova smyslu nejvíce ovlivnily mou tvorbu:

  • Sublime text je pokročilý textový editor. Když píšu pokročilý, opravdu myslím pokročilý, ne něco typu “poznámkový blok se zvýrazněnou syntaxí několika klíčových slov”. Je především rychlý a hezký a k tomu obsahuje několik fíčur, které jsou zkrátka dokonalé. Za všechny například Goto Anything, Multiple Selection (nejvíc návykové!), Quick add next, Jump back a mnoho dalších vychytávek.

    Nikdy bych nevěřil, že nastane doba, kdy budu mít rád nějaké vývojové prostředí. Kdysi jsem používal PSPad. Jako jo, nebyl to úplně příšerný program jako některé jiné, ale zase to prakticky nic neumělo. Obarvovalo to kód, mělo to chytré taby a umělo to zkonvertovat malá písmena na velká… Zkrátka hotový wow efekt. Přešel jsem časem na NetBeans, které sice mělo dobrý styl napovídání a nějaké ty snippety, ale celkově to bylo pooomaaalééé, škaredé a éééé…

    Takže Sublime Text FTW, když si porovnám, jak se mi tvořily stránky před ST a po ST, tak už se do předchozího stavu fakt nechci nikdy vrátit.

  • Github, protože změnil opensource. Github zde nedávám proto, že bych ho já sám nějak extra používal, ale hlavně proto, že ho používají jiní. Github se stal de-facto standardem v oblasti OSS a většina OSS, které alespoň já potkávám, sídlí na Githubu. V podstatě platí, že když sháním nějakou knihovnu nebo třeba doplněk do Sublime textu, tak buď to najdu v nějakém package manageru nebo to najdu na Githubu. Instalace pak typicky probíhá tak, že v terminálu napíšu git clone url nebo tam kliknu na “Clone in Desktop”, ani terminál není potřeba. Žádné stahování zipů nebo tarů jako někdy v pravěku… K tomu na Githubu většinou najdu i dokumentaci, pro OS X i pro iPhone máme skvělou aplikaci a jako bonus je celý Github mocinky hezký!

  • Markdown je značkovací jazyk, který lze použít pro psaní textů na web. U nás je asi známější Texy!, Markdown je něco trochu podobného, akorát je mnohem jednodušší, celosvětově mnohem známější a hlavně mnohem používanější. Když jsem zmiňoval dokumentaci na Githubu, tak ta je typicky psaná v Markdownu a dokonce tam jsou v Markdownu i německé zákony ;-).

    Je to nejuniverzálnější formát, v jakém lze dnes psát nějaký jednoduše formátovaný text. Chcete ho převést do HTML? Každý jazyk má na to knihovnu. Chcete jiný formát? Pandoc převede Markdown do čehokoliv. Chcete psát formátovaný text v aplikacích jako je deník One day nebo iA Writer? Použijte Markdown! S nějakým HTML si můžete leda trhnout nohou ;-). Markdown by zkrátka měl být všude jako defualtní syntax pro psaní textu.

  • Python, aneb i programovací jazyk můžete mít rádi. Já se primárně neživím programováním, většinou si už jen programuji nějaké utilitky na pár set řádků (i když kdybych to psal v Javě, tak by to bylo pár tisíc řádků), takže potřebuji především nějaký programovací jazyk, který nebude otravně složitý a zároveň je mainstreamový, aby se mi nestalo, že pro to nenajdu ani knihovnu pro parsování … Markdownu.

    Python je přesně takový. Jednoduchý, čistý, mainstreamový s hromadou knihoven pro všechno. Předtím jsem programoval v C#. Jenže když jsem tehdy potřeboval nějakou blbost na pár řádků, tak to znamenalo spustit Visual Studio, založit projekt, vytvořit šest interfaců, napsat třicetkrát Dictionary<string, int> foo = new Dictionary<string, int>(), zkompilovat, dopsat chybějící středník, zkompilovat, zaradovat se, že to běží. Pak to chtělo překopírovat exe soubor někam víc po ruce než je umístění ~/Documents/VS Projects/2013/Projects/My Projects/MyApplication007/Content/Ballmer/bin/release, pak si člověk uvědomí, že když změní zdroják, bude muset exe soubor kopírovat znova, takže radši změní PATH nebo vytvoří zástupce pro ten exe soubor nebo já vlastně nevím jak to rozumně řešit… No a teď s Pythonem na Macu vytvořím jeden .py soubor v ~/Utilities/, napíšu třicet řádků kódů a to je vše.

  • OS X má zkrátka blíže k Linuxu než Windows, takže spousta vývojových věcí, které mají primárně běžet na Linuxu, běží na OS X lépe než na Windows a díky existujícím repozitářům typu MacPorts není jejich instalace porod jako tomu bývá na Windows. Přestože jsem měl Windows daleko déle než OS X, tak OS X rozumím více a funguje mi lépe. A co si budeme povídat, terminál je terminál :-).

Disclaimer: Zdrojový Markdown tohoto článku byl napsán v Sublime textu na OS X a byl nahrán na Github. Do příště vymyslím, jak během psaní článku využiji Python.

A jaké technologii nejvíce ovlivnily vaši tvorbu?

Pitomý Putna

Kauza Putna rozdělila republiku do přibližně dvou skupin. První skupinu tvořili lidé typu “profesorem by měl být ušlechtilý, úctyhodný a moudrý člověk na vysoké morální úrovni, neměl by sledovat televizi Nova a měl by se smát humoru Jana Wericha”. Druhou skupinu pak lze charakterizovat pomocí Petra Nečase zhruba takto: “i když se člověk chová pitomě, neměl by to být důvod k neudělení profesury”.

Která skupina byla okamžitě označena jako ta “primitivní” a která jako “intelektuálně osvícená” je asi každému jasné. (Především v závislosti na tom, do které skupiny se řadí on sám.) Tím začala diskuse, jestli má prezident vůbec právo neudělit profesuru a pokud toto právo má mít, tak jestli může být “morální poklesek” validním důvodem pro neudělení profesury. Vzhledem k tomu, že Zeman poměrně rychle ustoupil, tak se zdá, že alespoň dočasně vyhrála druhá skupina. Hurá, zvolávají v diskusích.

Shame on us, zvolávám já.

Ty dvě skupiny, které jsem nastínil a jejichž zástupce jsem z médií slýchával nejčastěji, totiž obě potichu předpokládají, že když jde člověk na demonstraci s transparentem “Katolické buzny zdraví Bátoru”, tak se jedná o něco špatného, nemorálního, možná snad i amorálního!

Odkud se tento axiom vzal? Dokážu si představit, že na tom transparentu lidé vidí humor, satiru, ironii nebo dokonce sarkastický metahumor. Nedokážu si ale představit, jak tam někdo může vidět vulgárnost či snad dokonce nějakou urážku. Nebo cokoliv jinak špatného. Vždyť podobných příspěvků je Twitter plný… Jako přes kopírák platí totéž pro to jeho předvolební video, snad je jen daleko méně zábavné.

Prezident, premiér i ministr školství, asi tři nejvýznamnější postavy v této kauze, přitom pokládají Putnovo chování za nějakým způsobem špatné. Zkrátka inteligentní a morálně správný člověk přece nechodí na demonstrace, a když už tam je, tak nenosí transparent, a když už ano, tak jedině s nápisem “Neberte si to prosím osobně, pane Bátoro, ale nesouhlasím s Vámi” a na druhé straně logo EU s textem “Tento transparent vznikl za podpory EU v rámci projektu Demonstrace pro každého“.

Tím, že Martin Putna nesl onen transparent, neudělal nic špatného ani nemorálního a nemělo by mu to tak bránit stát se profesorem, i kdyby jsme se nakonec dohodli na tom, že profesor by opravdu měl být morálně správný člověk.

Netolerance ostatních mi zase flákla další facku.

Jak se Zeman prolhal na Hrad

Dne 26. 1. 2013 zvítězil Miloš Zeman v první přímé volbě prezidenta. Celou jeho předvolební kampaň doprovázela lež a manipulace a to v takovém měřítku, že lze oprávněně říci, že se pan Zeman na ten Hrad zkrátka prolhal. A protože lidé rádi zapomínají a staré články se blbě dohledávají, sepsal jsem tento článek, který shrnuje vybrané lži, které Miloš Zeman, případně jeho tým, aktivně šířil. Až se budu za tři roky s někým dohadovat a ten někdo mi bude tvrdit, že Miloš Zeman nikdy v kampani nelhal, tak mu aspoň budu moci poslat odkaz na tento článek. Žádné větší ambice tento text nemá. Všechny zmíněné lži jsou jen citacemi z existujících článků na zpravodajských webech.

Lež první: Zemanovy lži: „Schwarzenberg mě nevyhnal!” tvrdí Táňa Bílá

„Zeman soupeři vytkl, že se prohlásil za ochránce chudých a slabých, když podle něj dělá přesně opak. Své tvrzení se snažil doložit tím, že místopředseda vlády v 90. letech zrestituoval zámek v Čimelicích, vyhnal z prostor vysokým nájmem tamější učiliště pro postižené a dokonce připravil o byt učitelku Táňu Bílou.” píše týden.cz ve svém článku. Článek pokračuje:

„‚Je to lež jak věž!‘ reagovala učitelka Bílá na výrok Zemana. ‚V roce 81/82 byla zrušena filmová škola, kde jsem dvacet let učila. Tam byly asi čtyři podnikové byty, z nichž jsme dostali výpověď. Přešla tam totiž zvláštní učňovka a my jsme se přestěhovali do Písku, kde jsem učila na gymnáziu. Pan Schwarzenberg dostal zámek zpět o devět, deset let později, takže mě skutečně nevyštípal. Nevím, kdo nezodpovědný tohle Zemanovi řekl, asi nějaký trouba.‘”

Lež Druhá: Zeman odmítá vinu v kauze Mostecké uhelné. Fakta však mluví proti němu

„Prezidentský kandidát Miloš Zeman se v kampani začal zbavovat odpovědnosti za privatizaci mosteckých dolů z roku 1999, kterou švýcarská prokuratura označila za zkorumpovanou. Tvrdí, že jeho vláda s ní neměla nic společného.” píše idnes.cz.

„‚Je to naprostá a vědomá lež Miloše Zemana,‘ reagoval pro MF DNES někdejší šéf Fondu národního majetku Roman Češka. Tošovského vláda v privatizaci dolů neměla žádnou roli. Privatizace začala již v době kuponové privatizace, kdy stát převedl 46 procent akcií firmy na Fond národního majetku a pět procent dal zdarma městům a obcím. Obce však své akcie záhy prodaly. V době Tošovského vlády už pouze management dolů ukrytý za schránkou zahraniční struktury Appian dokončoval tajné skupování volných akcií z trhu i od obcí, a to za peníze vytažené ze samotné firmy. Získal tak většinový podíl.”

„O podílu Zemanovy vlády na problematické privatizaci Mostecké uhelné svědčí i vyšetřování ve Švýcarsku, kde jsou exmanažeři dolů a Appianu obžalováni z praní špinavých peněz. Detektivové v minulých letech vyslýchali kvůli privatizaci ministry Zemanovy vlády i Miloše Zemana. Exmanažery MUS loni obvinila policie i v Česku, a to z privatizačního podvodu za 1,6 miliardy, který se stal v době Zemanovy vlády. Švýcarská prokuratura navíc považuje privatizaci menšinového podílu dolů za uplacenou.”

Lež Třetí: Zeman se omluvil za řeči o hajlování na hradě Therese Schwarzenbergové

Jedna z těch lží, která byla nejodpornější a zároveň opravdu nelze zpochybnit, že to lež byla, protože se za ni později Miloš Zeman omluvil: „‚[Karel Schwarzenberg] Cíleně zamlčel, že i jeho rodiče měli kolem sebe samé nacisty, a že dokonce v rodovém sídle, kde pobývá jeho žena Theresa, dosud visí obrazy s hákovými kříži a hajlujícími lidmi,‘ vyrukoval Zeman se šokujícím tvrzením.” píše blesk.cz.

„Jak se okamžitě ukázalo, poslední předek Therese Schwarzenberg žil na hradě Hardegg naposledy před třemi sty lety. Tehdy rodina sídlo prodala a logicky neměla žádný vliv na to, co bude o několik století později na jeho zdech viset za obrazy. Buď si Zemanův tým takto zásadní informace neověřuje, nebo chtěl prostě odpálit bombu za každou cenu.”

Lež Čtvrtá: Zeman ze mě udělal lháře, naštval se herec Hanák a šel na policii

„Není to pravda, je to pomluva nebo provokace. Těmito slovy Miloš Zeman ve středu rezolutně odmítl, že by si kdy jeho tým chtěl koupit přízeň herce Tomáše Hanáka. Jak však zjistil server Lidovky.cz, sms s žádostí o podporu výměnou za štědrou ‚refundaci‘ zaslal Hanákovi člen buňky vedené lobbistou Miroslavem Šloufem.” píší lidovky.cz.

„Herec se proto hned ve čtvrtek ráno vydal na policii. ‚Nejsem žádný lhář. Šel jsem proto hned ráno na policii a nechal jsem o té smsce udělat zápis,‘ řekl serveru Lidovky.cz Hanák. Policie si poznamenala jak obsah textové zprávy, tak číslo odesilatele.”

„Lidovky.cz autorovi textové zprávy několikrát volaly, avšak hovory nebral. Každopádně, jde o vysoce postaveného člena SPOZ. Patří k pražské stranické organizaci, jíž předsedá sám Miroslav Šlouf.”

Lež pátá: Franz: Zeman mě v kampani zneužil

„Hudební skladatel a vyřazený prezidentský kandidát Vladimír Franz se ohradil proti tomu, že ho Miloš Zeman využil ve své inzertní kampani před finále přímé volby prezidenta. Svým voličům prý Zemana nedoporučil, pouze řekl, že osobně mu dá svůj hlas. Franz to v pátek řekl serveru lidovky.cz.” píší novinky.cz.

„Nelíbí se mu prý navíc, že se objevil v Zemanově inzerci vedle Fischera, kterého si prý ‚naprosto neváží a proti kterému bojoval‘. ‚Z mého osobního rozhodnutí se stala součást kampaně,‘ dodal.”

Lež šestá: Další Zemanova televizní lež. Tentokrát o Posseltovi

Šestá lež ve skutečnosti obsahuje dvě lži v jednom. První část lži: „Před pár dny citoval mluvčího sudetských Němců Bernda Posselta, který se údajně v Süddeutsche Zeitung vyjádřil pochvalně o Schwarzenbergovi. Posselt však České televizi sdělil, že se k situaci vůbec nevyjádřil.” píší lidovky.cz.

Druhá část lži: „Poté, co televize odvysílala Posseltovo tvrzení, Zeman obrátil a řekl, že Posselta necitoval ze Süddeutsche Zeitung, ale z webového portálu Britské listy. Debata na toto téma poté skončila. Ovšem jen malou chvíli na to reagoval portál Britské listy, který Zemana usvědčil ze lži: ‚Britské listy se musí ohradit proti tvrzení Miloše Zemana v prezidentské diskuzi na ČT 24, že zveřejnily informaci ze Süddeutsche Zeitung o podpoře Bernda Posselta kandidátovi na prezidenta Schwarzenbergovi. Není to pravda. Jméno Posselt použily Britské listy naposledy 30. 05. 2012,’ napsaly Britské listy na svém portálu.”

Lež sedmá: Žádné štvanici vystavena nejsem, popřela Bohdalová Zemana

„Herečka Jiřina Bohdalová ve středu popřela slova prezidentského kandidáta Miloše Zemana, který o ní v rozhovoru pro Rádio Impuls prohlásil, že mu pláče do telefonu, neboť je vystavena štvanici kvůli podpoře, kterou mu nedávno vyjádřila. Bohdalová obvinila média, že si vymýšlejí s cílem ji pošpinit, slova o štvanici nicméně pochází ze Zemanových úst.” píší novinky.cz.

Lež osmá: Nech naše mrtvé předky na pokoji, vyzývají Zemana Smoljakovi potomci

„Potomky Ladislava Smoljaka rozlítil leták, který na oficiálním facebookovém účtu zveřejnil tým kampaně Miloše Zemana. Leták kritizoval podporu, kterou Zdeněk Svěrák vyjadřuje Karlu Schwarzenbergovi a stálo v něm, že by se Jára Cimrman ‚společně s panem Smoljakem v hrobě obracel.‘ Smoljakova rodina to zásadně odmítá.” píší lidovky.cz.

„‚Chápeme, že pro pana Zemana musí být frustrující, když se mu dostává tak žalostné podpory ze strany známých a respektovaných osobností. To však neomlouvá nanejvýš trapný pokus předstírat spřízněnost s těmi, kteří už nejsou na živu,‘ píší dcery a synové Ladislava Smoljaka ve vyjádření. Odvolání na jejich otce považují za naprosto absurdní. Smoljakovi potomci zmiňují, že jejich otec byl velkým příznivcem a přítelem Karla Schwarzenberga. Z jeho případného zvolení prezidentem byl měl prý obrovskou radost. ‚Vyzýváme Miloše Zemana, aby nechal naše mrtvé předky na pokoji,‘ doplňují Smoljakovi.”

Lži další: Demagog.cz: Nejvíce lží navršil v debatě na ČT Miloš Zeman

„Říkají nám kandidáti na prezidenta skutečně pravdu? Autoři projektu Demagog.cz se to rozhodli zjistit. Všechna tvrzení uchazečů o Hrad v televizním pořadu ČT podrobili detailní analýze. Výsledek? Ukázal se jednoznačný vítěz i hlavní poražený.” píší lidovky.cz.

„Naopak hlavním poraženým se stal Miloš Zeman (SPOZ). Kandidáta, který rád opravuje novináře při sebemenší mýlce, přistihl Demagog.cz hned při pěti lžích. Další dva jeho výroky byly zavádějící a u tří nešlo ověřit jejich pravdivost. Osmkrát pak Zeman pronesl tvrzení pravdivá.”

Lži kolem Šloufa: Šlouf: Zemanovi jsem pomáhal s kampaní a hodlám i nadále

Těžko říci, kdo z těch dvou pánů lže, můžete to posoudit sami: „Kontroverzní lobbista Miroslav Šlouf přiznal, že Miloši Zemanovi pomáhal s předvolební kampaní. Zkoušel například vyjednat podporu u KSČM, ODS i KDU-ČSL. Finančně prý na předvolební propagaci nepřispíval. Zemanovi je připraven radit i při výkonu prezidentské funkce, pokud si to vítěz přímé volby hlavy státu bude přát. Šlouf to dnes řekl novinářům v Top hotelu, kde měl Zeman volební štáb. Zeman poté v České televizi uvedl, že Šlouf nemluvil pravdu.” píše e15.cz.

„Zeman se v předvolební kampani ke Šloufovi nehlásil. Zmiňoval ho spíše jako bývalého poradce, s nímž však již v současnosti nespolupracuje. ‚Já jsem v podstatě tento koncept naší rozluky v kampani vymyslel,‘ řekl dnes Šlouf. Zeman prý jeho nápad respektoval. ‚A byl jsem tomu rád, protože jsem nechtěl, aby jeho kampaň byla o mně,‘ dodal.” Viz také rozhovor se samotným Šloufem.

Třešnička na dortu: Advokát s pochybnou minulostí v StB objednal inzerát proti Schwarzenbergovi. Ten se brání

Toto není další lež pana Zemana a ani jeho týmu. V pátek 25. 1. 2013, tedy v první den voleb, vyšel v deníku Blesk celostránkový inzerát, který ve čtyřech bodech házel špínu na Karla Schwarzenberga. Body byly buď přímo lživé nebo přinejmenším demagogické. Krom toho inzerát nesplňoval zákonné požadavky. Inzerát si podal Vladimír Zavadil, důstojník komunistické StB; můžete se také podívat na jeho složku [PDF].

„Schwarzenbergův tým dospěl k názoru, že inzerát porušuje volební zákon a je možná šířením poplašné zprávy, řekl mluvčí Marek Pražák. Volební štáb jeho rivala Miloše Zemana (SPOZ) se od inzerátu distancoval a sdělil, že s ním nemá nic společného.” píše ihned.cz.

Drobnosti na konec:

Články, které se ke mně dostaly později:

Všechny odkazované články jsem archivoval na dvou místech: první archiv, druhý archiv.

Vrah z Frenštátu měl zálibu v násilných hrách

Frenštátský zabiják Antonín Blažek, který před týdnem odpálil panelový dům i se svými sousedy a kromě sebe zabil dalších pět lidí včetně tří dětí, měl velkou zálibu v násilných hrách. V dětství s oblibou trávil čas tím, že si s vrstevníky hrál na indiány a bandity.

Naše noviny zjistily, že nejoblíbenější hrou, u které trávil třináctiletý klučina desítky hodin, byla střílečka s legendárním vrhačem kamínků a kamenů, slangově též prak, pomocí něhož se mimo jiné snažil rozbít sousedovic okna.

S prakem si svůj masakr nacvičoval například i norský hoch Anders Behring Breivik a hry na indiány pravděpodobně praktikoval i střelec z amerického Newtownu Adam Lanza. Je tedy možné, že i Blažek našel inspiraci k hrůznému činu, který podle sousedů zcela jistě spáchal, právě hraním si na indiány a bandity.

Blažek sám sebe považoval za velmi dobrého indiána a svými výsledky se také chlubil ostatním klukům ve škole. Na vánoční besídce dokonce zveřejnil i svou hrací přezdívku.

„Na střílečce hraji pod nickem Hořící buvol. Myslím, že mám vůbec nejblíže k Velkému Manitů,” pyšnil se Blažek a odhalil zde také název svého klanu, který vedl, Liščí stopa.

Blažek dále trpěl pocity, že jej sousedé chtějí zabít, že mu dělají schválnosti, bonzují ho jeho rodičům a že ho vyhánějí ze svých zahrad, když tam šli s Liščí stopou na jablíčka.

Za tyto výstřednosti mu otec Radim vyměřil nepodmíněný trest pětadvacet na holou. Blažkovi dále vadila například i večerka, kterou mu matka stanovila na osmou hodinu večerní. Byl zde i prodej živých ryb.

Mírně zkreslený pohled na celou tuto situaci pak naleznete na Novinkách: Vrah z Frenštátu měl zálibu v násilných počítačových hrách

Jak jsme bojovali proti spamujícím Bangladéšanům

Dlouhou dobu si naše fórum vystačilo s klasickým jednoduchým antispamem: povinná registrace, kdy byla uživateli předložena otázka, kterou za něj ale odpověděl Javascript. Uživatel tak o ničem nevěděl a roboti, kteří typicky Javascript neinterpretují, byli v háji. To ale stačilo jen do jisté doby.

Na fóru se postupně začalo objevovat více spamů a ze začátku mi nebylo úplně jasné, jak se vlastně tito spammeři dostali přes tuto ochranu. Začal jsem tak pokusy o registrace logovat a ti roboti, kteří se dostali dále, měli více méně společné tyto vlastnosti:

  • Podle hlaviček měli moderní prohlížeč, žádný IE 5.5 jako ti roboti, kteří neprošli.
  • Antispamovou otázku napsali správně na první pokus.

Takže buď někdo cíleně útočil na fórum a znal odpovědi na otázky, nebo ti roboti interpretovali Javascript. Pravděpodobnější byla druhá verze, takže jsem přidal na fórum nějaké kusy Javascriptu, abych to ověřil. Výsledkem bylo, že všechny změny, které prováděl jen Javascript, se u těch robotů, kteří prošli, projevovaly.

Nainstaloval jsem nějaký skript, který uměl z IP adresy poznat, z jaké země se uživatel přihlašuje. Většina úspěšných robotů měla Bangladéšskou IP adresu.

Zkusil jsem se zeptat moudřejších, jestli mají nějakou radu. Dostalo se mi hlavně popostrčení – možná to nejsou roboti, ale živí lidé. Z masa, kostí a rýže. A za dolar na týden a kus bambusu mi spamují fórum. Že podobné služby existují je celkem známo, ač v tomto případě se jedná jen o přepis CAPTCHA.

Dobře, takže je možné, že na mě neútočí jen tupí roboti, ale také chytří Bangladéšané.

Jak ale vytvořit antispam tak, aby jím neprošel živý člověk z Bangladéše? Chtěl jsem především nějaké elegantní řešení, žádné technické zrůdnosti, ani něco, co by obtěžovalo validní uživatele. V té době tam byla otázka typu Spočítej 5+17, což je ale celkem univerzální otázka v tom smyslu, že ji dokáže pochopit a zároveň na ni odpovědět i Bangladéšan.

Změnil jsem otázku tak, aby z ní nebylo zřejmé, na co se ptám, tj. něco jako Jaký je den mezi pátkem a nedělí? a nastavil jsem, že každý, kdo se nepřihlašuje z CZ nebo SK na tu otázku při registraci musí odpovědět. Tuhle otázku Bangladéšan nepochopí a nebude na ni znát odpověď. Zároveň na ni odpoví každý Čech a Slovák, což jsou prakticky všichni uživatelé fóra.

A za pár dní jsme měli na fóru dalšího spamujícího Bangladéšana. Nejzajímavější byl log, který říkal, že jeden z Bangladéšanů se tam dostal tak, že postupně zkoušel přibližně tyto odpovědi:

  1. saterday
  2. saturday
  3. sobota

Evidentně používal nějaký překladač, který mu přeložil otázku, ale Bangladéšan nejprve odpověděl anglicky a udělal překlep, pak se opravil a až pak mu došlo, že musí odpovědět česky, takže si ještě saturday přeložil do češtiny. A byl na fóru.

Hmm.

Takže česká otázka nestačí, Bangladéšané používají překladač. Nyní už to začíná být zajímavější. Jak upravit antispam tak, aby běžného uživatele neotravoval a Bangladéšan přes něj nepřešel ani s překladačem?

V podstatě se vše zredukovalo na to vymyslet nějakou otázku, na kterou zná odpověď každý Čech nebo Slovák (včetně puberťáků!), ale Bangladéšan ji znát nebude a to ani když použije překladač a následně Google. To je překvapivě složitý úkol. Něco z toho, co nás napadlo a zavrhli jsme:

  • Přísloví. Kdo jinému jámu kopá, sám do ní [doplň]. Bohužel často stačí frázi vložit do Googlu a odpověď je na světě.
  • Aby odpověď vyžadovala diakritiku. Kromě toho, že tím znemožníme registraci pravověrným linuxákům :-), tak tu odpověď lze zkopírovat třeba z Googlu a validní lidé, kteří se chtějí registrovat z ciziny, nemusí mít českou klávesnici.
  • Otázky typu: jaká je nejvyšší hora ČR? jsou úplně jednoduše dohledatelné asi úplně kdekoliv, subjektivnější otázky typu Jak se jmenuje nejznámější český zpěvák jsou v podstatě podobně dohledatelné: první dvě slova prvního výsledku jasně říkají: Karel Gott.
  • Zajímavá byla otázka Kdo vynalezl telefon těsně po Bellovi? Našeho nejslavnějšího vynálezce by možná nešlo tak lehce vygooglit, ale zase těžko chtít po dvanáctiletých puberťačkách, které mají problémy s domácím úkolem, aby znaly Járu Cimrmana.
  • Popkulturní odkazy jako Paroubek jinak na pět. Přestože je možností mnoho (Jyrka, prase), tak to zase nebude znát každý. Puberťačky tím spíše. Hlášky z filmů jsou většinou dohledatelné stejně jako přísloví nebo Karel Gott.
  • Otázka na gramatiku: Přepište následující větu bez gramatických chyb: “ženy souložili” Tohle byl celkem dobrý nápad, asi by byl použitelný, ale nejvíc jsem se bál toho, že by to někdo nevěděl. Na druhou stranu – možná by to nebyla žádná škoda :-D. Teoreticky by se ještě dal použít nějaký checker, třeba z Wordu.

Výsledek? No, v podstatě žádný. Některé otázky by byly použitelné, pokud bychom předpokládali, že Bangladéšan buď vůbec nepoužije Google nebo to bude zkoušet jen chvíli. Celkem zajímavé cvičení je předpokládat, že to ten Bangladéšan bude zkoušet dlouho. Napadá vás nějaká otázka, na které by si Bangladéšan vylámal zuby i s Googlem, ale Čech/Slovák by znal odpověď?

Nakonec pomohla změna formy dotazu. Máme web, 21. století – co takhle použít nějaká multimédia? Stačí například přiložit obrázek a zeptat se, co je na něm? Případně nějaké audio/video.

Problém: Google má hledání obrázků a když si tam člověk nechá vyhledat obrázek něčeho známého, tak mu Google zároveň řekne, co by to tak mohlo být. U notoricky známé fotky Karlova mostu to u mě napíše: Best guess for this image: charles bridge a totéž pro Agátu: Best guess for this image: agáta hanychová.

Ale to by až tak nevadilo. Obrázek lze trochu poškodit nebo použít nějaký, z kterého Google nepozná o co jde. A jsme v cíli. Zbývá už jen vymyslet něco, co by tom obrázku mělo být, aby to poznal puberťák i důchodce.

Nakonec jsem zvolil … Karla Gotta. Snad je natolik velká legenda, že ho znají i dnešní puberťáci. Použil jsem nějakou zakopanou fotku, kterou jsem ještě různě zdeformoval, aby Google nenašel žádný podobný obrázek a neuhádl, kdo na fotce je. Lze použít i více obrázků s tím, že uživatel musí poznat aspoň někoho. Takže pro mladší lze použít třeba tu Agátu.

Pro jistotu jsem soubor s obrázkem lstivě pojmenoval marek_vasut.jpg. A ne nadarmo, za tu dobu, co je tento antispam nasazený, zkoušeli Marka Vašuta tři lidé a několik dalších zkoušelo jen Marek. Bangladéšané nejsou tak úplně blbí! Jednou tam byl vyplněný i Havel (ale Klaus ne, to zase bude ukřivděný).

Takže rozuzlení – jaká je účinnost Káji Gotta? Antispam s Kájou byl nasazen v červnu roku 2012 a nejsem si vědom toho, že by se tam zaregistroval nějaký zlý Bangladéšan. Hurá! Kolik validních uživatelů přes antispam neprošlo? Těžko říci, jeden z nich mi napsal email. Byl to Američan a chtěl kontaktovat někoho z fóra, víc mi nepsal. Emailem jsem mu prozradil odpověď. Víc nevím, moc jich snad není.

Nakonec máme po technické stránce triviální antispam, který ale funguje. Alespoň zatím. Držte palce, ať funguje dále nebo navrhněte nějaké jiné jednoduché, ale neprůstřelné řešení :-)

Drobnosti, které se mi nelíbí na Macu

Dnes článek z druhého břehu.

Flash

Největší zlo na mém Macu je jednoznačně Flash. Nic příšernějšího opravdu nainstalovaného nemám. Na Windows jsem nikdy s Flashem problém neměl — samozřejmě kromě psychického problému s tím, že Flash je nenativní blob vložený do webové stránky, který si žije svým vlastním životem. Nicméně fungoval a nepamatuji si, kdy se mi ve Woknech naposledy stalo, že mi Flash udělal bác. Ovšem na Jablíčku to je úplně jiné kafe. Dost možná to už ani není kafe. Primárně brouzdám v Safari a průměrně mi ten adobácký blob spadne co dva dny. Hodně rychle jsem se naučil používat Click2Flash, což je hezký pomocník, který zakáže všechen Flash a spustí ho až po kliknutí. Docela to pomohlo, ale stejně si to vesele padá třeba na YouTube. Tam sice mám povoleno HTML5, ale asi mám smůlu na videa, která v HTML5 neběží, protože nevím, kdy se mi naposledy spustilo nějaké video jinak než ve flashovém přehrávači. Kéž by se Stevu Jobsovi povedlo vytlačit Flash na okraj webu, to by bylo tak príma!

Prohlížeč

Jak si bystrý čtenář všiml, používám Safari, což je výchozí prohlížeč na Macu a spojeném království iPhonů, iPodů a iPadů. Safari je prohlížeč, který se mi v základní verzi bez doplňků moc nelíbí, je divný a občas pomalý. Jeho největším plusem je ofkórs nativnost. Žádný jiný prohlížeč zkrátka nepodporuje všechny vychytávky, které OS X nabízí. Začíná to standardními ovládacími prvky (select box apod.), které tam vypadají trochu jinak a pokračuje to pak tím, že obvykle nemají podporu pro text replacement fíčury (to jsou třeba chytré uvozovky, chytré pomlčky…). Kecálek Adium zase umí v textu zprávy nahradit „%safari” za adresu aktuálně otevřeného tabu v Safari, takže se nemusíte přesouvat do Safari, kopírovat adresu a zase zpátky do Adia. (Blbé je, že to neumím změnit na něco kratšího, ale to už je jiná věc.)

Bez doplňků je pro mě Safari naprosto nepoužitelný prohlížeč, který v základu neumí ani vyhledávání pomocí klíčových slov („g Radek Hulán zmodralá prostata” hledá v Googlu, „w Radek Hulán diskuse o smazání” hledá na Wikipedii, „c Radek Hulán dokument” hledá na ČSFD atd.). Naštěstí i do Safari existují doplňky, takže po nainstalování Safari Stand, Glims a AdBlocker jsem z toho udělal prohlížeč s alespoň základními schopnostmi, které od prohlížeče požaduji. Záporem budiž to, že každý doplněk se instaluje jinak a hlavně se odinstalovává jinak; centrální správa doplňků neexistuje. Jeden doplněk dokonce nejsem schopen odinstalovat ani podle návodu (TabExpose). Dalším problémem je, že občas trvá docela dlouho, než se v Safari otevře nový tab — obzvláště, když bylo Safari zrovna nějakou dobu neaktivní. Tohle se mi v jiných prohlížečích nestávalo.

Stabilita

Se stabilitou mého systému to není nijak slavné. Ne že bych každou chvíli viděl jablíčkovou BSOD, to ne, ale docela často se mi stává, že mi padající aplikace zabrzdí celý systém tak, že se nedá používat. Typicky když padá na držku Flash, tak než dopadne až na zem, trvá to asi deset sekund a během té doby se systém plazí jako hlemýžď po obědě a odezva je horší než na hotlince T-Mobilu. Tohle na Windows asi není o moc lepší, ale na Windows mi tak často nepadají aplikace. Ačkoliv je pravda, že za 90 % těchto kotrmelců může … wait for it … Flash. Fajn je, že v případě nutnosti funguje Force quit lépe než ukončování procesů ve Woknech.

Hardware

Klasika — ostré hrany; známý problém. Pokud na MacBook trochu nešikovněji položím ruce, za pár minut mě to opravdu bolí.

Chybějící klávesy. Pokud jsem v OS X, tak mi chybějící klávesy nijak nevadí, ale když bootnu do Windows, najednou chybějící klávesy jako PageUp/PageDown začnou vadit. Ale chápu, že primární starostí Applu asi není, aby tam bezproblémově fungovaly Windows.

Placené aplikace

Tohle bylo docela překvapení. Než jsem si pořídil MacBook, snažil jsem se přečíst co možná nejvíc článků o Applu, o switcherech a podobné romány a bajky. Unikla mi ale informace o tom, jak je to s aplikacemi. Takže má se to asi takto: aplikací pro OS X je méně než pro Windows (to jsem věděl) a ne zrovna malá část z nich je placená (tohle už mi uniklo). Byl jsem celkem překvapený, že každá druhá aplikace, na kterou jsem narazil, byla placená. Přitom se často jednalo o blbosti, které by na Windows nejspíš byly zdarma. Je ale pravda, že Macové aplikace jsou většinou kvalitnější, hezčí a použitelnější než nějaký podobný free software na Windows. Nicméně zůstává faktem, že míra placených aplikací mě překvapila. Cena za takovou klasickou nenáročnou aplikaci bývá 10–30$.

Nekompatibilita aplikací

Zarazila mě i nekompatibilita aplikací napříč jednotlivými verzemi OS X. Často jsem potkával aplikace, které měly dvě nebo tři instalačky pro různé verze OS X (10.6, 10.5, 10.4 — menší už jsem myslím nepotkal). Stejně tak není problém potkat hlášku „Leopard only” (→ to je vlastně docela dobrý vtípek. Funguje „Leopard only” software na Snow Leopardovi?). Ve Windows jsem se s tímhle problémem nikdy nesetkal, na Sedmičkách jsem běžně zprovoznil nějaký obskurní software, jehož vývoj ustrnul někdy v dobách XP. Stejně tak instalačka je obvykle stejná pro XP, Vistu i Sedmičky. Statistiku jsem samozřejmě nedělal, ale můj pocit je takový, že kompatibilita aplikací s novými verzemi OS X je horší než na Windows.

Odinstalování aplikací

Asi každý zná tu historku o tom, že Mac OS X je skvělý, protože umožňuje instalovat aplikace přetažením jednoho souboru do složky Applications. Kromě toho, že to není celá pravda (existují zde i klasické instalátory), tak problém nastává při odinstalování. Pokud totiž jen vezmete aplikace a přetáhnete ji do koše, sice aplikace odstraníte, ale různě po systému se ještě mohou povalovat další aplikační data, která už se neodstraní. Nevím o tom, že by to samotný OS X uměl nějak vyřešit, existují ale aplikace třetích stran, které dokáží při odinstalaci odstranit i tato data. (Já používám Appcleaner, je zdarma.)

Velké iTunes

Roztahování oken jen vpravo dole — to je cypárna jak Brno. Kromě toho, že je to nepraktické (často se mi stává, že se s trackpadem netrefím do rožku, ale kliknu už mimo okno, bomba), tak je vcelku humorné, že když připojím k MacBooku LCD a roztáhnu tam iTunes na nějakou větší velikost, tak když pak LCD odpojím, iTunes zůstane stejně velké. Ale bacha, to znamená, že okno iTunes je vyšší než obrazovka MacBooku a pravý dolní růžek je prostě někde utopený pod stolem a já nevím, jak to jinak zmenšit xD. Zeleným čudlem se dá iTunes zmenšit až moc a při restartu mi to zachovao velikost :-). Zkrátka jsem si musel počkat, až zase připojím LCD a zmenšil jsem to tam.

Drobnosti

Terminál s neviditelnou ikonkou. Hehe.

Pokud jsem kupříkladu v Safari a kliknu pravým na vysypat koš, zobrazí se mi po vysypání všechna okna Finderu a jedno z nich dostane focus. Což je vcelku Macovsky logické, protože koš patří pod Finder a po vysypání koše to zkrátka přesune focus na další okno Finderu, ale vysírá mě to.

Některé vychytávky trvají až příliš dlouho. Nahoře jsem zmínil, že když v Adiu napíši „%safari”, vyzvedne si to ze Safari aktuální adresu a odešle ji namísto tohoto textu. Problém je v tom, že samotné vyzvednutí trvá třeba tři, čtyři sekundy. A není to vina Adia, zkoušel jsem si naprogramovat v Automatoru Service, která by uměla nakopírovat do schránky URL aktuálního tabu v Safari. Výsledek je stejný, při prvním použití to trvá stejně dlouhou dobu, než se to provede…

Drobnosti, které se mi líbí na Macu

Několik drobností, které se mi líbí na Mac OS X a MacBooku:

  • MacBook nemá tisíc a jednu multimediální klávesu.

  • Znáte to, když začnete rolovat v prohlížeči pomocí šipek na klávesnici a najednou uprostřed textu, který zrovna čtete, trčí kurzor myši, který jste šikovně „odložili” doprostřed obrazovky? Na Macu se při rolování pomocí šipek kurzor automaticky skryje.

  • Takový Word umí automatickou záměnu textů, například automaticky transformuje obyčejné uvozovky na české nebo trojici teček na výpustku. Mac OS toto umožňuje nadefinovat napříč celým systémem. (Smutnou skutečností je, že se najdou programy, které toto moc nepodporují, naštěstí jich je menšina.) Stejně tak umí i kontrolu pravopisu nad celým systémem.

  • Rychlé probouzení. Dvě sekundy po otevření MacBooku můžu pracovat.

  • Absolutní tichost. Pokud MacBook nějak zásadně nevytěžuji, není VŮBEC slyšet. Naopak při velkém vytížení dělá kravál jako kráva. (Zatím jsem ho vytížil dvakrát: když jsem v BootCampu ve Windows testoval bakalářku a procesory běžely na 100 % několik desítek minut a když připojím externí LCD a přehrávám nějaký film ve flashi. HTML5 je v pohodě.)

  • Ty červené ikonky u aplikací v doku. Krásně signalizují, co se děje.

  • Složka downloads v Doku a její výchozí styl zobrazování. Takové to, když na ni kliknete a rozjede se seznam posledních stažených souborů. Geniálně použitelné. Na Windows jsem to dělal tak, že jsem už při stahování ručně určoval, kam se má soubor stáhnout. Tady to neřeším, nechám Safari, ať mi to stáhne do Downloads, v Doku ještě vidím průběh stahování. Pak to jednoduše přes Dok spustím nebo to přetáhnu kam potřebuji. Jednoduché jako facka. (Nevím nakolik by to šlo nasimulovat ve Windows, Firefoxí správce stahování neumí později aplikovat drag&drop a navíc mě štvalo už jen to, že se otevřelo nějaké další okno. Řešil jsem to nějakým doplňkem, který mi ukazoval průběh stahování ve status baru.)

  • Neexistence tlačítka „uložit změny”. Běžné aplikace zobrazují změny nastavení realtime, stejně tak ukládají nějaký obsah realitme (například MacJournal, program, ve kterém tohle píši, to dělá přesně tak).

  • Přehledné zobrazení všech (nebo většiny) nainstalovaných aplikací.

  • Náhledy ikon u podporovaných souborů (třeba náhled PDF souboru, jako u obrázků).

  • Provázanost některých aplikací — pokud si v jednom FTP klientovi uložím heslo, druhý FTP klient si ho z klíčenky zase vytáhne. (Nevím ale, jak moc je to bezpečné.)

  • Znáte nebo používáte gesta myší v prohlížeči? MacBook podporuje gesta na trackpadu/touchapdu, který rozezná více dotyků.

  • Možnost nadefinovat (nebo předefinovat) si zkratku k jakékoliv položce menu v jakékoliv aplikaci. Stejně tak mi připadá, že je tady lepší práce s globálními zkratkami napříč celým systémem.

  • Jednotnost zkratek: většina důležitých zkratek se dělá přes cmd, což je jakási obdoba win klávesy. Tuto klávesu navíc nežere Flash, takže když koukáte na RedTube na porno a chcete ho rychle vypnout, tak cmd+w bude, narozdíl od ctrl+w, fungovat . (Za předpokladu, že jste předtím měli focus v přehrávači.)

  • Tracks, zatím nejlepší aplikace, na kterou jsem narazil. Umožňuje jednoduše nadefinovat globální zkratky na ovládání iTunes, včetně vyhledávání a spouštění písní podle jejich názvů. Funguje to jako takové spotlight na iTunes — zkrátka stisknu alt+space, napíšu třeba Cradle of Filth (nebo jen část) a ono mi to vypíše všechny písničky od Cradle of Filth. Pak si jen vyberu co chci pustit a jedem. Lze to i propojit s Last.fm.

  • SlidePad, zatím nejlepší aplikace na ukládání rychlopoznámek, na jakou jsem narazil. Když stisknu alt+a, vyjede mi z levého okraje textové pole, které má automaticky focus, takže může hned něco napsat nebo vložit. Pak stačí zase alt+a a jsem tam, kde jsem byl. Ukládá se to samozřejmě samo.

  • Zajímavý je samozřejmě Automator, který umožňuje jednoduše vytvářet jakési utility a zautomatizované akce. Ale prozatím s ním mám spíš problémy a hádáme se. Uvidíme, jestli se udobříme. Stejně tak spotlight, vyhledávání napříč celým systémem. Na spouštění aplikací je to fajn, ale dál si moc nerozumíme. Nechápu, proč když dám jednou vyhledat nějakou složku, tak mi ji najde celkem rychle, ale zase deset minut to ani po minutě hledání nezobrazí to, co před chvílí.

  • Apple.com jsou přehledné a hezké stránky xD.

  • Svítící jablíčko je prostě cool :-).

No, to by prozatím mohlo stačit :-).

Méně známé seriály, které byste neměli minout

Jasně, všichni sledujeme HIMYM, TBBT, House, Misfits, Fringe, Dextera a podobné známé seriály. Proto zde zkusím představit seriály, které nejsou tak všeobecně známé a opravdu se mi líbily. (Pokud byste náhodou neznali předchozí seriály a následující ano, tak sorry.)

  • Skins. Naprosto geniální seriál o partě teenagerů, kteří si dělají co chtějí a přesto nebo právě proto je všechno kolem nich tak strašně zkurvené. Seriál ukazuje život dost syrově a reálně, všude samý chlast, drogy, problémy s rodiči, problémy ve škole… Každý díl se primárně věnuje jedné postavě, přičemž každá postava je opravdu naprosto jiná (to mám rád, protože mám často problém si po celý film/seriál zapamatovat kdo je vlastně kdo) a stejně jsou všechny sympatické. Seriál má v současnosti čtyři řady, připravuje se pátá. Po dvou řadách se vyměnila generace, většina postav zmizela a celé kouzlo se jaksi ztratilo. Třetí a čtvrtá řada tak byla naprosto příšerná, radši se snad ani nekoukejte. V nové, páté řadě, bude opět nová generace. Pokud bych vybrat seriál, ze kterého byly nejvíc cítit emoce, tak by to byl tenhle.
  • Psychoville. V hlavní roli klaun se železným hákem místo ruky, tlustý retardovaný člověk, kterému jeho máma, která vypadá jako chlap, pomáhá vraždit, slepý sběratel hraček, sestřička, která věří, že její panenka je živá a chová se k ní jako ke svému dítěti a liliput, který ovládá telekinezi. Může být tohle špatný seriál? Nemůže. V seriálu je kopa černého humoru a díky tomu, že existuje jen sedm dílů, neztrácí v průběhu času na kvalitě. Jestli chcete ujetý seriál, tohle bude dobrá volba. Asi nejabsurdnější (a zároveň velmi dobrý!) seriál, jaký jsem viděl. Ještě by docela dost mohl navnadit obrázek :o).

  • Lost Room. Sci-fi seriál o policajtovi Joeovi, který najde podivný klíč, který umí odemknout jakékoliv dveře. To zní fajnově, jenže ty dveře pak vedou do podivného motelového pokoje, který v naší realitě neexistuje. Rychle se zjistí, že pokud cokoliv v pokoji změníte, tak po zavření a otevření dveří se dá vše do původního stavu. A věci, které jste tam dali, zmizí. A o hlavní zápletku je postaráno, obzvláště, když má Joe malou holčičku. Z pokoje dále zmizelo asi dalších sto věcí a každá věc, přesněji „objekt“, má nějakou zvláštní schopnost. Joe postupně zjišťuje, co to vlastně všechno znamená, kde se vzal klíč, potkává lidi s jinými objekty a dostává se stále hlouběji. Lost Room je opět krátký seriál, má šest dílů a tak se nebudete ani u jednoho nudit, není tam žádné dlouhé natahování. V každém díle je odkryto něco málo z celé záhady, pár dalších otázek se přidá, ale přesto zůstává děj celkem přehledný a nezamotaný. Ono ho naštěstí nebylo možné během šesti dílů nějak zásadně zašmodrchat. Hlavním tahounem Lost Room je tak hlavně příběh, který prostě zhltáte.

  • Coupling. Taková britská verze Přátel. Tři muži a tři ženy posedávají v baru a řeší hlavně sex. Což je rozdíl oproti Přátelům, kde seděli v kavárně a řešili Rosse s Rachel :-). Rozdílů je tam samozřejmě více, hlavně v tom, že humor v Couplingu je daleko úchylnější a absurdnější, Přátelé se pořád drží při zdi. Někdy v poslední sezoně dojde k výměně jedné hlavní postavy a už to stojí za starou bačkoru.

  • Six feet under. Seriál z hrobařského prostředí. V hlavních rolích Dexter, který hraje gaye a Joe z Lost Room (Peter Krause). Dohromady vlastní pohřební ústav, v každém díle se tak starají kolem jednoho mrtvého. Viděl jsem asi dvě série a stejně se scénáristům povedlo pokaždé vymyslet nějaký nový archetyp mrtvoly, kolem které se budou dít jiné věci než v předcházejících dílech. Nečekaně se tam objeví nějaký ten černý humor (rozhovory s mrtvolami), na druhou stranu je seriál i dost depresivní.

  • Freaks and Geeks. Další seriál o teenagerech, ale opět kvalitní. Výše uvedení Skins jsou sice jiná káva, ale tohle je taky zajímavý počin. Mimochodem — hraje tam Marshall z HIMYM. Hlavní příběh je vcelku banální, jedna šprtka se snaží stát se oblíbenou v kolektivu sportovně nadaných cool týpků. Seriál celkem inteligentně zobrazuje radosti a strasti mládeže a pokud si chcete trochu zavzpomínat na své mládí, tak tohle by mohla být ta cesta.

  • Kyle XY. Z počátku velmi dobrý seriálek o tom, jak se kdesi objeví geniální dítě s mírně nadpřirozenými schopnostmi, ale s absolutní ztrátou paměti. Je kouzelné sledovat, jak se toto dítko postupně začleňuje do společnosti a poznává okolí, sem tam využije svou schopnost k vykonání jak jinak než dobra, jak se zamilovává atp. Problém seriálu je, že tato dějová line začleňování scénáristům nestačila a přidali ještě jednu linii, konspirační. On ten Kyle je ve skutečnosti produkt nějaké společnosti a ti ho chtějí zpátky nebo tak něco. Pak je tam ještě jiná společnost, pak ještě jiná, všechno je strašně moc tajemné, přeplácané, paranormální a hlavně neskutečně trapné. V pozdějších dílech je bohužel čím dál více konspirací a čím dál méně životních trablů Kyla, takže někdy z kraje třetí série jsem na to přestal koukat. Nicméně první série a ještě i celkem druhá série byla dobrá a stojí za zhlédnutí.

A nakonec pár seriálů jednou větou:

  • How do you want me? Hlavní předností je představitel hlavní role, Dylan Moran, neboli Bernard Black z Black Books. Jak to dopadne, když se kvůli své manželce přestěhujete z města na vesnici, kde vás všichni nenávidějí? Bude z Bernarda zase alkoholik? :-)
  • Moonlight je už zrušený seriál o upírském detektivovi. Trochu kýčovitý seriál, ale koukalo se na to celkem hezky.
  • Breaking Bad, neboli česky Perníkový táta. Výjimečně uvádím i český název, protože je prostě dokonalý. Co se stane, když učíte na škole chemii a dovíte se, že za chvíli zemřete a znáte studenta, který prodává drogy?

To by bylo pro dnešek všechno.

Ročníkový projekt

Ve škole jsme měli za rok naprogramovat vcelku jednoduchou deskovou hru. A zde je výsledek.


U mě na webu si můžete stáhnout spustitelný exe soubor. Instalace není nutná (z tohoto exáče dokonce nemožná). Ke spuštění potřebujete .NET 3.5, jestli je třeba verze SP ani nevím. Pravidla jsou vysvětlena přímo ve hře v sekci nápověda. Když tak jen stručně:

Na začátku si vyberete zda chcete hrát za útočníka nebo za obránce. Obránce brání svou pevnost a útočník se ji snaží obsadit. Obsazení se provede ve chvíli, kdy útočník umístí devět svých kamenů do pevnosti. Útočník se pohybuje pouze vpřed a do boku, obránce všemi směry. K tomu může obránce skákat útočníkovy kameny podobně jako v dámě. Obránce vyhrává, když má útočník méně než devět kamenů. Obránce může přeskočit více kamenů současně, ale dělá se to trochu krkolomně – levým tlačítkem myši vyberete obránce, pravým naklikáte cestu, kudy má skákat a levým tlačítkem potvrdíte skok (kliknout můžete kdekoliv).

Hru můžete ukládat, načítat ze souboru, přehrávat, listovat v historii, vybírat různé úrovně obtížnosti…

Z implementačního hlediska byl asi nejzajímavější Minimax – vygenerování všech možných stavů hry, které mohou za určitý počet kol nastat. Ve výchozím nastavení to na těžké obtížnosti počítá čtyři tahy dopředu. Na mém dvoujádru to fičí v pohodě, ale na notebooku už při těžké obtížnosti je vidět znatelné zpomalení.

Pak už asi nic extra zajímavého. Ukládá se to do čitelného XML, takže ho můžete hezky editovat a pohrát si s tím. Doufám, že se vám nepovede změnit vstupní soubor tak, aby ta hra pak spadla, snad tam provádím dost kontrol :-). Hra je ve více vláken; jedno vlákno se stará o GUI a jedno o výpočty, když nějaké jsou. Takže hra se nezasekne, když zrovna počítač počítá tahy, celá hra je nadále normálně ovladatelná.

Samotná inteligence počítače není zrovna nejlepší, je to jen pár pravidel a občas ten počítač hraje dost na chuja. Ale celkově vzato nehraje zase tak špatně, ačkoliv ho nejspíš po pochopení pravidel porazíte na první pokus :-).

Obhajoba probíhala celkem v pohodě, pár minut jsem svou hru předváděl, ale oponenti už si ji stejně proklikali den předem, takže na obhajobě už si to člověk vlastně jen mohl pokazit, když mu to třeba nějak spadlo, což se naštěstí nikomu nestalo. Po krátké prezentaci následovala diskuse, což znamenalo vyslechnout si výtky od oponentů. Řekli mi v zásadě dvě výtky: (1) debilně vyřešené skákání více kamenů; (2) limit tahů – ten nebyl v zadání a přidal jsem ho tam proto, abych zamezil opakovaným tahům počítače. Měl jsem vymyslet inteligentnější způsob, než suchý limit tahů. Jinak to bylo v pohodě.

Celkově nás bylo na termínu 11, z čehož 7 lidí projekt obhájilo. Zajímavé přitom bylo, že z druháku (je to předmět pro druháky) jsme tam byli jen tři, a to ještě aplikovaní informatici (máme ještě teoretické informatiky, kterých je víc než nás, aplikáčů). Zbytek byli buď nějací učitelé (ani jeden to neudělal) nebo třeťáci, kteří to opakovali. Od nás to dali dva ze tří.

Nakonec to ani nebylo tak těžké, jak se zdálo. Celkově jsem napsal zhruba 4000 řádků zdrojového kódu, což je asi docela hodně – koukal jsem se jen tak letmo na některé ostatní zdrojáky a většina asi měla méně řádků. Ale těžko hodnotit, já měl u každé metody, třídy a typu napsanou dokumentaci a hodně věcí jsem měl roztahaných do mnoha metod (což je správně). Byli lidé, kteří měli celá pravidla nacpaná do jedné funkce, prostě hromada ifů na šest obrazovek na šířku. To se mi moc nelíbilo.

Dost velká otrava byla taky s dokumentací. Museli jsme mít dokumentaci v PDF včetně zdrojových souborů, což zlehka implikuje použití TeXu. Takže ze zdrojových souborů jsem nakonec musel vygenerovat XML soubor s popisem všech metod, pak jsem pomocí XSL transformace z toho vygeneroval TeXový soubor, který jsem následně zkompiloval do PDF. No hrozný proces to byl. K tomu ještě dopsat popisy algoritmů…

Ještě jsem vlastně nezmínil, že hra je naprogramována v C#, můj oblíbený programovací jazyk, jak jistě všichni víte. C# je boží, všechen ten LINQ, extension methods, a lambda výrazy… Ale to je jiná story.

Takže ročníkový projekt za mnou, geometrie (ne, žádné rýsování trojúhelníčků, ale hromada počítání s vektorovými prostory) a paralelní a logické programování přede mnou.

Jak vysokoškoláci táhnou IT

Na Facebooku proběhla nedávno taková malá debata o tom, jestli je VŠ k něčemu nebo k ničemu. Detaily jsou nezajímavé, důležitá je jedna myšlenka, která tam probublala. Jeden človíček tvrdil, že “IT odjakživa táhli a táhnou vysokoškoláci”, s čímž jsem souhlasil, ale oponenti zásadně nesouhlasili. No, zkusil jsem si najít, za kterými technologiemi stojí lidé s vysokou školou a za kterou lidé bez vysoké školy. Omezil jsem se pouze na web a internet, protože zase tolik času nemám :-). Výsledek uvidíte na této stránce. Za všemi významnými technologiemi, na které jsem si vzpomněl, stojí někdo s vysokou školou. Náhoda? Fikce? Důkaz? To už si rozmyslete sami.

Opavsko-olomoucké vlakové paradoxum

A jak dlouho čekáte ve frontě na jízdenku vy?


Znáte to, přijdete na nádraží, chcete si koupit jízdenku a ejhle, fronta jako blázen. Stoupnete si do řady a čekáte a čekáte. Za přiměřený čas dostanete lístek a jdete na vlak. Ne tak v Olomouci a ne tak v Opavě.

V Opavě totiž přijdete na nádr a ve frontě stojí tak dva lidi. Vždycky. Nebo alespoň poslední půlrok. Řeknete si super, to půjde rychle. Stoupnete si do fronty a čekáte. První člověk se zrovna dohaduje s paní, že chce sice jet do Práskařic, ale nikoli přes Vagislavín, ale přes Řiťolezy. Na to paní odpovídá, že to nejde, protože podle drážního předpisu číslo evidenční 435/12 paragraf 8 řádek 3 se nesmí vydávat přestupní jízdenka z Krutoalbrechtic do Práskařic přes Řiťolezy, že to by musel pán jet ne z Krutoalbrechtic, anóbrž od Plachtoklaz. Pán že ne, že to ani omylem, že s tím si paní od dráh může políbit svůj plesnivý ánus a že chce jet přes Řiťolezy a basta fidli. Po třech paragrafech a několika zadnic se nakonec shodnou na tom, že pán pojede do Krutoalbrechtiv vlakem, pak přesedne na autobus, dojede do Řiťolez, tam si koupí svůj oblíbený Řiťolezácký chleba, který pečou jen v Řiťolezech a pak pojede vlakem domů. Sedm minut v tahu, vy stále nemáte lístek.

Nastupuje na řadu slečna, která stála před vámi. Mladá, sympatická, ta určitě nepojede do Řiťolez, to je v klidexu. Já bych chtěla studentký průkaz do Ostrávy, říká. A potvrzení od školy máte? No nemám, ale mám ISIC. Tak si jich sežeňte ještě třicet jedna a můžete s nimi hrát Černého Petra, ale studentskou průkazku vám nedáme. Ale vždyť ten ISIC přece říká, že jsem studentkou vysoké školy, ne? Ta karta říká, že svou první menstruaci už máte za sebou, ale o vysoké škole neříká nic. Tady máte papír a až vám ho potvrdí škola, můžete dostat průkazku. Ale blablabla.

Přestáváte čekat, minuty ubýhají a vlak skoro ujíždí. Vlezete do mezinárodní pokladny, koupíte si lístek meziměsto a jdete pryč.

Teď Olomouc. Koukáte na kolejích na Californication, Fox Mulder si to zrovna rozdává s nějakou kráskou a najednou zjistíte, že vlak jede za pár minut. Nahážete věci do krosny a letíte na nádr. Vlak jede za sedm minut, když doběhnete do haly a tam je fronta patnácti lidí u každé kasy. Do zpocené prostitutky, která si zrovna odpracovala svých osm hodin na E55 ve společnosti všude ochlupených německých gentlemanů, klejete a stoupnete si do fronty. Než napočítáte do 180, jste na řadě, máte v ruce lístek a éla hop, sedíte ve vlaku. Ještě si stihnete koupit noviny. Reflex. Sráthem.

Toto je nejsilnější a největší paradoxum, se kterým jsem se setkal. Neví někdo, proč vystát čtvrtinovou frontu v Opavě než jaká je v Olomouci trvá čtyřikrát déle? Hmm, Petro, nevíš? Možná bych o tom mohl napsat bakalářskou práci.

Jak probíhal semestr

Krátký pohled do zákulisí mého učení a snažení na výšce.


Pro připomenutí - jsem na aplikované informatice na Univerzitě Palackého, druhý ročník.

Semestr začal v pohodě, měli jsme klasické předměty jako Algoritmická matematika (teorie grafů), kam nikdo nechodil, protože máme dobré skriptum. Pak Softwarová laboratoř, což bylo vcelku jednoduché programování v C++ a zápočet nebyl o nic složitější, akorát byla povinná nějaká docházka. Dále jsme měli matematiku, analýzu. Limity, derivace, integrály… To všichni znáte, že jo? ;-) Poslední tři předměty už byly vesměs zajímavé: projektový seminář (programovali jsme nějakou složitější variaci dámy), Formální jazyky a automaty (regulární výrazy a takové věci) a nakonec Paradigmata programování (funkcionální programování).

Na projekťák jsem se docela těšil, konečně jsem programoval nějaký větší kus software. Probíhalo to tak, že si člověk na začátku semestru vybral jednoho ze šesti vedoucích, každý měl jinou variaci stolní hry dáma a někteří z nich měli i omezení na programovací jazyky. Já si nakonec vybral Obranu pevnosti, což byla hra, kde nebyly dámy (o to to bylo jednodušší), ale zase jsem měl složitější hrací desku (byla ve tvaru kříže). Celkově vzato to co do obtížnosti byl takový průměr. Byly tam ještě lehčí hry, ale i složitější. Programoval jsem to v C#, což je samozřejmě nejlepší programovací jazyk :-). Za zimní semestr jsme měli zvládnout naprosto korektní implementaci pravidel a funkční a “inteligentní” hru počítače (minimax - generování všech možných tahů do určité úrovně). Trochu mi na konci semestru vadila různá úroveň hodnocení jednotlivých projektů. Byli tam na jedné straně vedoucí, kteří kontrolovali každičký detail a na druhé straně se zapisovalo když se to alespoň bez chyby zkompilovalo… Já měl samozřejmě toho největšího puntičkáře :-). Ale v zásadě mi to nevadilo, alespoň mám tu zimní část dobře a ti, co neměli ani implementaci počítačového hráče, budou mít v letním semestru co dělat. Ale přišlo mi to trochu nefér.

Na začátku zkouškového jsem si vzal jako první na paškál matematiku. Kupodivu mě učení docela bavilo, protože mi to i vcelku šlo. Na přednášky a cvika jsem chodil, takže jsem si to spíš jen tak opakoval než že bych se to přehnaně moc šprtil. Učil jsem se zhruba pět dní, výsledkem byla jednička s pochvalou, že ani někteří matematici to mnohdy neumí tak dobře jako jsem to uměl já ;-). Písemná se mi tedy moc nevyvedla, ale na ústní jsem to naštěstí zachránil.

Druhý předmět byla Algoritmická matematika. To je takový předmět, na který se nechodí a učí se to ze skripta pro dálkaře. Bohužel v tom skriptu je to trochu ořezané, dálkaři to mají lehčí, takže ačkoliv jsme všichni uměli celé skriptum, dostala většina trojku, protože na zkoušce se vyskytly věci, které se braly na přednáškách, kam skoro nikdo nechodil. No co, trojka taky dobrá. Hlavně vzhledem k tomu, že jsem se na to učil asi odpoledne.

Další na řadě byly Formální jazyky a automaty. Hodně mrzký a hodně zajímavý předmět. Cvika byla v pohodě, možná nejzábavnější cvika, jaká jsme měli, ale přežít tříhodinovou přednášku, kde se od začátku do konce jedou definice a důkazy… Eh, to šlo špatně. Nakonec jsem ale byl na všech přednáškách kromě té poslední. Při učení jsme to spočítali na cca 70 stránek čistého textu, kde nebylo skoro nic jiného než definice a důkazy. Pro ilustraci jeden z těch delších důkazů, který nakonec byl na zkoušce. Když jsem přijel na koleje, tak mi spolubydla oznámil, že na písemce bude v praktické části jen konstrukce jakési tabulky, což jsem vůbec nevěděl, protože jsem nebyl na poslední přednášce, jak si vzpomínáte. A kdo neudělá praktickou, neudělal zkoušku. Takže jsme se to tak zhruba naučili a šli jsme tam. Původně nás bylo přihlášených deset, došlo nás tam pět. Udělal jsem to pouze já a to ještě za tři, zbytek vyházel. Nakonec jsem na sebe byl i trochu naštvaný, protože ta písemka nebyla těžká a kdybych nebyl °|°, mohl jsem mít dvojku, při štěstí i jedničku.

Paradigmata programování. Velice vtipný předmět, který jsem si nechal na konec. Brali jsme tam funkcionální programování v Lispu. Zajímavý předmět se zajímavých obsahem, ale bez jakýchkoliv učebních materiálů. Když jsem se začal učit, zjistil jsem, že kromě zdrojových kódů (celkem asi 1500 řádků v několika souborech. A 1500 řádků v Lispu je hergot hodně, asi jako 15 000 řádků v céčkových jazycích :-)) a nekompatibilních slajdů z loňského roku nic nemáme. Mluvilo se ještě o dvou anglických knížkách (které si člověk musel stáhnout z warezu…), ale i tam toho bylo hodně málo. Pokud člověk spojil chatrné zápisky z přednášek (přednášky nebyly zrovna zapisovatelné, spíš se dobře poslouchaly), staré slajdy a anglické knížky, měl materiály tak ke třetině toho, co jsme se učili. Bezva. Takže jsem strávil pár hodin koukáním do zdrojáků v Lispu a pak šel na zkoušku. Měla být ve středu, ale učitel byl nemocný a tak se zkouška přesunula na pátek. Nejdříve byla písemná část, ze které jsme museli dostat polovinu bodů, přičemž se bodíky strhávaly fakt za každou blbůstku. Celý bod z příkladu měl opravdu jen ten, kdo odpověděl maximálně správně. Po asi třech hodinách čekání učitel vyšel a že prý to dopadlo mimořádně špatně a nikdo to neudělal nejlepší výsledek byl 3,8 bodů ze čtyř potřebných (bylo celkem osm příkladů). Hmm, dobrý no. Já měl 3,7. Nakonec řekl, že na ústní vezme všechny, ale ti s menším počtem bodů to budou mít o to složitější. Já šel asi třetí, přede mnou šel človíček, který měl 3,8 bodů a neudělal to… Hehe. Ale šel jsem tam a zůstal jsem tam přes půl hodiny. Dusil mě celkem dlouho, furt jsem nemohl přijít na jednu banálnost, která mě napadla až na kolejích. Nakonec jsem mu tam napsal takřka z hlavy jedno hezké rekurzivní makro a dal mi to za dva. Štígro. Mimochodem nikdo jiný to od nás neudělal. Já těm svým spolužákům přináším smůlu, kromě algoritmické matematiky jsem zkoušku udělal vždy jen já, ostatní ne (i na matematice to ostatní dva nedali).

A to je všechno. Teď mám týden volno a pak zase další semestr…

OOP: Obsah seriálu

OOP teoreticky

Následující články jsou součástí jednoho uceleného seriálu. Pokud nebudete číst seriál postupně, asi vám to nebude moc dávat smysl.

OOP prakticky

OOP prakticky: Na co jsme zapomněli

Zde vám ukážu, na co všechno jsem při návrhu programu zapomněl a jak jednoduchá bude náprava. Jedna z výhod objektů totiž mimo jiné je snadná údržba a snadná oprava vzniklých chyb. Zpravidla stačí opravit nějakou metodu v jedné třídě a je to. Horší chyby vzniknou při špatném návrhu programu, ale to je na jiné povídání.

Nezapouzdřené výrazy

Nejprve ukázkový chybný kód:

1
2
3
Soucet soucet = new Soucet();
Console.WriteLine("Tohle vyhodí chybu: {0}", soucet.A.ToString());
Console.Read();

Otázka zní – proč to vyhodí chybu? Objekt je přece zapouzdřený a nemůže se tak dostat do nežádoucího stavu. Odpověď je, že je zapouzdřený špatně, protože jsme zapomněli na výchozí hodnoty parametrů. Pokud vytvoříme Součet a nepřidáme mu ručně nějaké hodnoty, bude ve slotech A a B prázdno a program při pokusu vytáhnout ze slotů nějakou hodnotu spadne. Chybu napravíme tak, že už při vytvoření objektu nastavíme sloty na nějakou výchozí hodnotu, typicky asi na nulu. Třídu Binární Výrazy upravíme takto:

1
2
3
4
5
public BinarniVyraz() 
{
A = new Konstanta();
B = new Konstanta();
}

To je vše. Při vytváření prázdného součtu se automaticky do slotů A a B uloží nulová konstanta a program pak nespadne. Co ostatní třídy? U Konstanty se automaticky do hodnoty uloží nula, protože se jedná o Integer, a to jeho výchozí hodnota (alespoň v C#). U Proměnné už by to ale nějakou rozumnou výchozí hodnotu chtělo, protože za současného stavu se tam ukládá prázdný řetězec, což je blbé. Program sice nespadne, ale proměnná s žádným názvem je blbá proměnná. Takže jako výchozí hodnotu můžeme zvolit „x“:

1
2
3
4
public Promenna() 
{
Nazev = "x";
}

Pro klid duše můžeme udělat podobnou úpravu i u Konstanty, abychom měli jistotu, že tam bude na začátku nula:

1
2
3
4
public Konstanta() 
{
Hodnota = 0;
}

OOP teoreticky: Metody a vlastnosti

Objekt nemusí pouze uchovávat informace, jak jsme si ukazovali v minulém příkladu. N to bychom objekty vůbec nepotřebovali, vystačili bychom si jen s nějakými strukturami. Síla objektů je v tom, že mohou obsahovat obslužné funkce, kterým se říká metody. Tyto metody pak mohou měnit stav objektu. V předchozích příkladech jsem zmínil krásnou funkci, která manipuluje s objektem a mění jeho vnitřní stav. Byla to metoda Posun(). Co má tato metoda dělat? Bude přebírat dva číselné argumenty a jednoduše posune souřadnice bodu o zadané délky. Implementace:

1
2
3
4
5
6
7
8
9
10
11
12
class Bod
{
public int X;
public int Y;

public void Posun(int PosunX, int PosunY)
{
X += PosunX;
Y += PosunY;
}

}

Mělo by být vcelku jasné, jak to funguje. Jen bych rád zdůraznil, že všechny metody v dané třídě mohou pracovat s proměnnými, které ten objekt má. Na osmém řádku předchozího kódu tedy metoda Posun() manipuluje s proměnnou X, kterou jsme deklarovali na třetím řádku. Každá metoda do těchto proměnných vidí a může je měnit, pokud to nějak nezakážeme, ale o tom potom.

A kuš, už těm proměnným X a Y nebudeme říkat proměnné, ale vlastnosti či sloty. V céčkových jazycích je běžnější označení Vlastnost, ale v jiných jazycích se můžeme setkat i s jiným označením, třeba slot. Občas to budu míchat, někdy mi přijde příhodnější to, jindy ono. Já vím, nešvar. Takže obecně řečeno, objekt má různé vlastnosti, náš objekt Bod má dvě vlastnosti: X a Y. Takový objekt Hráč by mohl mít třeba vlastnost Jméno. Objekt Manažer by mohl mít slot pro uchování Hrací desky, na které se hraje a také slot, ve kterém si bude uchovávat Rozhodčího, který zná pravidla hry.

Metody jsou zpravidla funkce, které nějak manipulují s vlastnosti daného objektu. Buď si jen přečte data z vlastností a vrátí nějakou zajímavou informaci, například v jakém kvadrantu Bod leží, nebo může přímo manipulovat a měnit vlastnost objektů. To je příklad naší metody Posun(), která mění hodnoty obou vlastností.

Trochu teoretičtěji řečeno s objektem pracujeme pomocí zpráv. Objekt už si na to reaguje po svém, to je jeho věc, jak daný problém vyřeší (a je to problém programátora, jak to naprogramuje). My například pošleme objektu zprávu „hele kémo, hejbni tím svým líným zadkem a posuň se“ a objekt na to zareaguje „jasná páka, kémo“ a posune se. Jakožto uživatele nějaké třídy nás nezajímá jak to provede. Pokud budeme chtít, aby se náš bod posunul třeba o +10 pixelů na ose x, jednoduše pošleme objektu zprávu a předáme příslušné parametry:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void Main()

{
Bod bod = new Bod();
Console.WriteLine("Bod před posunutím: [{0}, {1}]", bod.X, bod.Y);
bod.Posun(10, 0);
Console.WriteLine("Bod po posunutí: [{0}, {1}]", bod.X, bod.Y);
Console.Read();

/*
* Program vypíše:
* Bod před posunutím: [0, 0]
* Bod po posunutí: [10, 0]
*/

}

Jako uživatelé dané třídy se už nestaráme o to, jak je obslužná metoda implementována, pro nás už je to černá bedna, do které nevidíme a ani vidět nechceme. Zkrátka objekt se umí posouvat, tak toho využijeme. Všimněte si hezké maličkosti. Pokud změníme reprezentaci souřadnic z čísel třeba na písmena (namísto [1, 2] –> [a, b]), stačí když jen upravíme metodu Posun(), aby si čísla, která dostane v argumentech, převedla na písmena a pak nějak dále zpracovala. Jakékoliv výskyty volání metody Posun() můžou zůstat nezměněny. Jinou část kódu zkrátka vůbec nemusíme přepisovat. To je docela hezké, ne?

OOP teoreticky: Základy

Takže jaký je smysl či princip OOP? Rozdělit celý program na dílčí části a řešit postupně pouze tyto menší části programu. Tím, že problém rozdělíme na menší části, stává se celkový projekt snáze řešitelný, snáze analyzovatelný a snáze udržovatelný. Příklad: programujeme nějakou hru. Třeba šachy, to je vcelku jedno. Jak by se to řešilo objektově? Celý problém by se rozdělil na menší díly, takže bychom měli část, která by se starala o pravidla hry, byl by to takový rozhodčí. Další část by se starala o reprezentaci hrací desky, dále bychom potřebovali něco, co bude celou hru řídit, nějakého manažera celé hry. Vidíte, jak jsme hezky rozkouskovali projekt na menší části? Důležité je, že každá část se stará jen o to své. Rozhodčí jako jediný zná pravidla hry. Manažer nemá žádnou představu o tom, kam může která figurka skočit.

Všem předchozím částem můžeme říkat objekty. Rozdělili jsme velký problém šachů na menší části/objekty Rozhodčí, Manažer, Hrací deska apod. Takže co je to objekt? Objekt je jakási entita, struktura, která reprezentuje určitou jedinečnou souvislou část celého programu. Pokud poskládáme a pospojujeme všechny objekty dohromady, máme celý program.

Více programátorsky je objekt struktura, která obsahuje určitě proměnné a určité funkce, které se vztahují k myšlence objektu. Například pokud bychom měli objekt Bod, mohl by obsahovat proměnné X a Y, reprezentující x-ovou a y-ovou souřadnici. A teď by to chtělo vymyslet nějakou funkci, která by se k tomuto objektu hodila. Co můžeme dělat s bodem/souřadnicí? Bod můžeme třeba posouvat, takže objekt Bod by mohl mít u sebe funkci Posun(), která by daný bod posunula o nějaké ty pixely.

OOP prakticky: Substituce

Jak budeme provádět substituci? Jednoduše, musíme v našem výrazu najít všechny proměnné stejného názvu a namísto těchto proměnných vrátit výraz, který je má nahradit. V podstatě na tom nic není. Ještě jedna otázka: budou mít metodu substituce všechny třídy? Vždyť substituovat budeme pouze proměnnou, takže by to svádělo k tomu napsat tuto metodu pouze semka. To by samozřejmě byla chyba. Pokud máme Proměnnou v Součtu, je jasné, že i tato Proměnná musí být nahrazena. Aby tato Proměnná mohla být nahrazena, musíme tu Proměnnou nejprve najít. To uděláme nejjednodušeji tak, že zavoláme metodu Substituce() u Součtu a ta zavolá metodu Substituce() jak na výraz A, tak na výraz B. Tím dosáhneme toho, že ať budeme třeba stovky zanořených Součtů, nakonec se dostaneme ke všech výrazům a všechny zkontrolujeme, jestli se náhodou nejedná o Proměnnou, kterou hledáme. Takže odpověď na původní otázku zní, že metodu Substituce() bude mít každý Matematický Výraz. Tam ji také definujeme.

1
2
3
4
5
6
{
public abstract MatematickyVyraz Derivace();
public abstract MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota);
public abstract MatematickyVyraz Kopie();

}

Metoda bude mít dva argumenty: String reprezentující Název Proměnné, kterou hledáme a Matematický Výraz, kterým chceme nahrazovat. Implementace v jednotlivých třídách již bude triviální. Připomínám, že metoda bude vracet nový Matematický Výraz, takže v každém kroku musím vytvářet nové kopie objektů. Konstanta:

1
2
3
4
public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)
{
return Kopie();
}

Konstantu zřejmě nijak substituovat nemůžeme, vrátíme proto pouze kopii. Implementace v Proměnné:

1
2
3
4
5
6
7
8
public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)
{
if(Nazev == NazevPromenne)
return Hodnota;
else
return Kopie();

}

Nejprve zjistíme, jestli jsme našli proměnnou, kterou hledáme. Pokud ano, vrátíme předaný Matematický Výraz. Pokud ne, vrátíme také pouze kopii Proměnné. U Binárních výrazů bude situace stejná – vytvoříme vždy novou instanci daného výrazu a na vlastnosti A a B poštveme substituci. Implementace u Součtu:

1
2
3
4
5
6
7
8
public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)

{
Soucet soucet = new Soucet();
soucet.A = A.Substituce(NazevPromenne, Hodnota);
soucet.B = B.Substituce(NazevPromenne, Hodnota);
return soucet;
}

Rozdíl:

public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)

1
2
3
4
5
6
{
Rozdil rozdil = new Rozdil();
rozdil.A = A.Substituce(NazevPromenne, Hodnota);
rozdil.B = B.Substituce(NazevPromenne, Hodnota);
return rozdil;
}

Součin:

public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)

1
2
3
4
5
6
{
Soucin soucin = new Soucin();
soucin.A = A.Substituce(NazevPromenne, Hodnota);
soucin.B = B.Substituce(NazevPromenne, Hodnota);
return soucin;
}

Podíl:

public override MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota)

1
2
3
4
5
6
{
Podil podil = new Podil();
podil.A = A.Substituce(NazevPromenne, Hodnota);
podil.B = B.Substituce(NazevPromenne, Hodnota);
return podil;
}

A to je všechno. Vyzkoušíme.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
static void Main(string[] args)
{
Konstanta a = new Konstanta(10);
Konstanta b = new Konstanta(20);
Promenna x = new Promenna("x");
Promenna y = new Promenna("y");
Soucet soucet = new Soucet(a, x);
Soucin soucin = new Soucin(b, y);
Rozdil rozdil = new Rozdil(soucet, soucin);
Console.WriteLine("Před substitucí: {0}",
rozdil.ToString());

Console.WriteLine("Po substituci [x => 666]: {0}",
rozdil.Substituce("x", new Konstanta(666)).ToString());

Console.WriteLine("Po substituci [x => 666; y => 33]: {0}",
rozdil.Substituce("x", new Konstanta(666)).Substituce("y", new Konstanta(33)).ToString());

Console.WriteLine("Po substituce [x => (10 + 20)]: {0}",
rozdil.Substituce("x", new Soucet(a, b)).ToString());

Console.Read();

/*

Výstup z programu:
Před substitucí: ((10 + x) - (20 \* y))
Po substituci [x => 666]: ((10 + 666) - (20 \* y))
Po substituci [x => 666; y => 33]: ((10 + 666) - (20 \* 33))
Po substituce [x => (10 + 20)]: ((10 + (10 + 20)) - (20 \* y))
*/

}

OOP prakticky: Polymorfismus

Konečně se dostane na metody zjednodušení nebo derivování. Metodu pro derivaci budou mít jistě všechny matematické výrazy. Pokud jste dobře četli předchozí kapitolu, tak víte, že pak definice takovéto metody patří do vrchní třídy Matematický Výraz. Ovšem naskýtá se jeden zajímavý problém. Přestože každý Matematický Výraz, se kterým my pracujeme, je derivovatelný, implementace derivace se pro každý výraz liší. Jinak se derivuje konstanta a jinak třeba součet. Potřebovali bychom tudíž mít v hlavní třídě Matematický Výraz definovanou metodu pro derivování, abychom ji mohli používat v každém Matematickém Výrazu nezávisle na jeho přesném typu a zároveň bychom potřebovali tuto metodu v každé třídě přepsat podle pravidel derivování té dané třídy. A přesně to nám umožňuje polymorfismus a přepisování metod.

Díky polymorfismu může mít každá třída ve stromu dědičnosti stejnou metodu s různou implementací. Pokud si vzpomenete na předchozí příklad s Geometrickými útvary, tak společná metoda by mohl být ten obsah. U Obdélníku i u Kružnice jsme schopni spočítat obsah, avšak pokaždé naprosto jiným způsobem. Další hezký příklad na polymorfismus je kopírování objektů. Každý objekt jistě může vytvořit svou kopii, avšak každý objekt bude tu kopii vytvářet jinak, protože každý objekt má (respektive může mít) jiné sloty/vlastnosti. Touto metodou tedy začneme, protože je nejnázornější a budeme ji využívat dále při derivování a zjednodušování. Nejprve si definujeme abstraktní metodu Kopie() v třídě Matematický Výraz. Abstraktní metoda značí, že každý objekt, který je potomkem, musí tuto metodu přepsat. Abstraktní metoda vlastně jen definuje hlavičku metody, vůbec se nezabývá implementací; tím se zabývají až třídy níže. Ono by to také bylo nelogické, kdyby se tím vrchní třída zabývala – jak má třída Matematický Výraz vědět, jak zkopírovat třeba Součet? Jdeme implementovat:

1
2
3
4
abstract class MatematickyVyraz
{
public abstract MatematickyVyraz Kopie();
}

Kompilátor C# nám momentálně zahlásí mnoho chyb, protože ostatní třídy nerespektují nařízení své matičky a neimplementují metodu Kopie(). Takže ji jdeme přidat ostatním třídám. Při přepisování metod se v C# používá klíčové slovo override. S tím už jsme se setkali, když jsme přepisovali metodu ToString(). Tato metoda je definovaná úplně nejvýše a každičký objekt může tuto metodu přepsat. Zpět ke kopírování. Pokud chceme zkopírovat určitý objekt, vytvoříme instanci téhož objektu a zkopírujeme hodnoty z původního objektu do nového objektu. Metoda pro třídu Konstanta:

1
2
3
4
public override MatematickyVyraz Kopie()
{
return new Konstanta(Hodnota);
}

Metoda pro třídu Proměnná:

1
2
3
4
public override MatematickyVyraz Kopie()
{
return new Promenna(Nazev);
}

Metoda pro třídu Součet:

1
2
3
4
public override MatematickyVyraz Kopie()
{
return new Soucet(A.Kopie(), B.Kopie());
}

Zde bych se trochu zastavil. Pokud chceme zkopírovat objekt součet, nestačí vytvořit nový objekt Součet a suše přiřadit A a B. Neprovedla by se totiž skutečná kopie, protože v novém i starém objektu by A a B odkazovalo na stejný objekt. Byly by to dvě různé třídy, které by se odkazovaly na stejné hodnoty A a B. Pokud bychom v jedné třídě změnili hodnotu A, změnila by se hodnota i ve druhé třídě. Metoda pro Rozdíl:

1
2
3
4
public override MatematickyVyraz Kopie()
{
return new Rozdil(A.Kopie(), B.Kopie());
}

A teď si ukážeme to pravé kouzlo a tu největší sílu polymorfismu. Ve chvíli, kdy všechny naše třídy implementují metodu Kopie(), můžeme na libovolný objekt poslat metodu Kopie() a získáme kopii všech členů, které výraz obsahuje. Pokud máme výraz (3 + 10), zavolá se nejprve metoda Kopie() u Součtu. Ta vytvoří nový Součet a zavolá Kopii na své dvě hodnoty. Vrátí se tedy kopie trojky a desítky. Pokud bychom vzali složitější příklad, třeba (5 + (10 – 4)), tak se nejprve vytvoří nový součet a pak se zavolá kopie pětky a kopie rozdílu. A kopie rozdílu sama vytvoří nový Rozdíl a udělá kopii konstant 10 a 4. Není to kouzelné, jak díky polymorfismu jsme schopni prolézt celý strom objektů? Můžeme si to hned vyzkoušet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
static void Main(string[] args)
{
Konstanta a = new Konstanta(10);
Konstanta b = new Konstanta(20);
Promenna x = new Promenna("x");
Promenna y = new Promenna("y");
Soucet soucet1 = new Soucet(a, x);
Soucet soucet2 = new Soucet(b, y);
Rozdil rozdil1 = new Rozdil(soucet1, soucet2);
Console.WriteLine("Rozdíl1: {0}", rozdil1.ToString());
MatematickyVyraz rozdil2 = rozdil1.Kopie();
Console.WriteLine("Rozdíl2: {0}", rozdil2.ToString());
rozdil1 = new Rozdil(a, b);
Console.WriteLine("Rozdíl1: {0}", rozdil1.ToString());
Console.WriteLine("Rozdíl2: {0}", rozdil2.ToString());
Console.Read();

/*
* Výstup z programu:
* Rozdíl1: ((10 + x) - (20 + y))
* Rozdíl2: ((10 + x) - (20 + y))
* Rozdíl1: (10 - 20)
* Rozdíl2: ((10 + x) - (20 + y))
*/
}

OOP prakticky: Zjednodušování

Už u derivací jsme se setkali s tím, že jsme ve výrazu měli spoustu částí, které by jistě šly zkrátit. Například je zbytečné zobrazovat výraz (0 * a), protože nula krát cokoliv je stejně nula. Jak to tedy provedeme? Základní zjednodušení můžeme udělat tak, že pokud je daný výraz ve výsledku nulový, prostě vrátíme novou nulovou Konstantu. Ve specifických případech poté můžeme metodu zjednodušení přepsat tak, aby zjednodušovala poněkud sofistikovaněji. Začněme ale s tím nulovým výraz. Budeme potřebovat metodu, která zjistí, zda je daný výraz nulový. Otázka zní: má smysl definovat tuto metodu pro každý Matematický Výraz? Jistě můžeme rozhodnout, zda třeba Součet nebo Rozdíl je ve výsledku nulový. Stejně tak se můžeme rozhodnout u Konstanty. Jedinou potíž dělá proměnná. Tam ta metoda moc smysl nemá, protože Proměnná nemůže být nikdy nulová, leda až po dosazení. Nicméně stále jsme schopni rozhodnout, kdy je Výraz nulový a kdy ne – v případě Proměnné vrátíme vždy False, každá Proměnná je nenulová. Jak metodu zavedeme? Přidáme ji do třídy Matematický Výraz takto:

1
2
3
4
5
6
7
abstract class MatematickyVyraz
{
public abstract MatematickyVyraz Derivace();
public abstract MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota);
public abstract MatematickyVyraz Kopie();
public abstract bool NulovyVyraz();
}

Zajímavá otázka je, zda má být metoda abstraktní. Můžeme ji totiž definovat pouze jako virtuální metodu s tím, že defaultně bude vracet False. Ušetřili bychom si trochu psaní ve třídách, u kterých nejsme schopni zjistit, zda je výraz nulový (Proměnná) nebo ve výrazech, které nikdy nebudou záporné – kterákoliv funkce s oborem hodnot, ve kterém se nenachází nula (1 / x). Pro jednoduchost ponechme metodu abstraktní a v každé třídě si tuto metodu napíšeme zvlášť. Pojďme tedy implementovat metodu NulovyVyraz() v našich třídách. Začneme konstantou. Zde je výraz nulový, když je nulová Hodnota Konstanty:

1
2
3
4
public override bool NulovyVyraz()
{
return Hodnota == 0;
}

Dále Proměnná. Jak už jsme řekli, proměnná nebude nulová nikdy:

1
2
3
4
public override bool NulovyVyraz()
{
return false;
}

Teď Binární Výrazy. Začneme součtem. Kdy je součet nulový? Když platí rovnice (-A = B). To prozatím nejsme schopni vyjádřit, protože naše kalkulačka neumí počítat výsledné hodnoty. Takže se spokojíme s implementací, že Součet je nulový, když jsou nulové oba dva Výrazy A i B.

1
2
3
4
public override bool NulovyVyraz()
{
return A.NulovyVyraz() && B.NulovyVyraz();
}

U Rozdílu to nadefinujeme stejně:

1
2
3
4
public override bool NulovyVyraz()
{
return A.NulovyVyraz() && B.NulovyVyraz();
}

U Součinu to bude podobné, akorát tam bude jiný logický operátor. Stačí, když alespoň jeden výraz bude nulový a již je celý výraz nulový:

1
2
3
4
public override bool NulovyVyraz()
{
return A.NulovyVyraz() || B.NulovyVyraz();
}

U Podílu je pak jediná možnost na nulovost: čitatel je rovný nule.

1
2
3
4
public override bool NulovyVyraz()
{
return A.NulovyVyraz();
}

To bychom měli. Teď už jen zbývá definovat metodu pro zjednodušení, která zjistí, zda je daný výraz nulový a pokud ano, vrátí nulovou Konstantu. Kde danou metodu definujeme? Zjednodušovat budeme chtít všechny Matematické Výrazy, přestože u některých bude zjednodušení triviální (Konstanta a Proměnná). Metodu tedy definujeme v hlavní třídě Matematické Výrazy. Implementace:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
abstract class MatematickyVyraz
{
public virtual MatematickyVyraz Zjednodus()
{
if(NulovyVyraz())
return new Konstanta();
return Kopie();
}

public abstract MatematickyVyraz Derivace();
public abstract MatematickyVyraz Substituce(string NazevPromenne, MatematickyVyraz Hodnota);
public abstract MatematickyVyraz Kopie();
public abstract bool NulovyVyraz();
}

Tuto metodu zdědí všechny třídy, takže už teď můžeme vyzkoušet, jak naše zjednodušování funguje:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
static void Main(string[] args)

{

Konstanta nula = new Konstanta();

Konstanta deset = new Konstanta(10);

Promenna a = new Promenna("a");

Soucin nulovySoucin = new Soucin(a, nula);

Soucet obycejnySoucet = new Soucet(a, deset);

Soucet nulovySoucet = new Soucet(nula, nula);

Soucet dvojitaNula = new Soucet(nulovySoucin, nulovySoucin);

Soucet hokusPokus = new Soucet(nulovySoucin, deset);

Console.WriteLine("Před zjednodušením: {0}",

nulovySoucin.ToString());

Console.WriteLine("Po zjednodušení: {0}",

nulovySoucin.Zjednodus().ToString());

Console.WriteLine("-------");

Console.WriteLine("Před zjednodušením: {0}",

obycejnySoucet.ToString());

Console.WriteLine("Po zjednodušení: {0}",

obycejnySoucet.Zjednodus().ToString());

Console.WriteLine("-------");

Console.WriteLine("Před zjednodušením: {0}",

nulovySoucet.ToString());

Console.WriteLine("Po zjednodušení: {0}",

nulovySoucet.Zjednodus().ToString());

Console.WriteLine("-------");

Console.WriteLine("Před zjednodušením: {0}",

dvojitaNula.ToString());

Console.WriteLine("Po zjednodušení: {0}",

dvojitaNula.Zjednodus().ToString());

Console.WriteLine("-------");

Console.WriteLine("Před zjednodušením: {0}",

hokusPokus.ToString());

Console.WriteLine("Po zjednodušení: {0}",

hokusPokus.Zjednodus().ToString());

Console.Read();

/*

Výstup z programu:

Před zjednodušením: (a * 0)

Po zjednodušení: 0

-------

Před zjednodušením: (a + 10)

Po zjednodušení: (a + 10)

-------

Před zjednodušením: (0 + 0)

Po zjednodušení: 0

-------

Před zjednodušením: ((a * 0) + (a * 0))

Po zjednodušení: 0

-------

Před zjednodušením: ((a * 0) + 10)

Po zjednodušení: ((a * 0) + 10)

*/

}

Vidíme, že vše hezky funguje, až na poslední příklad. Tam máme zcela zřejmý nulový výraz (a * 0), přesto zjednodušen nebyl. Chyba je v tom, že metodou Zjednoduš() neprocházíme celý strom výrazů. V Binárních výrazem je nevoláme na sloty A a B. Takže jdeme přepisovat. Zároveň můžeme metodu Zjednoduš() u sčítání implementovat tak, aby v případě, kdy je jeden z výrazů nulový, vrátila druhý výraz:

1
2
3
4
5
6
7
8
9
10
11
12
public override MatematickyVyraz Zjednodus()
{
MatematickyVyraz v1 = A.Zjednodus();
MatematickyVyraz v2 = B.Zjednodus();

if(v1.NulovyVyraz())
return v2;
if(v2.NulovyVyraz())
return v1;

return new Soucet(v1, v2);
}

Všimněte si, že nejdřív jako první zjednodušíme A a B a až poté zjišťujeme, jestli je tento výraz nulový. Kdybychom toto neudělali, nemuseli bychom dostat maximálně možný zjednodušený výraz.

Podobnou úpravu uděláme u Rozdílu. Jen pozor na znaménka u Rozdílu – v případě, že je A nulové, nemůžeme vrátit B, protože by se ztratilo znaménko. Museli bychom vrátit –B, což vlastně neumíme udělat jinak než Rozdílem (případě ještě složitěji Součinem):

1
2
3
4
5
6
7
8
public override MatematickyVyraz Zjednodus()
{
MatematickyVyraz v1 = A.Zjednodus();
MatematickyVyraz v2 = B.Zjednodus();
if(v2.NulovyVyraz())
return v1;
return new Rozdil(v1, v2);
}

Implementace u součinu:

1
2
3
4
5
6
7
8
public override MatematickyVyraz Zjednodus()
{
MatematickyVyraz v1 = A.Zjednodus();
MatematickyVyraz v2 = B.Zjednodus();
if(v1.NulovyVyraz() || v2.NulovyVyraz())
return new Konstanta();
return Kopie();
}

A u podílu:

1
2
3
4
5
6
7
8
9
10
public override MatematickyVyraz Zjednodus()
{
MatematickyVyraz v1 = A.Zjednodus();
MatematickyVyraz v2 = B.Zjednodus();
if(v1.NulovyVyraz())
return new Konstanta();
if(v2.NulovyVyraz())
throw new Exception("Nemůžeme dělit nulou!");
return new Podil(v1, v2);
}

Zde bychom měli ošetřovat, zda není zjednodušený výraz nulový, abychom po zjednodušení nedostali nesmysl. Předchozí hokusPokus příklad se již zjednoduší správně:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
static void Main(string[] args)

{

Konstanta nula = new Konstanta();

Konstanta deset = new Konstanta(10);

Promenna a = new Promenna("a");

Soucin nulovySoucin = new Soucin(a, nula);

Soucet hokusPokus = new Soucet(nulovySoucin, deset);

Console.WriteLine("Před zjednodušením: {0}",

hokusPokus.ToString());

Console.WriteLine("Po zjednodušení: {0}",

hokusPokus.Zjednodus().ToString());

Console.Read();

/*

Výstup z programu:

Před zjednodušením: ((a * 0) + 10)

Po zjednodušení: 10

*/

}

OOP prakticky: Má být konstanta objekt?

Teď už opravdu začínáme s programováním. A hned otázka na úvod – má být nejjednodušší matematický výraz, konstanta, objekt nebo stačí, pokud budeme pracovat s holým číslem? (Poznámka: v programu budu pro jednoduchost používat datový typ Integer, ale není to nijak podstatné.) Nabízí se odpověď, že konstanta je prostě číslo, tak proč ho deklarovat jako objekt? Odpověď se dovíte v průběhu dalšího čtení, teď se to bude špatně vysvětlovat, když neznáte základní části OOP. Ale zkusme to. Představte si, že všechny ostatní výrazy (proměnnou, součet, …) definujete jako objekty a pouze konstantu definujete jako číslo. Vidíte už trošku, že to asi nebude ono? Jak byste vytvořili například metodu, která danou konstantu zderivuje? Kde byste takovou funkci deklarovali? A teď si představte, že byste při každém volání derivace museli kontrolovat, zda derivujete konstantu nebo něco jiného, protože u ostatních výrazů bude metoda derivace definovaná jinde než u konstanty. Takže pokud by to byla konstanta, zavolali byste speciální funkci pro konstantu, pokud by to byl jiný objekt, zavoláte standardní metodu. Už vidíte, že v objektovém stromu je výhodné mít všechny dílčí části jako objekty a nedávat některé části jako základní typy (tj. Integer nebo třeba String)?

Dobře, ujasnili jsme si, že konstanta bude objekt jako každý jiný matematický výraz. Jak nyní nadefinujeme naši třídu? Třída bude mít jednu vlastnost, a sice Hodnota konstanty. Hodnota konstanty již může být normální Integer, konstanta už nemůže obsahovat další komplikovanější výrazy. A to je všechno, víc nepotřebujeme:

1
2
3
4
5
6
7
8
9
10
11
12
class Konstanta

{
public int Hodnota;
public Konstanta() { }

public Konstanta(int Hodnota)
{
this.Hodnota = Hodnota;
}

}

To by byla první, naivní, verze Konstanty. Tato třída ještě určitě není finální, budeme ji dále vylepšovat. Jako první se zaměříme na poslední bod předchozí kapitoly. Naše aplikace má být mít pro každý výraz definovanou metodu pro čitelný výpis. Přepíšeme tedy metodu ToString tak, aby vracela číslo ze slotu Hodnota:

1
2
3
4
public override string ToString()
{
return Hodnota.ToString();
}

Nyní máme metodu, která nám vrací textovou reprezentaci Konstanty. Klíčového slova override si prozatím nevšímejte, to má co dočinění s polymorfismem, které přijde na řadu až později. Nyní považujme naši třídu za dostatečně soběstačnou a můžeme vyzkoušet, jak funguje:

1
2
3
4
5
6
7
8
9
static void Main(string\[\] args)
{
Konstanta a = new Konstanta(10);
Konstanta b = new Konstanta(25);
Console.WriteLine("a: {0}, b: {1}", a.ToString(), b.ToString());
// Výpis bude: a: 10, b: 25
Console.Read();

}

Víc toho zatím třída Konstanta neumí. Prozatím nám to bude stačit, ještě se k ní vrátíme. Nyní se podíváme na další třídu, Proměnná. Na této třídě již mohu vysvětlit první z pilířů:

OOP prakticky: Derivace

Dostáváme se k zajímavější látce, a to jsou derivace. Pokud derivovat neumíte, nevadí, je to vesměs jednoduchá záležitost, aplikace několika triviálních vzorečků. Ty můžete najít třeba na Wikipedii.

Teď musíme přijít na to, kam metodu definovat. Potřebujeme, aby byl derivovatelný každý výraz, který vytvoříme. Metodu derivace dostaneme do každé třídy tak, že ji přidáme do Otce všech tříd, do Matematického výrazu. Tato metodu bude v této třídy opět pouze abstraktní, my nemůžeme vědět, jak budou derivovány jednotlivé další výrazy. Třídu upravíme takto:


   1: abstract class MatematickyVyraz
   2: {
   3:     public abstract MatematickyVyraz Kopie();
   4:     public abstract MatematickyVyraz Derivace();
   5: }

Nyní máme v každé třídě přístup k metodě Derivace(), avšak nyní ji musíme v každé třídě definovat. Tak do toho. Začneme u konstanty. Jaká je derivace konstanty? Inu, nula. Pokud zderivujete jakékoliv číslo, získáte nulu. Takže v konstantě bude derivace definována takto:


   1: public override MatematickyVyraz Derivace()
   2: {
   3:     return new Konstanta();
   4: }

Teď šup na proměnnou. Jaká je derivace proměnné? Jednička. Takže to definujme:


   1: public override MatematickyVyraz Derivace()
   2: {
   3:     return new Konstanta(1);
   4: }

Teď se podívejte na Binární Výrazy. Mají Binární Výrazy jednotnou derivaci, abychom ji mohli nadefinovat přímo ve třídě Binárních Výrazů? Nemají, součet, rozdíl, součin i podíl se derivují jinak. Začneme derivací součtu. Derivace součtu je součet derivací, tedy (a + b)’ = a’ + b’ (apostrof je derivace). Metoda ve třídě Součet by vypadala takto:


   1: public override MatematickyVyraz Derivace()
   2: {
   3:     return new Soucet(A.Derivace(), B.Derivace());
   4: }

Vytvoříme novou instanci třídy Součet a jako argumenty mu předáme zderivované A a zderivované B. Děláme přesně to, co po nás chce vzorec. Derivaci u odečítání vypadá úplně stejně, jen budeme vytvářet instanci Rozdílu:


   1: public override MatematickyVyraz Derivace()
   2: {
   3:     return new Rozdil(A.Derivace(), B.Derivace());
   4: }

Abychom si ukázali i trochu složitější derivace, nadefinujeme si konečně třídy Součin a Podíl. Budou to opět potomci Binárního Výrazu, ale jinak na těch třídách nebude nic zajímavého. Následuje Součin:


   1: class Soucin : BinarniVyraz
   2: {
   3:     public Soucin() : base() { }
   4:     public Soucin(MatematickyVyraz A, MatematickyVyraz B) : base(A, B) { }
   5:  
   6:     public override string ToString()
   7:     {
   8:         return ToBinaryString(“*”);
   9:     }
  10:  
  11:     public override MatematickyVyraz Kopie()
  12:     {
  13:         return new Soucin(A.Kopie(), B.Kopie());
  14:     }
  15: }

A Podíl. Zde si všimněte, že v rámci zapouzdření kontrolujeme, jestli se náhodou nepokoušíme dělit nulou.


   1: class Podil : BinarniVyraz
   2: {
   3:     public Podil() : base() { }
   4:     public Podil(MatematickyVyraz A, MatematickyVyraz B)
   5:         : base(A, B)
   6:     {
   7:  
   8:     }
   9:  
  10:     private MatematickyVyraz _B;
  11:     public override MatematickyVyraz B
  12:     {
  13:         get { return _B; }
  14:         set
  15:         {
  16:             if(value is Konstanta)
  17:                 if((value as Konstanta).Hodnota == 0)
  18:                     throw new Exception(“Nemůžeme dělit nulou!”);
  19:  
  20:             _B = value;
  21:         }
  22:     }
  23:  
  24:     public override string ToString()
  25:     {
  26:         return ToBinaryString(“/“);
  27:     }
  28:  
  29:     public override MatematickyVyraz Kopie()
  30:     {
  31:         return new Podil(A.Kopie(), B.Kopie());
  32:     }
  33: }

Všimněte si ještě, že jsme přepsali set blok u „B“. Abychom toto vůbec mohli udělat, musíme přepsat rodičovskou třídu Binární Výraz a označit tam vlastnost B za přepisovatelnou pomocí klíčového slova C# virtual.


   1: abstract class BinarniVyraz : MatematickyVyraz
   2: {
   3:     public MatematickyVyraz A;
   4:     public virtual MatematickyVyraz B;
   5:  
   6:     public string ToBinaryString(string Znamenko)
   7:     {
   8:         return String.Format(“({0} {1} {2})”, A.ToString(), Znamenko, B.ToString());
   9:     }
  10: }

A teď si pojďme definovat derivace u Součinu a Podílu. Začneme Součinem, kde platí vzorec: (a b)’ = (a’ b) + (a * b’). Vytvoření derivace tedy bude u Součinu o fous složitější než u předchozích tříd:


   1: public override MatematickyVyraz Derivace()
   2: {
   3:     Soucet soucet = new Soucet();
   4:  
   5:     soucet.A = new Soucin(A.Derivace(), B.Kopie());
   6:     soucet.B = new Soucin(A.Kopie(), B.Derivace());
   7:  
   8:     return soucet;
   9: }

U podílu platí vzorec: (a / b)’ = ((a’ b) + (a b’)) / b2. Implementace ve třídě Podíl:


   1: public override MatematickyVyraz Derivace()
   2: {
   3:     Soucet soucet = new Soucet();
   4:  
   5:     soucet.A = new Soucin(A.Derivace(), B.Kopie());
   6:     soucet.B = new Soucin(A.Kopie(), B.Derivace());
   7:  
   8:     Podil podil = new Podil();
   9:  
  10:     podil.A = soucet;
  11:     podil.B = new Soucin(B.Kopie(), B.Kopie());
  12:  
  13:     return podil;
  14: }

Zkusme si, jak nám to derivuje.


   1: static void Main(string[] args)
   2: {
   3:     Konstanta a = new Konstanta(10);
   4:     Konstanta b = new Konstanta(20);
   5:  
   6:     Promenna x = new Promenna(“x”);
   7:     Promenna y = new Promenna(“y”);
   8:  
   9:     Soucet soucet = new Soucet(a, x);
  10:     Soucin soucin = new Soucin(b, y);
  11:  
  12:     Rozdil rozdil = new Rozdil(soucet, soucin);
  13:  
  14:     Console.WriteLine(“Před derivací: {0}”, rozdil.ToString());
  15:     Console.WriteLine(“Po derivaci: {0}”, rozdil.Derivace().ToString());
  16:  
  17:     Console.Read();
  18:  
  19:     /
  20:     Výstup z programu:
  21:     
  22:     Před derivací: ((10 + x) - (20  y))
  23:     Po derivaci: ((0 + 1) - ((0  y) + (20  1)))
  24:     */
  25: }

Funguje, derivuje nám to správně. Co nám teď zbývá? Substituce proměnné a zjednodušování výrazů. Koukneme se nejprve na substituci proměnné, to bude jednodušší.

OOP prakticky: Úvod

Tento článek není určen pro každého. Měli byste již mít základní představu o tom, co to objekty jsou a znát jejich přibližnou syntaxi v některém z běžných objektových jazyků (C#, Java, C++, stačí i PHP). Stejně tak byste už měli umět programovat, nečekejte, že vám budu vysvětlovat, jak funguje cyklus. Typický čtenář tohoto článku by měl být programátor, který se zrovna pustil do objektů, jakž takž pochopil syntaxi OOP, tuší, že existují nějaké private či public metody, chápe rozdíl mezi třídou a objektem, ale zcela mu uniká smysl OOP; zpravidla si myslí, že objekty jsou pouze zesložitění normálního programování bez žádného přínosu.

V tomto článku opravdu nebudu popisovat syntaxi OOP, článek by měl být maximálně nezávislý na použitém jazyku. Přesto použité ukázky v nějakém programovacím jazyku být musí, to dá rozum. V pseudokódu se mi to psát nechce, výsledek by byl podobný, jak kdybych zvolil nějaký běžně používaný jazyk, akorát pseudokód by si nezkompiloval vůbec nikdo. Po krátkém váhání jsem tedy zvolil C#, protože je to můj oblíbený jazyk a OOP je tam docela čitelné a jasné. Buďte rádi, že vám příklady neukazuju třeba v Lispu ;-). Pokud zrovna C# neovládáte, nebojte se, syntaxe není nijak zásadně odlišná od vašeho oblíbené jazyku, pokud zrovna nepoužíváte nějaký exotičtější jazyky. Lispaři prominou, ti se holt budou muset při čtení zdrojáků trochu víc snažit :-).

Co se v článku dovíte

V průběhu celého článku si sestavíme malou matematickou aplikaci, která bude trochu podobná kalkulačce. Tento program by měl po dokončení být schopen provádět některé jednodušší matematické úkony jako je třeba dosazení hodnoty za proměnnou, zjednodušení daného výrazu nebo třeba derivace výrazu. Celý program bude ryze objektový, aplikace budeme budovat zespoda (bottom-up) a postupně budu vysvětlovat zásadní vlastnosti OOP. Dovíte se tak, proč je výhodné na některé typy úloh používat objekty, co je to zapouzdřenost, dědičnost a polymorfismus. Všechny tyto základní kameny zároveň chytře aplikujeme na naši kalkulačku. Dost bylo planých řečí, jdeme na programování.

Co bude náš matematický editor umět

V prvé řadě bychom si měli stanovit nějaké cíle, abychom věděli, co vlastně programujeme. Naše aplikace by měla být schopna uchovávat v nějaké formě určitý matematický výraz. Pro jednoduchost předpokládejme, že by program měl být schopen rozpoznávat tyto základní matematické prvky: konstanty, proměnné, binární výrazy (třeba součet dvou čísel, či rozdíl…) a funkce. To by mohlo stačit. Dále by aplikace měla mít tyto prostředky:

  • Zjednodušení celého výrazu: Implementace může být jednoduchá – například pokud je v součinu alespoň jedna nulová konstanta, jednoduše výraz zjednodušíme na nulu, nebo může být sofistikovaná – může například převádět zlomky do základního tvaru. V článku popíši jen jednoduchou verzi, ale klidně si metody vylepšete dle libosti.
  • Dosazení hodnoty do proměnné: Aplikace by měla být schopna do výrazu „x + 5“ dosadit za proměnnou x třeba desítku a vrátit tak výraz „10 + 5“. Nemusíme se přitom držet pouze dosazování konstant, ale můžeme dosazovat klidně další výrazy.
  • Derivování: Každý námi definovaný matematický výraz by měl být schopen vrátit svou derivaci. Pokud nevíte co je to derivace, nezoufejte. Je to vcelku triviální operace, která se řídí jednoduchými vzorci. Dokud se budeme držet jednoduchých matematických výrazů (sčítání, násobení, …), bude i derivace jednoduchá a bude se opravdu jednat o pouhou aplikace vzorečku. Ty můžete najít třeba na wikipedii.
  • Textová reprezentace výrazu: Každý matematický výraz musí mít určenou svou textovou reprezentaci, abychom si tyto výrazy mohli jednoduše vypisovat do konzole, případně někam jinam.

OOP prakticky: Zapouzdřenost

V tuto chvíli navrhujeme třídu Proměnná. Co musí třída obsahovat? Tak předně nějaký slot pro ukládání názvu proměnné, to je jasné jako facka v pravé poledne. Ještě něco? Asi ne, to by mohlo stačit. Substituci vyřešíme později. Takže nejprve vytvoříme třídu, která bude obsahovat slot pro uchování názvu proměnné. to bude obyčejný String:

1
2
3
4
5
6
7
8
9
10
{
public string Nazev;
public Promenna() { }

public Promenna(string Nazev)
{
this.Nazev = Nazev;
}

}

Připíšeme metodu ToString(), která bude prostě vracet Nazev, nic víc. Pokud se proměnná jmenuje „x1“, asi budeme chtít ve výpisu vidět „x1“.

1
2
3
4
public override string ToString()
{
return Nazev;
}

Opět vyzkoušíme:

1
2
3
4
5
6
7
8
static void Main(string[] args)
{
Promenna x1 = new Promenna("x1");
Promenna x2 = new Promenna("x2");
Console.WriteLine("{0}, {1}", x1, x2);
//Výpis bude: x1, x2
Console.Read();
}

Kdo našel chybu? Pokud si někdo všiml jisté nedokonalosti implementace této třídy, má bod. Pro ty méně bystré: my nikde nekontrolujeme, jaký má ta proměnná název. A už jste někdy viděli třeba proměnnou „123456“? Asi ne, protože není moc zvykem, aby se proměnná skládala jen z čísel či aby vůbec začínala číslem. Proto bychom se měli nějak postarat o to, aby se do Názvu uložila jen platná hodnota, což může být například jen slovo, které začíná písmenem a následují opět písmena nebo i čísla. Tedy aby vyhovovaly názvy jako „x1“, „sila10“ nebo jen „rychlost“, ale aby už nevyhověly názvy typu „12x“ nebo „666“. To samozřejmě zařídit lze.

Vzpomínáte si na privátní metody/vlastnosti? Privátní vlastnost je ta vlastnost, která může být modifikována pouze z vnitřku třídy, nikoli zvenčí, pomocí instance. Pokud si vytvoříme instanci pomocí klíčového slova new, nemůže již přes tuto instanci přistupovat k privátním vlastnostem. Ukázka to jistí:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// Ukázková třída s private a public vlastností

class Ukazka
{
public int verejnaVlastnost;
private int privatniVlastnost;
public void setPriv(int cislo)
{
privatniVlastnost = cislo;
}

public int getPriv()
{
return privatniVlastnost;
}
}

class Program
{
static void Main(string[] args)
{
Ukazka ukazka = new Ukazka();

// To je v pořádku, verejnaVlastnost je public
ukazka.verejnaVlastnost = 10;

// Kompilátor vyhodí chybu,
// privatniVlastnost je private, nemůžeme
// k ní přistupovat přes instanci.
ukazka.privatniVlastnost = 20;

// To už je OK, k samotné privátní vlastnosti
// přistupuje vnitřní metoda, která k tomu
// má opravávnění.
ukazka.setPriv(10);

Console.Read();
}
}

Vidíme, že jsme schopni schovat určité vlastnosti tak, aby nebyly přístupné zvenčí tím, že je označíme za private. Nastavování a čtení z této proměnné můžeme udělat pomocí přídavných metod, v našem případě getPriv() a setPriv(). A tady už vidíme postup, jak docílit toho, abychom ve třídě Proměnná před uložením hodnoty zkontrolovali, jestli je daný Název platný. Samotnou vlastnost Název necháme private a sepíšeme si obslužné metody. Přesněji řečeno využijeme vymoženosti C#, který nám dovoluje napsat si vlastní get a set bloky k vlastnostem. Ostatní jazyky mají většinou něco podobného, takže by vás to nemělo nijak překvapit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private string _Nazev;
public string Nazev
{
get { return _Nazev; }
set
{
if(platnaPromenna(value))
_Nazev = value;
else
throw new Exception("Neplatný název proměnné.");
}
}

public static bool platnaPromenna(string Nazev)

{

Regex re = new Regex(@"^\[a-zA-Z\]\[a-zA-Z0-9\]\*$");

return re.IsMatch(Nazev);

}

Ještě jednou přesně popíši, co se bude dít, když se pokusíme do Názvu něco uložit. Jako první se zavolá set blok, ve kterém ověříme, jestli daný Název odpovídá regulárnímu výrazu (ten – jak doufám :-) – ověřuje, jestli daný String začíná písmenem a pak je tvořen jen písmeny nebo čísly. Pokud tomuto reguláru odpovídá, uloží do proměnné _Nazev předanou hodnotu. V opačném případě vyvoláme výjimku, že se snažíme vytvořit nesmyslnou proměnnou. Hezké, ne?

A teď se zkusme zamyslet, čeho jsme vlastně dosáhli a proč bylo nutné toto dělat. Pokud jsme napsali správné sety a gety, můžeme si být jisti, že se objekt nikdy nedostane do nějakého pofiderního stavu. Ať se budeme snažit sebevíc, nikdy se nám nepovede změnit objekt tak, aby byl nějak nesmyslný. A to je fajn, ne? To je přesně zapouzdřenost. Zapouzdřenost objektu tedy není nic jiného, než důsledná kontrola vstupů a výstupů a obecně celkového stavu objektu. Dodržíme-li pravidla zapouzdřenosti, budeme moci snadněji odlaďovat celý program. Pokud máme chybu v nějaké jiné třídě a ta se bude pokoušet vytvářet proměnnou „111“, okamžitě přijdeme na to, že se někde stala chyba. Typický příklad zapouzdřenosti může být u objektu, který má reprezentovat datum. Představte si, že by vám takový objekt dovolil přiřadit jako číslo měsíce 67. To by asi nebylo moc hezké, že ne? Takovou třídu je ideální vyhodit woknem až do koše. Správně zapouzdřená třída pro datum musí samozřejmě kontrolovat, zda vložené vstupy odpovídají logice našich datumů (já vím, píše se správně dat, ale ono se to pak plete s daty třeba v počítači). Ve chvíli, kdy třída nebude pořádně zapouzdřená, budete nuceni při objevení chyby prohledávat všechny třídy a kontrolovat, kde se vlastně stala chyba. Při správném zapouzdření se okruh hledání značně zúží.

Teď už máme naši třídu Proměnná zčásti hotovou. Umí vrátit svou textovou reprezentaci a je odolná vůči neplatným vstupům. To by nám pro tuto chvíli mohlo stačit. Pojďme se podívat na druhý klíč OOP:

OOP prakticky: Dědičnost

Přestože považuji dědičnost za více méně jasnou záležitost, spousta programátorů má s tímto pojmem problémy a občas se divím, co všechno jsou programátoři schopni podědit :-). Ale zpět k matematice. Nyní jsou na řadě binární operace: sčítání, odečítání, násobení a dělení. Jak budeme reprezentovat tyto operace? Inu, zase jako objekty. Budou to třídy, které budou obsahovat dva sloty: „A“ a „B“. Blbé pojmenování, co? Ono kromě dělení, kde můžeme použít čitatel a jmenovatel, se ty výrazy nijak dobře a jednotně nejmenují, takže zůstaneme u tohohle. Slot „A“ bude reprezentovat první výraz, slot „B“ bude reprezentovat druhý výraz. Easy. Jednoduchá verze součtu a rozdílu by mohla vypadat takto:

1
2
3
4
5
6
7
8
9
10
11
{
public Promenna A;
public Promenna B;
}


class Rozdil
{
public Promenna A;
public Promenna B;
}

Bystré (a snad i méně bystré) oko čtenářovo si jistě všimlo, že tyto dvě třídy jsou dosti nesmyslné a… celkově podivné. Jistě vás napadla otázka „proč jsou vlastnosti A a B zrovna typu Proměnná?“ či „jak tam dostanu Konstantu?“ Otázky jsou to správné, protože takhle definované třídy jsou nesmyslné. Ještě bystřejší mysl by se mohla zeptat, jestli není nešikovné, že v každé třídě definujeme tytéž vlastnosti. A v součinu a podílu je jistě budeme definovat taktéž. Hmm, s tím by chtělo něco udělat.

Potřebovali bychom nějaký mechanismus, kterým bychom kompilátoru řekli, že do těch slotů A a B můžeme uložit libovolný matematický výraz. Ať už ty, co jsme vytvořili doposud, nebo ty, které vytvoříme v budoucnu. Chtělo by to nějaký prostředek, kterým označíme všechny naše třídy za matematické výrazy a pak jako typ proměnné A a B uvedeme právě tento matematický výraz. A přesně k tomuto slouží dědičnost. Vytvoříme si novou třídu, kterou nazveme „Vyraz“ (či „MatematickyVyraz“). Tato třída bude reprezentovat předka všech dalších tříd, které vytvoříme. A všechny třídy, které jsme vytvořili, budou z této abstraktní třídy dědit. Tím všechny naše třídy označíme za Matematické výrazy a tento typ pak můžeme normálně používat jako vestavěné typy (Integer, String). Nejprve vytvoříme novou třídu MatematickyVyraz a pak upravíme všechny stávající třídy tak, aby z této třídy dědily (v C# se to dělá pomocí dvojtečky):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
abstract class MatematickyVyraz
{

}

class Konstanta : MatematickyVyraz
{
...
}

class Promenna : MatematickyVyraz
{
...
}

Klíčové slovo abstract znamená, že z třídy nepůjde vytvořit instance. Je to vcelku rozumné omezení, asi není moc pravděpodobné, že bychom někdy potřebovali instanci obecného Matematického Výrazu. Nyní můžeme předchozí třídy součtu a rozdílu upravit takto:

1
2
3
4
5
6
7
8
9
10
11
class Soucet : MatematickyVyraz
{
public MatematickyVyraz A;
public MatematickyVyraz B;
}

class Rozdil : MatematickyVyraz
{
public MatematickyVyraz A;
public MatematickyVyraz B;
}

Teď už jsme docílili toho, aby ve slotech A a B mohl být libovolný Matematický Výraz. Vzhledem k tomu, že samotné třídy součet a Rozdíl dědí z Matematického Výrazu, tak jeden objekt Součet v sobě může obsahovat další objekt Součet, tudíž již můžeme vytvořit nekonečnou posloupnost součtů a rozdílů. Jeden z konečných případů by mohl vypadat takto: (1 + (2 + (3 – 4))). Ještě jsme ale nevyřešili duplikování stejného kódu. Vidíme, že ve třídách se opakují vždy dva stejné řádky. To by chtělo nějak změnit.

Rodičovské třídy mohou klidně obsahovat i nějaké vlastnosti či metody, nemusí to být pouze prázdná třída. Tyto metody a vlastnosti poté zdědí i ostatní třídy. Pokud tedy definujeme v třídě Matematický Výraz sloty A a B, nemusíme je již definovat v Součtu a Rozdílu, a přesto je tam uvidíme a můžeme s nimi pracovat. Můžete si to představit tak, jako že se do třídy Součtu „nakopírují“ všechny metody a vlastnosti z rodičovské třídy Matematický výraz. To by nám trochu ulehčilo práci, kdybychom nemuseli pořád vypisovat tytéž vlastnosti, ne?

Stop! Kdo si myslí, že dané řešení je špatné, má bod. Bylo by sice hezké, kdybychom si ušetřili trochu práce, ale za jakou cenu? Z třídy Matematický Výraz dědí třeba i Konstanta. Má mít Konstanta dva sloty A a B? K čemu by to bylo dobré? Má tedy libovolný Matematický Výraz mít dva sloty? Určitě ne. Ve třídě Matematický Výraz by se měly vyskytovat vlastnosti či metody, které má mít opravdu každý Matematický Výraz. To dva sloty A a B určitě nejsou. Takže jak z toho ven?

Dědičnost samozřejmě nemusí být pouze jedna, třída A může dědit z třídy B a ta může dědit z třídy C a ta může blabla… Třídy Součet a rozdíl jsou zcela zřejmě binární operace, tak co takhle vytvořit další abstraktní třídu, kterou nazveme Binární Výraz, která bude dědit z Matematický Výraz a která bude obsahovat právě ty dva sloty, o které nám jde? Součet a Součin již pak bude pouze dědit z této třídy. Binární výrazy budou mít své dva sloty a Konstanta nebude mít dva zbytečné sloty navíc. Koza se nažrala a vlk zůstal celý. Třídy upravíme takto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
abstract class BinarniVyraz : MatematickyVyraz
{
public MatematickyVyraz A;
public MatematickyVyraz B;
}

class Soucet : BinarniVyraz
{

}

class Rozdil : BinarniVyraz
{

}

Teď přijde na řadu metoda ToString(). Zde opět využijeme dědění. Samozřejmě bychom mohli nadefinovat v každé třídě metodu ToString() zvlášť a celou, ale jednodušší bude, když se podíváme, jak chceme, aby ty binární výrazy vypadaly. Vždy to bude něco v takovémto tvaru: (a + 2), (4 – 8), (fronta * helma). Na prvním místě reprezentace A, pak mezera, pak specifický operátor, pak mezera, pak reprezentace B. To by šlo zjednodušit tak, že si napíšeme metodu, která bude brát jeden argument – ten bude představovat právě onen prostřední operátor. Metoda ToString() pak bude tuto metodu volat, v každé třídě pak pouze předá jiný argument, jednou plus, jinde minus. Tato kouzelná metoda bude poté umístěna právě ve třídě Binární Výraz, protože tato metoda se nebude měnit a budou ji potřebovat všechny Binární Výrazy. Implementace:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
abstract class BinarniVyraz : MatematickyVyraz
{
public MatematickyVyraz A;
public MatematickyVyraz B;

protected string ToBinaryString(string Znamenko)
{
return String.Format("({0} {1} {2})", A.ToString(), Znamenko, B.ToString());

}

}

class Soucet : BinarniVyraz
{
public override string ToString()
{
return ToBinaryString("+");
}

}

class Rozdil : BinarniVyraz
{
public override string ToString()
{
return ToBinaryString("-");
}
}

Klíčové slovo protected je takový kompromis mezi private a public. Public metody jsou vidět odkudkoliv a private zase odnikud, ani ze zděděné třídy. Protected zajistí, že metoda nebude vidět zvenčí jako public, ale bude vidět ve zděděných třídách, na rozdíl od private metod.

A teď pár obecných chytrých rad k dědičnosti: nevyužívejte dědičnost při každé příležitosti, kdy mají dva objekty něco společného. Využívejte dědičnost jen v případě, kdy je to logické. Pokud máme třídy Dítě a Rodič (Dítě dědí z Rodiče, zápis v C#: Dítě : Rodič), pak Dítě musí být vždy speciální případ Rodiče. Dítě musí být podmnožinou Rodiče. Například Obdélník je specifický případ Geometrického útvaru. Stejně tak Bod se specifický případ Geometrického objektu. A podmnožinou Geometrického útvaru je jak Obdélník, tak Bod. Pokud programujete nějakou hru, můžete mít abstraktní třídu Hráč a další dvě třídy, které dědí z Hráče: Lidský Hráč a Počítačový Hráč. Vždy musí platit, že pokud v některé funkci vyhovuje Rodič, musí funkci stačit, i když dostane Dítě. Pokud v naší kalkulačce něco předpokládá na vstupu Binární Výraz, musí se spokojit s jakýmkoliv Binárním Výrazem, tj. jak se Součtem tak i s Rozdílem či Podílem. Pokud metoda očekává na vstupu Hráče, tak funkce musí dávat smysl, ať už předáme Lidského Hráče nebo Počítačového.

Co nemá smysl: ve třídě Obdélník definujeme metodu obsah. Nyní definujeme třídu Kružnice. Uvědomíme si, že Kružnice má také obsah, tak ji jako předka dáme Obdélník, tedy Kružnice : Obdélník. Zřejmě je to ale nesmysl, Kružnice není specifický případ Obdélníku. A později se nám to vymstí. V Obdélníku můžeme definovat metodu na výpočet délky úhlopříčky, kterou Kružnice samozřejmě zdědí. Jak implementujeme výpočet úhlopříčky v Kružnici? No nijak, je to evidentní nesmysl, protože už to dědění bylo chujové. Možným řešením je vytvořit nějakou jinou třídu, která bude reprezentovat Geometrické útvary, které mohou mít obsah, tj. zabírají nějakou plochu. Chujové by taky bylo, kdybyste zdědili z Hráče třeba Zákazníka, protože Hráč i Zákazník mají své jméno nebo podobnou blbost. Že mají dva objekty některé společné vlastnosti ještě neznamená, že mají být v nějakém dědičném vztahu. Radiátor i člověk mohou mít nějakou teplotu – mají snad být v dědičném vztahu…?

Často se dává příklad s autem a volantem. Má být auto rodič a volant potomek? Samozřejmě, že ne. Volant není specifický případ auta. Potomkem auta může být třeba Audi nebo Škoda, ale ne volant ani pneumatiky. Pneumatiky sice s autem souvisí, ale jinak. Auto obsahuje volant, auto volant. To je všechno pravda, ale dědičnost tam nemá co dělat. Auto má obsahovat slot, ve kterém bude uložena instance volantu. Rozhodně nedědit!

To by nám prozatím mohlo u binárních výrazů stačit. Třídy pro Součin a Podíl zde teď uvádět nebudu, protože je to na chlup stejné jako definice Součtu a Rozdílu. Snad jen s tím rozdílem, že při zapouzdřování podílu musíte dát pozor, abyste nedělili nulou (tedy vlastnost B musí být různá od nuly). Vrhněme se na poslední základní pilíř OOP:

Bojkotovali jste olympiádu?


Pokud jste bojkotovali olympiádu v Pekingu z důvodů porušování lidských práv v Číně a především tedy Tibetu, tak by mě zajímalo, co jste tím získali nebo komu si myslíte, že jste tím pomohli?

Já jsem toho názoru, že nesledováním olympiády lautr nikomu nepomůžete, situace v Číně se vlivem vašeho nedívání rozhodně nezmění a vaše úsilí se mi tak jeví jako naprosto zbytečné. Pouze jste se připravili o možnost sledovat olympiádu – tedy pokud jste o tuto možnost stáli. Setkávám se totiž s lidmi, kteří letos bojkotovali olympiádu, protože Tibet a loni ji bojkotovali, protože tam nejde o sport a předtím proto, že bla bla bla. Takže ti z vás, kteří normálně olympiádu sledují, ale tuhle schválně kvůli Tibetu vynechali: Co jste tím získali?