---
# System prepended metadata

title: SZZ Programování

---

# SZZ Programování

## [Naše starý repo o prográmku](https://github.com/mpicek/programko)

# OOP pojmy

### Virtualni metoda 
 - ma implementaci, ale muzu ji overridovat (prepsat ji implementaci v potomkovi)
 - napr v jave nebo pythonu jsou vsechny metody virtualni, staticke metody ale virtualni nejsou. V jinych jazycich se virtualni metody definuji jako virtualni pomoci `virtual`

#### Override
 - **prepsani** metody v potomkovi

#### Overload
 - **pretizeni** metody - volani s ruznymi parametry

### Abstraktni metoda
 - nekdy jsem pro ni videl taky nazev "pure virtual" nebo tak neco
 - nema implementaci, musim ji implementovat v potomkovi (tzn. predefinoval jsem ji, je tudiz taky virtualni)

### Abstraktni trida
 - kdyz ma trida alespon jednu abstraktni metodu, tak je cela trida abstraktni
 - kdyz dedim z abstraktni tridy, musim implementovat **vsechny** abstraktni metody!
 - v cpp myslim je abstraktni trida vlastne to samy jako interface, hlavne proto, ze v cpp je vicenasobna dedicnost, takze jakoby "implementuju" vic abstraktnich trid (coz je to samy jako implementace vice interfacu)
	 - v jave ale neni vicenasobna dedicnost, takze muzu dedit jen od jedny tridy (treba i abstraktni), na druhou stranu muzu implementovat interfacu kolik chci :)
		 - jsou tam i jiny dalsi maly rozdily, ze v interfacu je vsechno public, static, final, to v abstraktni tride neni a taak

### Anonymni metoda
 - je to trida, ktera nema jmeno, je pouzita nekde v kodu jen na jednom miste treba

### Typy dedicnosti
 - **jednoducha** (muzu dedit max od jedny tridy) - Java, vicenasobnou dedicnost zaridim pres interface
 - **vicenasobna** - ze muzu dedit od vice trid naraz - C++, Python, muze nastat ale ten diamond problem, kdy zdedim tridu dvakrat


### Polymorfismus
 - k tomu, abych mel treba pole s objekty zvire a do toho mohl ulozit potomky ty tridy (krava, pes, ..)

### Tabulka virtualnich metod
 - v objektu je promenna ukazujici na tuhle tabulku
 - ta tabulka je pole ukazatelu na virtualni funkce
 - je jedna pro kazdou tridu
 - pri volani metody se zavola ta, ktera je v tyhle tabulce ulozena
 - objekt obsahuje odkaz na tuhle tabulku (a tenhle odkaz tam dosadi konstruktor)

### Interface
 - je to takova smlouva - rika se v ni, co bude mit definovano potomek
 - je to jako seznam funkci
 - ty funkce nejsou definovany, je jako popsane rozhrani, ale implementace neni definovana (ale muze byt defaultni treba v jave)
 - je to proto, ze neni nasobna dedicnost
 - muzeme tedy rict, ze prvek splnuje libovolny pocet interfacu a implementovat je v nem



## Práce s prostředky a mechanizmy pro ošetření chyb

### Chyby

Chyby dělíme na:

-   syntaktické (synax error)

    -   špatný zápis podle pravidel programu

    -   hlásí je překladač před spuštěním programu

    -   např. špatné mezery v Pythonu, chybějící složená závorka,
        neexistující typ ...

-   běhové (vyjímky = exception) (runtime error)

    -   nepřípustné operace

    -   ohlásí je program za běhu (až k nim dojde (pokud dojde))

-   sémantické (semantic error)

    -   program vydá nesprávný výsledek, neskončí ...

    -   nejsou hlášeny (musí je kontrolovat uživatel)

Proces odstraňování se nazývá ladění.

### Vyjímky

-   vyjímka (exception) = zpráva o běhové chybě

-   je objekt - typ záleží na programovacím jazyku

    -   Python - vždy potomci třídy BaseException (NameError, TypeError,
        ...)

        -   lze také odvodit vlastní typy

    -   C++ -

    -   C# - vždy potomci System.Exception

-   obsahuje i další informace (text zprávy, místo chyby, celý zásobník
    volání)

#### Ošetření vyjímek

Try-catch (resp. try-except) struktura:

-   v try bloku kontrolujeme zda nastala chyba

-   catch blok ošetřuje specifikovanou vyjímku (může jich být více) -
    provede specifické příkazy pokud nastala vyjímka

-   catch umí odchytit i všechny vyjímky - není to vhodné, chceme pouze
    odchytit chyby, kterým rozumíme (může nastat nečekaná chyba, o které
    bychom se nikdy nedozvěděli)

-   objekt reprezentující chybu lze typicky uložit do proměnné a
    kontrolovat vlastnosti vyjímky (jméno, textový výpis, argumenty,
    zásobník volání)

-   StackTrace - jak vypadal GC zásobník v místě vzniku vyjímky, kde
    vyjímka vznikla

-   používat pouze vyjimečně - drahá operace (musí se uložit informace o
    chybě - poměrně obsáhlé + časově náročné)

Finally:

-   zapisuje se za try-catch, pro vykonání příkazu bez ohledu zda je
    vykonávána část try, nebo catch

-   typicky pokud pracujeme se souboru, tak je chceme zavřít (ve
    finally)

-   problém s tzv. Disponable objekty (a paralelními operacemi)

    -   při práci se zamknou (aby nebyly modifikovány jinými)

    -   např. pokud mám otevřen textový editor, pak soubor nelze otevřít
        jiným programem

    -   typicky se odemkne voláním Dispose (u souboru v rámci Close)

    -   problém pokud nastane vyjímka, tak zůstane soubor zamčen a není
        s ním možno pracovat

    -   odemknout soubor může GC, ale ten zahazuje soubory až pokud je
        velký nárok na pamět (nemusí nastat do ukončení programu)

    -   řešení je použití Dispose ve finally, nebo using (with)
        struktura (je tam Dispose interně)

Vyvolání vyjímky throw (Python - raise):

-   pokud chceme ohlásit výjimečnou situaci, kterou neumíme řešit
    (chceme ukončit program a ohlásit chybu)

-   např. funkce načítající číslo nedostane číslo, server neodpovídá,
    ...

-   přeskočí se zbytek bloku (nedokončená funkce), možná se zastaví
    někde výše (v catch)

Problematická je práce s databázemi, soubory, .... Řešením je použití
struktury try ...finally, nebo using (resp. with) (try ...finally je
implicitně zahrnuto ve struktuře).

#### Druhy vyjímek - C#

-   SystemExceptions - typické bugy (NullReference, IndexOutOfRange),
    nechci odchytávat

-   ArgumentException - chyby uživatele (OutOfRange, NullArgument)

-   OutOfMemoryException

    -   došlo místo na GC haldě

        -   nezbývá místo pro vyskakovací okno

        -   zbývá dostatek místa pro výpis chyby do terminálu

        -   chci co nejrychleji zabít (abych uvolnil místo pro jiné
            programy)

    -   StackOverflowException

        -   došla paměť na zásobníku (oproti GC už nezbývá ani kousek

        -   prostě zabij (není místo na nic)

        -   nastává jednoduše pro vícevláknové programy (paralelní)

        -   nebezpečné v rekurzi - hluboké zanoření, musí si pamatovat i
            nadřazené proměnné funkcí

        -   ve funkcionálních jazycích je to vyřešeno koncovou rekurzí
            (proměnné jsou každým voláním přepisovány (víme, že už
            nadřazenou funkci nebudeme potřebovat))

### Defenzivní programování

-   vhodné předcházet chybám

-   ověřování vstupu (chyby uživatelů) a výstupů (vlastní chyby)

-   testovaní podmínek vstupu a výstupů (invarianty)

-   ověřování situací, které nemohou nastat

-   nízká tolerance (co neznáme, odmítnout)

### Rozdíly v programovacích jazycích

-   rozdíl mezi kompilovanými jazyky a interpretovanými

-   v Pythonu probíhá kontrola typů až za běhu (neodhalí překladač)

    -   ale pomocí externích nástrojů, lze kontrolovat před spuštěním)

            a: int = 5
            b: str = "abcd"
            def delka( slovo: str ) -> int:
            return len(slovo)

    -   kontroluje externí nástroj (Visual Studio, Visual Studion Code,
        PyCharm, ...)

### Testování

-   výpisy pro vývojáře (printy)

-   unit testy - testují jednotlivé části, třídy, funkce

-   integrační testy - spolupráce částí programů

-   regresní testy - zachování funkčnosti programu (jestli se
    aktualizací nerozbil)

-   testy nezávislé na okolí (vše si připraví samy)

-   Test Driven Developement - nejprve napsat testy (postupně je
    splňujeme)

-   

## Životní cyklus objektů a správa paměti

Životnost objektu je charakterizována časem mezi vytvořením objektu a
jeho zničením. Objekt může reálně existovat, ale již nemusí být
přístupný (ještě nebyl přepsán). Rozlišujeme proměnné na:

-   hodnotové

    -   každá proměnná je jiná instance objektu (ne pouze reference na
        objekt)

    -   typicky objekty malých tříd (int, char, struckt (v C#))

    -   např. v C++ jsou všechny proměnné hodnotové (pokud chci
        referenční musím specifikovat)

-   referenční (silná reference)

    -   new - alokace na haldě + konstruktor (v C#)

    -   v proměnné je uložen odkaz na objekt (nekopíruje se celý objekt,
        pokud není řečeno přímo)

    -   typicky větší objekty (string, array, class, ...)

-   pointery (slabá reference)

    -   ukazují libovolně do paměti (nikdo je nekontroluje)

    -   raw pointery v C++ (v C# komplikovanější)

    -   musíme ručně kontrolovat, zda byl objekt zničen (řeší smart
        pointery v C++)

-   tracking reference

    -   v C# jsou to out typy

    -   mohou ukazovat na nedeklarované proměnné, ale překladač
        kontroluje, jestli se používá již inicializovaný objekt

```{=html}
<!-- -->
```
-   mutable - lze měnit jejich hodnotu

-   immutable - nelze upravit hodnotu, při změně hodnoty vzniká nový
    objekt (nově alokován na GC haldě), např. string, vhodné pro
    paralelní programy

    -   problém se častým string concat (vznikají nové objekty), ale
        překladače to mají často vyřešeno efektivně

    -   C# varianta je StringBuilder (muttable string) - pro časté
        úpravy

-   readonly - immutable, ale zakázána také modifikace objektu

### Vznik objektů

-   objekt je alokován na haldě až po zavolání konstruktoru

-   statické parametry mají své vlastní konstruktory - inicializace při
    prvním použitím typu

### Uložení v paměti

// TODO: Obrazek

-   po definici lokální proměnné se uloží na zásobník (stack)

-   po definici objektu třídy jsou jeho proměnné uloženy na haldě

-   statické proměnné jsou uloženy na loader heap (společně se strojovým
    kódem)

### Životnost lokálních objektů

-   proměnná vzniká na začátku bloku (uvnitř složených závorek) a zaniká
    po jeho ukončení

-   životnost můžeme v C# explicitně zkrátit kódem ve složených
    závorkách (navíc)

-   proto můžou být na stacku (vždy první proměnná nahoře je ta, co bude
    nejdříve smazána)

### Adresový prostor

-   počítače mají svůj vlastní adresový prostor, kde jsou uloženy
    jednotlivé části kódů

-   horní část je typicky vyčleněna pro kernel OS

-   dolní část je virtuální adresový prostor (s kterým pracuje uživatel)

-   problém s programy využívající více programovacích jazyků (může
    dojít paměť), každý má svůj vlastní stack, heap (může rychleji dojít
    paměť)

### Alokace paměti

-   1\. část alokace je Reserve - najde zda existuje vhodná volná část
    paměti

-   2\. část alokace je Commit - fyzický zápis do paměti (typicky po
    částech)

-   v C++ není halda spravována GC, je tedy nutno objekt implicitně
    smazat příkazem delete

    -   problém pokud double delete neoprávněný přístup do paměti
        (objekt už tam není)

    -   problém pokud nesmažu plýtvání pamětí (neodalokovanou část nelze
        alokovat)

-   v C# a dalších GC jazycích spravuje objekty na haldě garbage
    colector

    -   jednou za čas zkontroluje objekty na, které nevedou reference a
        smaže je z haldy

    -   je spouštěn při nové alokaci (ne vždy)

    -   významně zpomaluje běh programu

    -   problém je, že na haldě vznikají díry a je potřeba většího
        souvislého úseku (např. pro pole) heap compacting

    -   heap compacting - prochází se halda a objekty se přesunují dolů,
        aby zaplnily díry, (je to velmi pomalé, provádí se někdy při
        dealokaci)

    -   pro zefektivnění 2 haldy (Large Object Heap, Small Object
        Heap) - velké objekty typicky jen pole (přizpůsobené operace na
        haldě)

    -   pro efektivitu dělíme objekty na 3 generace (dle délky života)

    -   s rostoucím časem se přeživší objekty posunují do vyšší generace
        (není kontrolována GC tak často)

    -   problém velkých objektů v nejvyšší generaci (např. zavřený
        soubor) lze implicitně zavolat GC



## Implementace základních prvků objektových jazyků

Rychle připomenutí OOP
 - kód rozdělen do tříd a objektů (přidružen k datům)
 - metody zapouzdřeny v objektech -> lepší přenos kódu
 - dědičnost
 - polymorfizmus - do jednoho pole narvu různé podtřídy dané třídy a mohu volat stejnou metodu na všech
   - přetěžování operátorů, přetěžování metod
 - rozhraní

Implementace .. tabulka virtuálních metod VS jak napsat objetk, třídu,.. reference vs deep copy


## Nativní a interpretovaný běh, řízení překladu a sestavení programu

#### Nativni
 - je to kompilovane do jazyka, kteremu rozumi procesor na dane platforme
 - kdyz mam zkompilovanej program na jedny platforme a chci ho prenest na druhou, mam dve moznosti, jak to udelat:
   1. zkompilovat kod znova pro tu danou platformu
   2. pouzit emulator, kterej na druhy platforme jakoby simuluje CPU toho prvniho stroje a tak si ten program mysli, ze je na tom prvnim stroji, doopravdy ale neni

#### Interpretovany jazyk
 - 3 druhy:
   1. provádějí přímo zdrojovej kód (unixovej shell)
   2. přeloží zdroják do mezikódu a pak ho spustí (Python)
   3. přímo spustí předem vytvořený předkompilovaný mezikód, který je produktem části interpretu (python, java prej)
 - výhody: dobře se to ladí, je to kompatibilní (když mám interpret na jiný platformě), paměť se dobře spravuje, protože není vázána na fyzickou adresu v operační paměti
 - obecně se dá prej mnohem jednodušeji vyrobit interpret než kompilátor -> můžu mít hodně platforem cílovejch

 - rychlost se zvysuje diky just-in-time (JIT) kompilaci
     - ta funguje tak, ze pri behu programu (uz ho jako interpretuju), tak si prekladam do nativniho jazyka casti toho kodu. Udelam to predem a pak ta interpretace je rychlejsi
     - ma to ale overhead na startu, kdy se to predkompilovava, taky to ma overhead uprostred programu, protoze se to kompiluje i za behu

#### Vyhody a nevyhody
 - nativni
     - rychlejsi
     - zavisly na platforme
 - interpretovany
     - pomalej (ale neni to tak hrozny s JIT)
     - vice nezavisle na platforme
     - potreba mit interpret na cilovym PC

#### Překlad
 - vlastně funkce z jednoho jazyka do jiného (zdrojový kód -> strojový kód)
 - kód fragmentován do více jednotek (např. souborů s kódem)
 - tyhle jednotky jsou překládány zvlášť (občas třeba nechceme všechno kompilovat naráz, žejo..) => překládají se do tzv. **objektového kódu**
 - objektový kód už je v podstatě strojový kód, jen jsou tam navíc informace o externích proměnných a informace umožňující přemístění návěstí..
 - Z jednotlivých objektových kódů a z funkcí v knihovnách se pomocí **linkeru** sestaví spustitelný strojový kód
 - překladový nástroje pak mohou generovat i něco navíc - mapy proměnných, kód s rozvojem maker, info o vyhodnocení konstant ... tohle se pak může používat pro debuggery
 - zadávaj se taky informace o tom, jak má překladač kód optimalizovat, o povolených rozšířeních syntaxe, warningy, ...
 - zdroják může obsahovat **pragmy**, což jsou příkazy nebo informace pro kompilátor

#### Překladač
 - běžně sestává ze dvou částí
   1. frontend = závislá na vstupním jazyce
   2. backend = závislá na cílové architektuře
 - překlad nemusí být přímý, může používat **mezikód**
   - mezikód je pak běžně nezávislý na platformě, ale je to už hezky zpracovanej zdrojovej kód (už je hodně zprocesovanej a je lehčí to už dopřekládat)
     - výhody pak jsou, že mezikód pak můžu překládat do různých architektur (a už to není tak složité) a dále že můžu mít více jazyků (zdrojových) a všechny mi to přeloží do mezikódu a pak už tu zbylou část (do cílový architektury) mám hotovou

#### Just-Tn-Time kompilace (JIT)
 - Zdrojový kód se **CELÝ** přeloží do mezikódu a to je pak dáno do kompilátoru dalšímu při spuštění programu (prej ne interpretu (na wikipedii)) .. asi proto, že se to překládá do nativního kódu
    - kompilační chyby jsou nalezeny již před spuštěním (super!)
    - on je danej před spuštěním a ono se to celý přeloží před spuštěním (prodleva na začátku)
    - pak jsou ekonomický JIT, který prostě v průběhu kompilujou
 - hodně se cachuje
 - jde ale líp optimalizovat pro danej procesor, což je gut
 - je možnost taky kompilovat při instalaci (Ahead-of-Time kompilace)
 - techniky
   - odstranění mrtvého kódu
   - vkládání těl metod
   - odstranění shodných podvýrazů
   - rozbalování smyček



