Amazon Web Services (AWS) oznámil (en) výstavbu Fastnetu – strategického transatlantického optického kabelu, který propojí americký stát Maryland s irským hrabstvím Cork a zajistí rychlý a spolehlivý přenos cloudových služeb a AI přes Atlantik. Fastnet je odpovědí na rostoucí poptávku po rychlém a spolehlivém přenosu dat mezi kontinenty. Systém byl navržen s ohledem na rostoucí provoz související s rozvojem umělé inteligence a
… více »Evropská komise zkoumá možnosti, jak přinutit členské státy Evropské unie, aby ze svých telekomunikačních sítí postupně vyloučily čínské dodavatele Huawei a ZTE. Místopředsedkyně EK Henna Virkkunenová chce změnit doporučení nepoužívat rizikové dodavatele při budování mobilních sítí z roku 2020 v právně závazný požadavek.
sudo-rs, tj. sudo a su přepsané do programovacího jazyka Rust, již obsaženo v Ubuntu 25.10, bylo vydáno ve verzi 0.2.10. Opraveny jsou 2 bezpečnostní chyby.
Kaspersky pro Linux je nově k dispozici také pro domácí uživatele.
Společnost Avalonia UI oznámila, že pracuje na .NET MAUI pro Linux a webový prohlížeč. Vyzkoušet lze demo v prohlížeči. Když bude backend stabilní, bude vydán jako open source pod licencí MIT.
Byl vydán Mozilla Firefox 145.0. Přehled novinek v poznámkách k vydání a poznámkách k vydání pro vývojáře. Ukončena byla podpora 32bitového Firefoxu pro Linux. Přidána byla podpora Matrosky. Řešeny jsou rovněž bezpečnostní chyby. Nový Firefox 145 bude brzy k dispozici také na Flathubu a Snapcraftu.
Lidé.cz (Wikipedie) jsou zpět jako sociální síť s "ambicí stát se místem pro kultivované debaty a bezpečným online prostředím".
Byla vydána nová verze 4.4 multiplatformního integrovaného vývojového prostředí (IDE) pro rychlý vývoj aplikaci (RAD) ve Free Pascalu Lazarus (Wikipedie). Využíván je Free Pascal Compiler (FPC) 3.2.2.
ASUS má v nabídce komplexní řešení pro vývoj a nasazení AI: kompaktní stolní AI superpočítač ASUS Ascent GX10 poháněný superčipem NVIDIA GB10 Grace Blackwell a platformou NVIDIA DGX Spark. S operačním systémem NVIDIA DGX založeném na Ubuntu.
Desktopové prostredie Trinity Desktop vyšlo vo verzii R14.1.5. Je tu opravená chyba v tqt komponente spôsobujúca 100% vyťaženie cpu, dlaždice pre viac monitorov a nemenej dôležité su dizajnové zmeny v podobe ikon, pozadí atď. Pridaná bola podpora distribúcií Debian Trixie, Ubuntu Questing, RHEL 10 a OpenSUSE Leap 16.
1. Metody, alias funkce
2. Třídy
2.1 Objektově orientovaný přístup
2.2 Definice tříd
2.3 Proměnné instance, inicializace
2.4 Přístupové metody
2.5 Řízení přístupu
2.6 Dědičnost
2.7 Proměnné třídy
Společně s tím, jak náš kód poroste, si brzy začneme všímat určitých úseků, které se budou v našem programu až příliš často opakovat. Zcela zjednodušeně, vytváříme-li například matematickou aplikaci, tak takové věci, jako je výpočet faktoriálu nebo třeba obvodu kruhu, využijeme poměrně často.
Dokola opisovat stále tentýž kód je nejen únavné, ale především nepraktické. Vymyslíme-li totiž v budoucnu efektivnější algoritmus nebo nedej bože zjistíme, že v něm máme chybu, budeme v důsledku odsouzeni k tomu důkladně projít celý zdrojový kód, který může čítat i desetitisíce řádků.
Moderní programovací jazyky (a Ruby není výjimkou) za tímto účelem nabízejí použití tzv. funkcí, kterým se v případě objektových jazyků říká metody. Obecný zápis definice metody vypadá takto:
def název(parametr_1, parametr_2, …) příkazy return návratová_hodnota end
Konvence říká, že názvy metod začínají malým písmenem. Definice se
uvozuje klíčovým slovem def, v závorce následuje výčet
proměnných, jejichž prostřednictvím budou metodě předány hodnoty, vzájemně oddělené čárkou. V těle metody je zapsán samotný kód, za klíčovým slovem
return je uvedena návratová hodnota. Definici uzavírá klíčové
slovo end.
Ačkoli se metody obvykle uvádějí v definici tříd, jak si ostatně zanedlouho ukážeme, lze je uvádět i samostatně jako klasické funkce v procedurálních jazycích. V souboru se pak jejich definice zapisují před samotným kódem.
Pozapomeňme na chvíli na existenci vhodnější Math.sqrt() a
zkusme si napsat metodu na výpočet druhé odmocniny ze zadaného čísla sami.
Ta by mohla vypadat například takto:
irb(main):001:0> def odmocnina(cislo) irb(main):002:1> return cislo**(1.0/2) irb(main):003:1> end => nil
K uvedení do chodu je třeba metodu odněkud z programu zavolat:
irb(main):004:0> odmocnina(256) => 16.0
Metody jsou volány svým jménem. V závorce jsou jim předány hodnoty,
které jsou následně přiřazeny lokálním proměnným v jejich těle – v
našem případě tedy platí, že cislo = 256.
Jelikož metoda vrací hodnotu, lze ji postavit na pravou stranu přiřazení:
irb(main):005:0> vysledek = odmocnina(16) => 4.0 irb(main):006:0> puts vysledek 4.0 => nil
Pojďme si naši definici trochu rozšířit; řekněme, že chceme mít možnost počítat libovolnou odmocninu, nejen druhou. Toho zcela intuitivně docílíme přidáním druhého parametru. Zároveň by se nám ale líbilo, abychom tento parametr nemuseli uvádět v případě, že nám druhá odmocnina stačí. Jak na to?
Návrháři programovacích jazyků si lenost programátorů dobře uvědomují, a tak Ruby umožňuje v definici specifikovat implicitní hodnoty:
irb(main):007:0> def odmocnina(cislo, exponent=2) irb(main):008:1> return cislo**(1.0/exponent) irb(main):009:1> end => nil irb(main):010:0> odmocnina(16, 4) => 2.0 irb(main):011:0> odmocnina(16) => 4.0
Parametry s implicitními hodnotami musí být v definici vždy vpravo a
nelze je prokládat, jinak by nebylo možné zajistit správné přiřazení.
Definice def pitomost(x=4, y, z=2) je tedy nesmyslná a
chybná.
Rekurze je možnost volat metodu z ní samotné a je silným nástrojem funkcionálních jazyků. V Ruby je nicméně možná také:
irb(main):012:0> def faktorial(n) irb(main):013:1> if n == 0 irb(main):014:2> return 1 irb(main):015:2> else irb(main):016:2* return n * faktorial(n - 1) irb(main):017:2> end irb(main):018:1> end => nil
Algoritmus slouží k výpočtu faktoriálu daného čísla. Je-li hodnota n nenulová, vynásobí se výsledkem volání metody s hodnotou n - 1. Je-li nulová, dojde k navrácení čísla 1 a rozvoj je ukončen. Tímto způsobem tak dosáhneme zcela intuitivního výpočtu, např. 6! = 6 * 5 * 4 * 3 * 2 * 1 = 720. Že to opravdu funguje ověříme snadno:
irb(main):019:0> faktorial(6) => 720
S rekurzí je nicméně třeba nakládat obezřetně, některé výpočty totiž mohou být značně paměťově náročné.
Pro úplnost ještě uvedu, že v definici metod lze vynechat také klíčové
slovo return a psát tak např. jen:
def odmocnina(cislo) cislo**(1.0/2) end
Osobně však doporučuji se tomuto zkrácení pokud možno vyhnout, k přehlednosti totiž rozhodně nepřispívá.
Než přejdeme k vysvětlení samotné práce s třídami a objekty, bylo by více než vhodné si na tomto místě povědět, co to objektově orientované programování (OOP) vlastně je. Vzhledem k zaměření a rozsahu tohoto seriálu není možné se do detailů věnovat všem jeho aspektům a ani se o to nebudu pokoušet. Existují povolanější a podstatně obsáhlejší zdroje, které se touto problematikou zabývají, a myslíte-li to s programováním vážně, vřele doporučuji si je do budoucnosti prostudovat.
Máte-li už s programováním nějaké předchozí zkušenosti a objektově orientovaný přístup znáte, můžete následující odstavce bez obav přeskočit a přejít rovnou k podkapitole 2.2 Definice tříd.
S rozvojem výpočetní techniky se vyvíjely také programovací jazyky, a to především směrem k větší srozumitelnosti. Současně s nimi se měnily také přístupy ke psaní počítačových programů.
Poměrně dlouhou dobu bylo (a dodnes je) uznávaným modelem tzv. procedurální programování. Program sestává z dat, která jsou uchovávána prostřednictvím proměnných, a procedur, které s těmito daty pracují. Přístup rozdělení jednotlivých ucelených úkonů do samostatných procedur je poměrně efektivní a nepochybně umožnil rozvoj i velmi složitých aplikací (linuxové jádro je celé napsáno v procedurálním jazyce C). Typicky procedurálním jazykem je např. Pascal.
Objektově orientovaný přístup se snaží ještě více přiblížit strukturu programu lidskému myšlení a vnímání reálného světa. Člověk o okolním světě (většinou) neuvažuje jako o sadě proměnných a procedur, ale jako o objektech. Tento přístup umožňuje nejen o problémech přemýšlet a pojímat je jako reálné věci, ale také objekty z jednotlivých objektů skládat, ba dokonce vlastnosti dědit. Díky přístupovým metodám je pak možné ochránit data před nechtěným přepsáním a vnitřní implementace skrýt.
Pokud si některá tvrzení z předchozího odstavce nedokážete představit, pusťte je z hlavy. Vše si názorně ukážeme v následujících kapitolách.
Stejně jako je Aris pes a já jsem člověk, tak i jednotlivé objekty jsou
vždy konkrétními instancemi nějaké třídy. Třída samotná se skládá z
proměnných a metod a její definice je uvozena klíčovým slovem
class. Konvencí je začínat názvy tříd velkým písmenem:
irb(main):020:0> class Pes irb(main):021:1> def zastekej irb(main):022:2> puts "Haf, haf!" irb(main):023:2> end irb(main):024:1> end => nil
Konkrétní instanci vytvoříme prostřednictvím metody
new:
irb(main):025:0> aris = Pes.new => #<Pes:0xb7d1308c>
Nyní již můžeme s nově vytvořenou instancí pracovat:
irb(main):026:0> aris.zastekej Haf, haf! => nil
Ponechme prosím stranou absenci jakékoli užitečnosti takovéto třídy. Mějte na paměti, že jde pouze o jednoduchou ukázku na vysvětlení základních principů; postupy zde naučené lze stejně tak dobře aplikovat na komplikované algoritmické úlohy, v rámci přístupnosti a srozumitelnosti se však spokojíme s jednodušší variantou.
Dosud jsme si ukázali, jak definovat metody třídy. K uchovávání hodnot v
rámci jedné instance slouží tzv. proměnné instance a jsou to lokální
proměnné společné všem jejím metodám. Od běžných proměnných se liší tím, že
jejich názvy začínají znakem @:
rb(main):027:0> class Pes
irb(main):028:1> def initialize(jmeno, rasa)
irb(main):029:2> @jmeno = jmeno
irb(main):030:2> @rasa = rasa
irb(main):031:2> end
irb(main):032:1> def info
irb(main):033:2> return "#{@jmeno} je #{@rasa}."
irb(main):034:2> end
irb(main):035:1> end
=> nil
Nadefinovali jsme si dvě proměnné instance (@jmeno a
@rasa) a dvě metody (initialize a
info).
initialize je standardní název pro tzv. inicializační
metodu, která umožňuje předání hodnot instanci už při jejím vytvoření.
Na rozdíl od jiných metod se nevolá přímo, ale prostřednictvím již známé
metody new:
irb(main):036:0> mujPes = Pes.new("Aris", "Border terier")
=> #<Pes:0xb7ca120c @jmeno="Aris", @rasa="Border terier">
Z návratové hodnoty je patrné, že zadané parametry byly skutečně předány
patřičným proměnným instance. Ověřit si to můžeme také zavoláním
muj_pes.info.
Možná vás napadlo, že pomocí tečkové notace by se dal vypsat obsah proměnné instance přímo. Když to ale vyzkoušíme, obdržíme následující chybové hlášení:
irb(main):037:0> mujPes.jmeno
NoMethodError: undefined method `jmeno' for #<Pes:0xb7c9d6fc @jmeno="Aris"
, @rasa="Border terier">
from (irb):37
from :0
O nic úspěšnější nebudeme ani v případě, že zkusíme zadat
mujPes.@jmeno. Toto chování je dalším aspektem objektového
přístupu – k práci s proměnnými slouží příslušné metody, což nejen
výrazně omezuje možné zavlečení chyby, ale zároveň také skrývá vnitřní
postupy.
Používáme-li například modul Math, většinou nás nezajímá,
jak je vnitřně implementován. Co potřebujeme vědět je, jaké prostředky nám
poskytuje a jak se s nimi pracuje. Výhodou tohoto přístupu je také to, že
vnitřní implementace jednotlivých metod pak můžeme měnit bez toho, aby byl
jakkoli zasažen kód, který s danou třídou pracuje.
Definice třídy o obohacená o přístupové metody by tak mohla vypadat např. takto:
irb(main):038:0> class Pes irb(main):039:1> def initialize(jmeno, rasa) irb(main):040:2> @jmeno = jmeno irb(main):041:2> @rasa = rasa irb(main):042:2> end irb(main):043:1> def jmeno irb(main):044:2> return @jmeno irb(main):045:2> end irb(main):046:1> def rasa irb(main):047:2> return @rasa irb(main):048:2> end irb(main):049:1> end => nil
V uvedeném příkladu jsou přístupové metody pojmenovány stejně jako
proměnné instance, což umožňuje intuitivní přístup k nim, někteří
programátoři však upřednostňují pojmenování typu vypisJmeno a
nastavJmeno. Výběr je opět na vás, nicméně vhodné je zůstat v
rámci programu konzistentní.
Výše uvedená definice má jednu nevýhodu: stále nám neumožňuje do
proměnných zapisovat. Abychom zachovali výše zavedený způsob, nadefinujeme
si metodu pro ukládání do proměnné @jmeno následujícím
způsobem:
irb(main):050:0> class Pes irb(main):051:1> def initialize(jmeno, rasa) irb(main):052:2> @jmeno = jmeno irb(main):053:2> @rasa = rasa irb(main):054:2> end irb(main):055:1> def jmeno irb(main):056:2> return @jmeno irb(main):057:2> end irb(main):058:1> def rasa irb(main):059:2> return @rasa irb(main):060:2> end irb(main):061:1> def jmeno=(noveJmeno) irb(main):062:2> @jmeno = noveJmeno irb(main):063:2> end irb(main):064:1> end => nil
Nyní můžeme s proměnnou pracovat, jako bychom k ní měli přímý přístup:
irb(main):065:0> mujPes = Pes.new("Aris", "Border terier")
=> #<Pes:0xb7cd1e0c @rasa="Border terier", @jmeno="Aris">
irb(main):066:0> mujPes.jmeno # puvodni jmeno
=> "Aris"
irb(main):067:0> mujPes.jmeno = "Cassie" # prirazeni
=> "Cassie"
irb(main):068:0> mujPes.jmeno # nove jmeno
=> "Cassie"
Jak vidíte, autor třídy má nad proměnnými plnou kontrolu a je jen na něm, které z nich a do jaké míry zpřístupní. Tato vlastnost má však jeden nepříjemný důsledek – díky přístupovým metodám se i takto triviální definice protáhla na nepříjemně velký počet řádků. Ruby proto nabízí elegantní zkratku:
irb(main):069:0> class Pes irb(main):070:1> def initialize(jmeno, rasa) irb(main):071:2> @jmeno = jmeno irb(main):072:2> @rasa = rasa irb(main):073:2> end irb(main):074:1> attr_reader :jmeno, :rasa irb(main):075:1> attr_writer :jmeno irb(main):076:1> end => nil
Tento příklad je naprostým ekvivalentem předcházejícího. Příkaz
attr_reader vytvoří k vybraným proměnným metody pro čtení a
attr_writer pro zápis. Názvy proměnných přitom začínají
dvojtečkou (nikoli zavináčem!) a jsou od sebe odděleny čárkami.
Už víme, že proměnné instance jsou považovány za soukromé a chceme-li k nim mít přístup „z venčí“, je třeba nadefinovat příslušné metody. To nám umožňuje nejen měnit způsob, jakým je s proměnnými vnitřně nakládáno, ale také rozhodnout, ke kterým proměnným vůbec přístup umožníme.
Ve složitějších třídách často pracujeme s metodami, které jsou volány jinými metodami, zároveň však neočekáváme jejich volání mimo definici třídy. Ruby rozlišuje tři druhy metod:
Pes, mohou si k těmto metodám navzájem přistupovat. Tyto
metody však nejsou dostupné ani z instancí jiných tříd, ani z jiných
částí programu.Které metody jsou jakého druhu můžeme explicitně stanovit
prostřednictvím klíčových slov public, protected
a private:
irb(main):077:0> class Kruh irb(main):078:1> def initialize(polomer) # implicitne verejna irb(main):079:2> @polomer = polomer irb(main):080:2> @PI = 3.14159 irb(main):081:2> end irb(main):082:1> private # nasleduji soukrome irb(main):083:1> def obvod irb(main):084:2> return 2 * @PI * @polomer irb(main):085:2> end irb(main):086:1> def obsah irb(main):087:2> return @PI * @polomer**2 irb(main):088:2> end irb(main):089:1> public # nasleduji verejne irb(main):090:1> def parametry irb(main):091:2> return "polomer:\t" + @polomer.to_s + irb(main):092:2* "\nobvod:\t\t" + obvod.to_s + irb(main):093:2* "\nobsah:\t\t" + obsah.to_s + "\n" irb(main):094:2> end irb(main):095:1> end => nil
Druhou možností je rozlišovat druh metod až v závěru. V našem případě bychom tedy na konec připsali:
public :parametry private :obvod, :obsah
Volba je opět na vás. A že to doopravdy funguje, ověříme snadno:
irb(main):096:0> k = Kruh.new(5)
=> #<Kruh:0xb7ced378 @PI=3.14159, @polomer=5>
irb(main):097:0> puts k.parametry
polomer: 5
obvod: 31.4159
obsah: 78.53975
=> nil
irb(main):098:0> k.obvod
NoMethodError: private method `obvod' called for #<Kruh:0xb7ced378 @PI=3.1
4159, @polomer=5>
from (irb):98
from :0
Může se stát, že nám možnosti určité třídy přestanou dostačovat. Dědičnost je způsob, jak přejmout metody a proměnné původní třídy a umožnit jejich rozšíření bez nutnosti původní třídu opisovat. Toto je obzvláště výhodné také v případě, že vnitřní implementaci původní třídy neznáme.
Zkusme si nadefinovat novou třídu Stene, která je v zásadě
speciálním případem třídy Pes. Štěně je bezpochyby taky pes,
ale na rozdíl od většiny svých slušně vychovaných příbuzných disponuje
jedním nešvarem, a to tím, že rozkouše, na co přijde, obzvláště když mu
rostou zoubky. Definice by potom mohla vypadat nějak takto:
irb(main):099:0> class Stene<Pes
irb(main):100:1> def rozkousej(predmet)
irb(main):101:2> return "#{predmet} je na cucky!"
irb(main):102:2> end
irb(main):103:1> end
=> nil
irb(main):104:0> mujPes = Stene.new("Cassie", "Yorksirsky terier")
=> #<Stene:0xb7cf91b4 @rasa="Yorksirsky terier", @jmeno="Cassie">
irb(main):105:0> mujPes.jmeno
=> "Cassie"
irb(main):106:0> mujPes.rozkousej("Dalkovy ovladac")
=> "Dalkovy ovladac je na cucky!"
Budeme-li chtít třídě přidat nové vlastnosti, pravděpodobně budeme muset
zasáhnout také do metody initialize. Změny chování některé z
děděných metod docílíme její novou definicí, opisovat však celý její obsah
je přinejmenším nepohodlné. Naštěstí lze dědit také obsah přepisované
metody:
irb(main):107:0> class Stene<Pes irb(main):108:1> def initialize(jmeno, rasa, vek) irb(main):109:2> super(jmeno, rasa) irb(main):110:2> @vek = vek irb(main):111:2> end irb(main):112:1> attr_reader :vek irb(main):113:1> attr_writer :vek irb(main):114:1> end => nil
irb(main):115:0> mujPes = Stene.new("Cassie", "Yorksirek", "6 mesicu")
=> #<Stene:0xb7cd9d8c @rasa="Yorksirek", @jmeno="Cassie", @vek="6 mesicu">
irb(main):116:0> mujPes.jmeno
=> "Cassie"
irb(main):117:0> mujPes.vek
=> "6 mesicu"
Vedle proměnných instance nabízí Ruby ještě tzv. proměnné
třídy, které jsou společné všem jejím instancím. Jejich názvy začínají
znaky @@ a uvádí se mimo těla definic metod, zpravidla na
začátku definice třídy před metodou initialize.
V následujícím příkladu si nadefinujeme proměnnou třídy
@@pocet, která bude uchovávat informace o počtu vytvořených
instancí:
irb(main):118:0> class Pes irb(main):119:1> @@pocet = 0 # promenna tridy irb(main):120:1> def initialize irb(main):121:2> @@pocet += 1 # pripocitame novou instanci irb(main):122:2> end irb(main):123:1> def pocet irb(main):124:2> return @@pocet # informace o aktualnim stavu irb(main):125:2> end irb(main):126:1> end => nil
Snadno ověříme, že to skutečně funguje:
irb(main):127:0> prvniPes = Pes.new => #<Pes:0xb7ceac18> irb(main):128:0> prvniPes.pocet => 1 irb(main):129:0> druhyPes = Pes.new => #<Pes:0xb7ce3cd8> irb(main):130:0> prvniPes.pocet => 2
Nástroje: Tisk bez diskuse
Tiskni
Sdílej:
U něj se aspoň dá říct, že je integrovaný do jazyka a poskytuje literály pro snippety.
A abych si ještě rejpnul, "věci okolo" se dají změnit/napsat/předělat pořád ještě snáze, než zprasený jazyk. Takže i když mohou být knihovny důležitější, je mnohem větší průser, když zjistím, že se peru s jazykem. Ona totiž knihovna (třeba pokud je v Cčku) je pro vývojáře v první řadě API a na to se dají udělat bindingy snad do čehokoli.
Jinak řečeno, pro Ruby je v podstatě k dispozici totéž, co pro Python nebo pro Perl. A SWIG to ještě o notný kus srovnává. Pokud jde o platformu, není co řešit - stačí ANSI C kompilátor. A pokud jde o vývojové prostředí, jestli mi sáhneš na Emacs, urazím Ti pazoury.
Ale podotýkám, že rubista jsem jen okrajově, velké aplikace v tom asi dělají jiní zdejší.
Já už si příliš zvykl na luxusní lispí kompilátory. Jen mi prostě přijde, že jakmile se člověk dostane k opravdu velkým věcem, tak programovací jazyk teprve začne být ta nejdůležitější věc.
nejaky velky projekty napsany v RubyZatím nikdo nic extra velkýho neprásknul, ale už jen ve standardní distribuci Ruby by mělo být ~420000 řádků Ruby. To mi přijde celkem dost.
Rails mají momentálně cca. 70000 řádků.
Tedy, mlčky předpokládám, že to je významná metrika, co taky nemusí být vždy pravda.
Je taky otázka, jestli existuje jeden velký monolitický projekt, na kterém by se dalo něco takového ukázat. Rubisté už ze své podstaty nesnášejí molochy typu J2EE, takže k tomu asi ani nemají tendence. (Ani mezi pythonisty zřejmě neplatí, že by kvůli Zope každý slintal.
) Pro mě je největším rubím projektem RubyForge.
ne nejakej web franty fuky
attr_accessor:? Potom se do tý proměnný dá i zapisovat a nemusí se na to dělat extra metody stylem:
class Pes
def initialize(jmeno)
@jmeno = jmeno
end
def name
return #{@jmeno}
end
def setName(jmeno)
@jmeno = jmeno
end
end
Místo toho se použije
class Pes
attr_accessor: jmeno
def initialize(jmeno)
@jmeno = jmeno
end
end
Nehledě na to, že v kombinaci s funkcionálním přístupem (nedestruktivními aktualizacemi - Alan Kay certified(R)
) je to mocný nástroj.
), ale prasata dokážou zprznit cokoliv. A pak takhle nadávají, ačkoliv za jejich problémy OOP ve skutečnosti vůbec nemůže.