Programovací jazyk C3: reakce na chyby, odložení vykonání příkazů

9. 10. 2025
Doba čtení: 31 minut

Sdílet

Programovací jazyk C3
Autor: Root.cz s využitím Zoner AI
C3 obsahuje v porovnání s původním jazykem C několik novinek. Mezi ně patří podpora pro práci s volitelnými (optional) hodnotami a konstrukce zajišťující odložené volání nějakého příkazu (defer).

Obsah

1. Programovací jazyk C3: reakce na chyby, odložení vykonání příkazů

2. Jak reprezentovat chybějící hodnotu nebo informaci o chybě?

3. Rozšíření datových typů: Optional

4. Přístup k hodnotě typu Optional s detekcí chyby

5. Uživatelsky definovaný typ s informací o chybě

6. Vynucení přístupu k hodnotě operátorem !!

7. Chování operátoru !! v případě, že je namísto hodnoty uložena informace o chybě

8. Praktické použití: výpočet faktoriálu bez vracení informace o chybě

9. Výpočet faktoriálu s detekcí nekorektního vstupu

10. Pokus o přímý přístup k vrácené hodnotě operátorem !!

11. Konstrukce defer

12. Základní porovnání konstrukce defer v jazycích Go a C3

13. Proč byla konstrukce defer do jazyka C3 přidána?

14. Pořadí volání příkazů zaregistrovaných s využitím příkazu defer

15. Sémantika defer v jazyce Go

16. Sémantika defer v jazyce C3

17. Konstrukce defer a return

18. Funkce volané na začátku a konci procesu

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Programovací jazyk C3: reakce na chyby, odložení vykonání příkazů

V již páté části seriálu o programovacím jazyce C3 se budeme zabývat velmi důležitým tématem, který byl do jisté míry v původním jazyce C poněkud odsunut do pozadí. Jedná se o způsoby, jakými může aplikace reagovat na nějaké chybové hodnoty resp. na chybějící hodnoty atd. S touto problematikou souvisí i rozšíření typového systému programovacího jazyka C3 o typ Optional. Ve skutečnosti se nejedná o žádnou žhavou novinku, protože typ Optional vznikl jako varianta typů Option a Result známých z dalších programovacích jazyků.

Popíšeme si taktéž programovou konstrukci, kterou lze použít pro odložené vykonání nějakých příkazů. Tato konstrukce se zapisuje klíčovým slovem defer, jehož sémantika je však v jazyce C3 odlišná, než například v programovacím jazyce Go (stejný zápis povede k odlišnému způsobu vykonání bloků defer).

2. Jak reprezentovat chybějící hodnotu nebo informaci o chybě?

V prakticky dennodenní programátorské praxi se setkáme s problematikou reprezentace chybějících hodnot nebo informací o chybě. Příkladem může být funkce, která buď vrací výsledek nějakého výpočtu nebo chybu. V různých jazycích se setkáme s několika způsoby, jak toho dosáhnout:

  1. Namísto vypočtené hodnoty se vrací „magická“ hodnota stejného typu
  2. Vrací se buď ukazatel nebo Null/None
  3. Vyhazuje se výjimka (odlišné řízení toku programu)
  4. Vrací se dvojice (hodnota, nil) nebo (cokoli, chyba)
  5. Používají se specializované typy Option, Maybe, Result atd.

V jazyku C3 se setkáme s posledním popsaným způsobem. Jedná se o způsob, který je převzatý z Haskellu, OCamlu či jazyka F#. Příkladem může být jazyk F# s typem Option:

type Option<'a> =
   | Some of 'a
   | None

Vidíme, že se ve skutečnosti vlastně jedná o výčtový typ s pouhými dvěma explicitně zapsanými (a překladači známými) hodnotami None a Some, přičemž Some „obaluje“ vlastní hodnotu typu 'a (alfa), se kterou chceme pracovat. Současně se tedy – zcela podle očekávání – jedná o generický datový typ, což v praxi znamená, že volitelná hodnota může být jakéhokoli typu (ovšem samozřejmě hlídaného překladačem již v době překladu zdrojového kódu).

Jen pro zajímavost se podívejme, jak je typ Option definovaný v Rustu:

enum Option<T> {
    None,
    Some(T),
}

V mnoha případech však nemusí být použití datového typu Option tím nejlepším řešením. Pro příklad nemusíme chodit daleko – předpokládejme, že budeme chtít, aby námi definovaná funkce pro dělení celých čísel vracela v případě pokusu o dělení nulou chybové hlášení a nikoli nicneříkající hodnotu None. K tomuto účelu se v programovacím jazyku F# používá datový typ nazvaný příhodně Result. Tento datový typ se podobá již popsanému typu Option, ovšem s tím rozdílem, že obaluje buď výsledek (třeba návratovou hodnotu volané funkce) nebo informaci o chybě. Deklarace struktury Result vypadá následovně:

type Result<'T,'TError> =
    | Ok of ResultValue:'T
    | Error of ErrorValue:'TError

Jen pro zajímavost a doplnění se podívejme, jak je tomu v Rustu:

enum Result<T, E> {
    Ok(T),
    Err(E),
}
Poznámka: opět tedy platí, že rozdíl je především v syntaxi, nikoli v sémantice.

V programovacím jazyku C3 nalezneme právě obdobu typu Result, která se zde však označuje termínem Optional (což může být zpočátku maličko matoucí).

3. Rozšíření datových typů: Optional

Nejprve si ukažme triviální příklad, ve kterém je definována běžná lokální proměnná typu int, je provedena inicializace této proměnné a následně je hodnota proměnné vypsána na standardní výstup:

module error_handling;
import std::io;
 
fn void main()
{
    int i = 42;
    io::printf("i=%d\n", i);
}

Výsledek bude pochopitelně následující:

i=42

V případě, že budeme chtít pracovat s potenciálně neuvedenými nebo neznámými hodnotami (tedy Optional) postačuje definici datového typu doplnit o otazník – viz podtrženou část kódu:

module error_handling;
import std::io;
 
fn void main()
{
    int? i = 42;
    io::printf("i=%d\n", i);
}

S takto definovanou proměnnou i se ovšem pracuje odlišným způsobem, na což nás upozorní překladač:

 4: fn void main()
 5: {
 6:     int? i = 42;
 7:     io::printf("i=%d\n", i);
        ^^^^^^^^^^^^^^^^^^^^^^^
(/home/ptisnovs/src/c3-examples/c3-errors-handling/02_optional_value.c3:7:5)
Error: The result of this call is optional due to its argument(s). This
optional result may not be implicitly discarded. Please assign it to a
variable, ignore it with '(void)', rethrow with '!' or panic with '!!'.

Z chybového hlášení překladače je patrné, že se k proměnné i musíme chovat jinak, než k běžné proměnné typu int. Jak bude zpracování její hodnoty vypadat, je ukázáno v navazující kapitole.

4. Přístup k hodnotě typu Optional s detekcí chyby

Korektní způsob přístupu (čtení) hodnoty, která je typu Optional, vyžaduje, aby se otestovaly obě možnosti, které mohou nastat – tj. jak situace, kdy proměnná obsahuje korektní hodnotu, tak i situace, kdy hodnotu neobsahuje popř. je namísto běžné hodnoty v proměnné uložena informace o chybě. Typicky se v této situaci setkáme s využitím rozvětvení typu if-else, které může vypadat následovně:

module error_handling;
import std::io;
 
fn void main()
{
    int? i = 42;
 
    if (catch excuse = i)
    {
        io::printfn("Fault: %s", excuse);
    } else {
        io::printf("i=%d\n", i);
    }
}

Překladač zjistí, že se korektně testují oba možné stavy a dovolí zdrojový kód přeložit (a spustit):

i=42

V případě, že se v první větvi vyskakuje z celé funkce nebo bloku (break, continue, return), není nutné zapisovat větev else, neboť překladač opět dokáže zjistit, že v podmínce testujeme potenciální chybový stav a navíc se z větve if řízení programu vrací zpět do volající funkce. To znamená, že i následující zápis je z pohledu překladače plně korektní a tudíž i přeložitelný:

module error_handling;
import std::io;
 
fn void main()
{
    int? i = 42;
 
    if (catch excuse = i)
    {
        io::printfn("Fault: %s", excuse);
        return;
    }
    io::printf("i=%d\n", i);
}

5. Uživatelsky definovaný typ s informací o chybě

Připomeňme si, že proměnná typu Optional může obsahovat buď přímo hodnotu (například 42) nebo informaci o chybě. Jak však taková informace o chybě vypadá? Jedná se o samostatnou hodnotu, kterou je možné definovat s využitím specializovaného klíčového slova faultdef. Definice může v tom nejjednodušším případě vypadat následovně:

faultdef MY_ERROR;

Tuto hodnotu můžeme přiřadit do proměnné typu Optional. Povšimněte si otazníku na konci přiřazení:

module error_handling;
import std::io;
 
faultdef MY_ERROR;
 
fn void main()
{
    int? i = MY_ERROR?;
 
    if (catch excuse = i)
    {
        io::printfn("Fault: %s", excuse);
    } else {
        io::printf("i=%d\n", i);
    }
}

Výsledek získaný po překladu a spuštění tohoto příkladu:

Fault: error_handling::MY_ERROR

Samozřejmě lze použít i alternativní zápis bez větve else:

module error_handling;
import std::io;
 
faultdef MY_ERROR;
 
fn void main()
{
    int? i = MY_ERROR?;
 
    if (catch excuse = i)
    {
        io::printfn("Fault: %s", excuse);
        return;
    }
    io::printf("i=%d\n", i);
}

Výsledky:

Fault: error_handling::MY_ERROR

6. Vynucení přístupu k hodnotě operátorem !!

Programovací jazyk C3 vývojářům nabízí speciální operátor reprezentovaný dvojicí znaků !!, který je zapisovaný za jméno proměnné nebo výrazu typu Optional. Tento operátor se pokouší provádět „unwrapping“ hodnoty, která je do Optional zabalena – počítá tedy optimisticky s tím, že proměnná skutečně hodnotu obsahuje (a nikoli chybu). Pokud proměnná/výraz skutečně obsahuje běžnou hodnotu, bude výsledkem tato hodnota, což si ostatně velmi snadno ověříme v dalším demonstračním příkladu:

module error_handling;
import std::io;
 
faultdef MY_ERROR;
 
fn void main()
{
    int? i = 42;
 
    io::printf("i=%d\n", i!!);
}

Vzhledem k tomu, že proměnná i (typu Optional) obsahuje běžnou hodnotu 42, je tato hodnota výrazem i!! vyhodnocena a vrácena:

i=42

7. Chování operátoru !! v případě, že je namísto hodnoty uložena informace o chybě

Pokud naopak do proměnné i namísto běžné hodnoty uložíme informaci o chybě a budeme chtít provést operaci typu unwrap nad touto proměnnou, musí runtime programovacího jazyka C3 na tuto skutečnost nějakým vhodným způsobem zareagovat – zde konkrétně tak, že dojde k běhové chybě a program zhavaruje:

module error_handling;
import std::io;
 
faultdef MY_ERROR;
 
fn void main()
{
    int? i = MY_ERROR?;
 
    io::printf("i=%d\n", i!!);
}

Z výpisu, který se zobrazí po pádu programu, lze dohledat, k jaké chybě došlo i v jakém místě programu musíme hledat příslušný programový řádek:

ERROR: 'Unexpected fault 'error_handling::MY_ERROR' was unwrapped!'
  in std.core.builtin.default_panic (/home/ptisnovs/xy/c3c/build/lib/std/core/builtin.c3:175) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling]
  in std.core.builtin.panicf (/home/ptisnovs/xy/c3c/build/lib/std/core/builtin.c3:231) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling]
  in error_handling.main (/home/ptisnovs/src/c3-examples/c3-errors-handling/08_force_unwrap.c3:10) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling]
  in @main_to_void_main (/home/ptisnovs/xy/c3c/build/lib/std/core/private/main_stub.c3:18) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling] [inline]
  in main (/home/ptisnovs/src/c3-examples/c3-errors-handling/08_force_unwrap.c3:6) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling]
  in __libc_start_call_main (source unavailable) [/lib64/libc.so.6]
  in __libc_start_main_alias_2 (source unavailable) [/lib64/libc.so.6]
  in _start (source unavailable) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling]

8. Praktické použití: výpočet faktoriálu bez vracení informace o chybě

Podívejme se nyní na praktické použití datového typu, který může nést informaci o hodnotě nebo naopak informaci o chybě. Typickým příkladem je výpočet faktoriálu, přičemž samotný faktoriál je definován pouze pro kladné hodnoty. Otázkou tedy je, „co“ se má vrátit v případě, že budeme chtít počítat faktoriál pro zápornou hodnotu (to by ještě bylo možné obejít vhodným typem parametru) nebo pro příliš vysokou hodnotu. První řešení spočívá v tom, že budeme nekorektní parametr do jisté míry ignorovat a vrátíme nějakou „magickou“ hodnotu (nebo test na chybný vstup vůbec neprovedeme):

module error_handling;
import std::io;
 
fn int factorial(int n)
{
    int result = 1;
    for (int i = 1; i <= n; ++i)
    {
        result *= i;
    }
    return result;
}
 
fn void main()
{
    for (int n = 10; n >= -10; n--)
    {
        io::printf("%d! = %d\n", n, factorial(n));
    }
}

Výpočet faktoriálu pro vstupní hodnoty v rozmezí 10..-10 dopadne v tomto případě následovně:

10! = 3628800
9! = 362880
8! = 40320
7! = 5040
6! = 720
5! = 120
4! = 24
3! = 6
2! = 2
1! = 1
0! = 1
-1! = 1
-2! = 1
-3! = 1
-4! = 1
-5! = 1
-6! = 1
-7! = 1
-8! = 1
-9! = 1
-10! = 1
Poznámka: zde se tedy neplatný parametr do jisté míry ignoroval a vrátila se hodnota 1.

9. Výpočet faktoriálu s detekcí nekorektního vstupu

Výpočet faktoriálu ovšem můžeme upravit tak, aby se detekovaly záporné parametry a pokud je opravdu záporný parametr předán, vrátí se chybová hodnota NEGATIVE_INPUT. Povšimněte si, že návratovou hodnotou funkce pro výpočet faktoriálu, není typ int ale int?:

module error_handling;
import std::io;
 
faultdef NEGATIVE_INPUT;
 
fn int? factorial(int n)
{
    if (n < 0) {
        return NEGATIVE_INPUT?;
    }
    int result = 1;
    for (int i = 1; i <= n; ++i)
    {
        result *= i;
    }
    return result;
}
 
fn void main()
{
    for (int n = 10; n >= -10; n--)
    {
        int? result = factorial(n);
        if (catch excuse = result)
        {
            io::printfn("Fault: %s: %d", excuse, n);
        } else {
            io::printf("%d!=%d\n", n, result);
        }
    }
}

V programu (main) korektně reagujeme na chybové hodnoty vrácené z funkce factorial:

10!=3628800
9!=362880
8!=40320
7!=5040
6!=720
5!=120
4!=24
3!=6
2!=2
1!=1
0!=1
Fault: error_handling::NEGATIVE_INPUT: -1
Fault: error_handling::NEGATIVE_INPUT: -2
Fault: error_handling::NEGATIVE_INPUT: -3
Fault: error_handling::NEGATIVE_INPUT: -4
Fault: error_handling::NEGATIVE_INPUT: -5
Fault: error_handling::NEGATIVE_INPUT: -6
Fault: error_handling::NEGATIVE_INPUT: -7
Fault: error_handling::NEGATIVE_INPUT: -8
Fault: error_handling::NEGATIVE_INPUT: -9
Fault: error_handling::NEGATIVE_INPUT: -10

10. Pokus o přímý přístup k vrácené hodnotě operátorem !!

Ještě si pro úplnost ukažme, jak dopadne pokus o unwrapping vrácené hodnoty bez testování, zda nebyla vrácena chyba:

module error_handling;
import std::io;
 
faultdef NEGATIVE_INPUT;
 
fn int? factorial(int n)
{
    if (n < 0) {
        return NEGATIVE_INPUT?;
    }
    int result = 1;
    for (int i = 1; i <= n; ++i)
    {
        result *= i;
    }
    return result;
}
 
fn void main()
{
    for (int n = 10; n >= -10; n--)
    {
        int result = factorial(n)!!;
        io::printf("%d!=%d\n", n, result);
    }
}

Takto upravený program po svém překladu a spuštění podle očekávání zhavaruje:

ERROR: 'Unexpected fault 'error_handling::NEGATIVE_INPUT' was unwrapped!'
  in std.core.builtin.default_panic (/home/ptisnovs/xy/c3c/build/lib/std/core/builtin.c3:175) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling]
  in std.core.builtin.panicf (/home/ptisnovs/xy/c3c/build/lib/std/core/builtin.c3:231) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling]
  in error_handling.main (/home/ptisnovs/src/c3-examples/c3-errors-handling/11_factorial.c3:23) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling]
  in @main_to_void_main (/home/ptisnovs/xy/c3c/build/lib/std/core/private/main_stub.c3:18) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling] [inline]
  in main (/home/ptisnovs/src/c3-examples/c3-errors-handling/11_factorial.c3:19) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling]
  in __libc_start_call_main (source unavailable) [/lib64/libc.so.6]
  in __libc_start_main_alias_2 (source unavailable) [/lib64/libc.so.6]
  in _start (source unavailable) [/home/ptisnovs/src/c3-examples/c3-errors-handling/error_handling]
Program interrupted by signal 4.

11. Konstrukce defer

Další jazykovou konstrukcí, která slouží k ovlivnění toku programu (control flow), je příkaz (resp. přesněji řečeno programová konstrukce) reprezentovaná klíčovým slovem defer. Touto konstrukcí je možné zaregistrovat požadavek na volání nějakého uceleného programového kódu (tj. typicky běžné funkce či anonymní funkce) do zásobníku, jehož obsah se vykoná při odchodu z toho bloku, ve kterém je příkaz defer použit. Z tohoto důvodu se tato technika nazývá odložené volání funkce nebo anonymní funkce. Předchozí dvě věty sice mohou znít poměrně složitě, zvláště pokud jste se s tímto konceptem dříve nesetkali, ale samotné použití konstrukce defer je ve skutečnosti poměrně přímočaré, jak si to ostatně ukážeme v demonstračních příkladech.

Poznámka: pozor – konstrukce defer má v jazyce C3 odlišnou sémantiku, než stejné klíčové slovo v jazyce Go!

12. Základní porovnání konstrukce defer v jazycích Go a C3

Konstrukce defer je velmi užitečnou součástí programovacího jazyka Go zmíněného v předchozí kapitole. Ukažme si tedy alespoň ve stručnosti, jak se tato konstrukce v Go používá:

package main
 
import "fmt"
 
func main() {
        defer fmt.Println("Too late")
 
        fmt.Println("Hello")
}

Z výše zobrazeného zdrojového kódu tohoto příkladu je patrné, že ve funkci main je použit příkaz defer, kterým požadujeme, aby se při ukončování funkce main zavolala jiná funkce, konkrétně funkce nazvaná fmt.Println (které se v tomto případě předá jediný parametr). Tím, že je před volání funkce fmt.Println zapsáno klíčové slovo defer, dojde k onomu odložení volání – runtime systém si jen zapamatuje, že má tuto funkci zavolat později.

Z chování programu je parné, že došlo k odloženému volání funkce:

Hello
Too late

V programovacím jazyku C3 se konstrukce defer zapisuje prakticky stejným způsobem, jako tomu bylo v Go. Ostatně neuškodí krátké porovnání:

module error_handling;
import std::io;
 
fn void main()
{
    defer io::printn("Too late");
    io::printn("Hello");
}

Opět se podívejme, jaké zprávy (a v jakém pořadí) se vypíšou po překladu a spuštění tohoto demonstračního příkladu:

Hello
Too late

13. Proč byla konstrukce defer do jazyka C3 přidána?

Nyní tedy víme (prozatím alespoň ve stručnosti), jakým způsobem se konstrukce defer zapisuje a používá, ale musíme si samozřejmě vysvětlit, proč vůbec v jazyku C3 existuje. V mnoha programech je totiž nutné nějakým způsobem a za jakýchkoli okolností uzavírat určité prostředky (resources). Může se jednat o připojení k databázi, otevřené připojení ke klientovi, otevřený soubor atd. A právě toto uzavírání prostředků lze poměrně elegantním způsobem realizovat v bloku či v několika blocích defer. Jedná se vlastně o zobecnění programového bloku typu finally používaného v programové konstrukci try-catch-finally v některých jiných programovacích jazycích.

Poznámka: konstrukci defer s funkcí pro uzavření nějakého prostředku (souboru, …) do zdrojového kódu zapište na nejbližší logické místo, například ihned po příkazu, který soubor otevírá. Tak dáte případným čtenářům kódu jasně najevo, jakým způsobem ošetřujete chyby – toto s klasickými bloky try-catch-finally obecně nelze provést.

14. Pořadí volání příkazů zaregistrovaných s využitím příkazu defer

Nic nám pochopitelně nebrání použít v rámci jedné funkce (nebo jakéhokoli jiného bloku) hned několik příkazů defer. Zajímavé bude ovšem zjistit, jak se bude tato funkce chovat při spuštění programu, tj. v runtime. Můžeme si to snadno otestovat, protože již víme, že v bloku defer je možné funkci (či obecně kódu zde zapsaném) předat libovolné argumenty. To mj. znamená, že můžeme defer použít například v programové smyčce atd. Ovšem my se obejdeme bez smyčky – pouze zaregistrujeme tři odložené příkazy:

module error_handling;
import std::io;
 
fn void main()
{
    defer io::printn("Defer #1");
    defer io::printn("Defer #2");
    defer io::printn("Defer #3");
    io::printn("Hello");
}

Ze zobrazených výsledků je patrné, že se odložené příkazy volají v opačném pořadí, než v jakém byly zaregistrovány. Je tomu tak z toho důvodu, že tyto příkazy jsou uloženy do zásobníku, tedy do struktury typu LIFO (Last In First Out):

Hello
Defer #3
Defer #2
Defer #1

15. Sémantika defer v jazyce Go

V programovacím jazyce Go se odložené příkazy vykonají (v opačném pořadí) vždy při opouštění funkce nebo metody, a to nezávisle na tom, zda byly zapsány v nějakém (zanořeném) bloku kódu. Ukažme si to na jednoduchém demonstračním příkladu se třemi bloky defer, které jsou definovány na úrovni funkce main, v jednom zanořeném bloku a nakonec v bloku zanořeném do nějakého jiného bloku:

package main
 
import "fmt"
 
func main() {
    fmt.Println("Hello")
    defer fmt.Println("Defer #1")
    {
        defer fmt.Println("Defer #2")
        {
            defer fmt.Println("Defer #3")
        }
    }
    fmt.Println("Bye")
}

Pořadí zobrazení zpráv po spuštění tohoto příkladu:

Hello
Bye
Defer #3
Defer #2
Defer #1

Z tohoto výpisu je patrné, že skutečně nezáleží na tom, zda je defer použit přímo v dané funkci nebo v nějakém vloženém bloku.

16. Sémantika defer v jazyce C3

Programovací jazyk C3 se chová odlišně od jazyka Go, protože odložené příkazy (defer) jsou zavolány nikoli na konci funkce, ale na konci každého bloku. To tedy znamená, že i když je syntaxe zápisu bloků defer v obou jazycích totožná, sémantika (chování) v runtime může být zcela odlišné. Pokusme se přepsat příklad z předchozí kapitoly z Go do C3:

module error_handling;
import std::io;
 
fn void main()
{
    io::printn("Hello");
    defer io::printn("Defer #1");
    {
        defer io::printn("Defer #2");
        {
            defer io::printn("Defer #3");
        }
    }
    io::printn("Bye");
}

Nyní je ze zobrazených zpráv patrné, že třetí a druhý odložený příkaz se vykonají ještě před výpisem zprávy Bye a pouze první odložený příkaz je skutečně zavolán při ukončování funkce (tělo funkce je samo o sobě blokem):

Hello
Defer #3
Defer #2
Bye
Defer #1

17. Konstrukce defer a return

Ještě si ovšem musíme ukázat jednu kombinaci jazykových konstrukcí a to konkrétně kombinaci defer a return. Konstrukce return ukončuje běh funkce a tudíž se vykonají i odložené příkazy, ovšem dokážeme tímto způsobem například modifikovat návratovou hodnotu funkce? Vyzkoušejme si to:

module error_handling;
import std::io;
 
fn int function()
{
    int a = 10;
 
    io::printn("Hello");
 
    defer a++;
    io::printn("Bye");
 
    return a;
}
 
fn void main()
{
    io::printn(function());
}

Z výpisu je patrné, že takto jednoduché to nebude:

Hello
Bye
10
Poznámka: příště si ukážeme trik, jak dosáhnou modifikace návratové hodnoty blokem defer.

18. Funkce volané na začátku a konci procesu

Konstrukce defer umožňuje modifikovat pořadí provádění kódu na úrovni jednotlivých příkazů (statement). Programovací jazyk C3 kromě toho podporuje i označení vybraných funkcí pomocí @init a @finalizer. Funkce označená jako @init bude provedena na začátku procesu a pochopitelně funkce označená @finalizer na konci procesu. Pokusme se tedy jednotlivé způsoby zkombinovat do jednoho (umělého) příkladu:

import std::io;
 
fn void main()
{
    defer io::printf("world");
 
    io::printf(", ");
}
 
fn void hello() @init
{
    io::printf("Hello");
}
 
fn void world() @finalizer
{
    io::printn("!");
}

Tento demonstrační příklad by měl po svém spuštění vypsat klasickou zprávu:

Hello, world!

19. Repositář s demonstračními příklady

Demonstrační příklady vytvořené pro nejnovější verzi programovacího jazyka C3 byly uloženy do repositáře dostupného na adrese https://github.com/tisnik/c3-examples. Následují odkazy na jednotlivé příklady (či jejich nedokončené části).

Demonstrační příklady z prvního článku o programovacím jazyku C3:

# Příklad Stručný popis Adresa
1 factorial.c3 realizace výpočtu faktoriálu https://github.com/tisnik/c3-examples/blob/master/intro­duction/factorial.c3
2 factorial_macro.c3 výpočet faktoriálu konkrétní hodnoty implementovaný formou makra https://github.com/tisnik/c3-examples/blob/master/intro­duction/factorial_macro.c3
       
3 swap_macro.c3 makro realizující prohození dvou hodnot https://github.com/tisnik/c3-examples/blob/master/intro­duction/swap_macro.c3
       
4 renderer.c výpočet a vykreslení Juliovy množiny implementovaný v jazyku C https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer.c
5 renderer_v1.c3 definice datové struktury s rozměry rastrového obrázku a skeleton všech funkcí https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v1.c3
6 renderer_v2.c3 anotace parametrů funkcí typu ukazatel (pointer) https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v2.c3
7 renderer_v3.c3 statická kontrola, zda se nepředávají neinicializované ukazatele https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v3.c3
8 renderer_v4.c3 runtime kontrola, zda se nepředávají neinicializované ukazatele https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v4.c3
9 renderer_v5.c3 první (nekorektní) varianta funkce pro inicializaci barvové palety https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v5.c3
10 renderer_v6.c3 druhá (korektní) varianta funkce pro inicializaci barvové palety https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v6.c3
11 renderer_v7.c3 volání knihovní I/O funkce a volání nativní céčkovské funkce https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v7.c3
12 renderer_v8.c3 plně funkční program pro výpočet a vykreslení Juliovy množiny https://github.com/tisnik/c3-examples/blob/master/intro­duction/renderer_v8.c3

Demonstrační příklady ze druhého článku o jazyku C3:

# Příklad Stručný popis Adresa
13 01_just_main.c3 struktura nejjednoduššího programu obsahujícího pouze prázdnou funkci main https://github.com/tisnik/c3-examples/blob/master/c3-basics/01_just_main.c3
14 02_module_name.c3 struktura programu s uvedeným plným jménem modulu https://github.com/tisnik/c3-examples/blob/master/c3-basics/02_module_name.c3
15 03_hello_world.c3 klasický program typu „Hello, world!“ napsaný v jazyku C3 https://github.com/tisnik/c3-examples/blob/master/c3-basics/03_hello_world.c3
16 04_exit_value.c3 ukončení procesu s předáním návratového kódu zpět volajícímu programu https://github.com/tisnik/c3-examples/blob/master/c3-basics/04_exit_value.c3
17 05_c_function.c3 zavolání funkce definované v knihovně programovacího jazyka C https://github.com/tisnik/c3-examples/blob/master/c3-basics/05_c_function.c3
       
18 06_bool_type.c3 definice proměnných typu pravdivostní hodnota (bool) https://github.com/tisnik/c3-examples/blob/master/c3-basics/06_bool_type.c3
19 07_int_to_bool.c3 implicitní převod hodnoty typu int na pravdivostní hodnotu (nekorektní řešení) https://github.com/tisnik/c3-examples/blob/master/c3-basics/07_int_to_bool.c3
20 08_int_to_bool.c3 explicitní převod hodnoty typu int na pravdivostní hodnotu (korektní řešení) https://github.com/tisnik/c3-examples/blob/master/c3-basics/08_int_to_bool.c3
21 09_int_to_bool.c3 explicitní převod hodnoty typu int na pravdivostní hodnotu (nekorektní řešení) https://github.com/tisnik/c3-examples/blob/master/c3-basics/09_int_to_bool.c3
22 10_bool_sizeof.c3 zjištění velikosti paměti obsazené hodnotou typu bool https://github.com/tisnik/c3-examples/blob/master/c3-basics/10_bool_sizeof.c3
       
23 11_int_types.c3 definice proměnných typu celé číslo se znaménkem s různou bitovou šířkou https://github.com/tisnik/c3-examples/blob/master/c3-basics/11_int_types.c3
24 12_uint_types.c3 definice proměnných typu celé číslo bez znaménka s různou bitovou šířkou https://github.com/tisnik/c3-examples/blob/master/c3-basics/12_uint_types.c3
25 13_no_suffixes.c3 celočíselné konstanty bez uvedení suffixu (bitové šířky) https://github.com/tisnik/c3-examples/blob/master/c3-basics/13_no_suffixes.c3
26 14_suffixes.c3 celočíselné konstanty s uvedením sufficu (bitové šířky) https://github.com/tisnik/c3-examples/blob/master/c3-basics/14_suffixes.c3
27 15_int_sizeof.c3 zjištění velikosti paměti obsazené celočíselnými hodnotami se znaménkem https://github.com/tisnik/c3-examples/blob/master/c3-basics/15_int_sizeof.c3
28 16_uint_sizeof.c3 zjištění velikosti paměti obsazené celočíselnými hodnotami bez znaménka https://github.com/tisnik/c3-examples/blob/master/c3-basics/16_uint_sizeof.c3
29 17_int_conversions.c3 korektní převody mezi celočíselnými hodnotami s různou bitovou šířkou https://github.com/tisnik/c3-examples/blob/master/c3-basics/17_int_conversions.c3
30 18_int_conversions.c3 nekorektní převody mezi celočíselnými hodnotami s různou bitovou šířkou https://github.com/tisnik/c3-examples/blob/master/c3-basics/18_int_conversions.c3
31 19_int_conversions.c3 explicitní převody a přetečení hodnot https://github.com/tisnik/c3-examples/blob/master/c3-basics/19_int_conversions.c3
       
32 20_float_types.c3 definice proměnných typu numerická hodnota s plovoucí řádovou čárkou (tečkou) https://github.com/tisnik/c3-examples/blob/master/c3-basics/20_float_types.c3
       
33 21_vector_type.c3 definice vektoru obsahujícího celočíselné hodnoty https://github.com/tisnik/c3-examples/blob/master/c3-basics/21_vector_type.c3
34 22_vector_operations.c3 základní operace s celými vektory https://github.com/tisnik/c3-examples/blob/master/c3-basics/22_vector_operations.c3
35 23_vector_sizes.c3 zjištění a tisk velikosti vektorů (různé datové typy prvků vektorů, shodná délka) https://github.com/tisnik/c3-examples/blob/master/c3-basics/23_vector_sizes.c3
36 24_vector_sizes.c3 zjištění a tisk velikosti vektorů (stejné datové typy prvků vektorů, odlišná délka) https://github.com/tisnik/c3-examples/blob/master/c3-basics/24_vector_sizes.c3

Demonstrační příklady použité ve třetím článku o jazyku C3:

# Příklad Stručný popis Adresa
37 01_vector_type.c3 definice vektoru, modifikace prvků vektoru, tisk obsahu celého vektoru https://github.com/tisnik/c3-examples/blob/master/c3-containers/01_vector_type.c3
38 02_vector_parameter.c3 předání vektoru do funkce hodnotou https://github.com/tisnik/c3-examples/blob/master/c3-containers/02_vector_parameter.c3
39 03_vector_pointer.c3 předání vektoru do funkce odkazem (přes ukazatel) https://github.com/tisnik/c3-examples/blob/master/c3-containers/03_vector_pointer.c3
       
40 04_array_type.c3 definice pole, modifikace prvků pole, tisk obsahu celého pole https://github.com/tisnik/c3-examples/blob/master/c3-containers/04_array_type.c3
41 05_array_parameter.c3 předání pole do funkce hodnotou https://github.com/tisnik/c3-examples/blob/master/c3-containers/05_array_parameter.c3
42 06_array_pointer.c3 předání pole do funkce odkazem (přes ukazatel) https://github.com/tisnik/c3-examples/blob/master/c3-containers/06_array_pointer.c3
       
43 07_slice_type.c3 vytvoření (konstrukce) řezu (slice) https://github.com/tisnik/c3-examples/blob/master/c3-containers/07_slice_type.c3
44 08_slice_parameter.c3 předání řezu do funkce https://github.com/tisnik/c3-examples/blob/master/c3-containers/08_slice_parameter.c3
45 09_slice_slicing.c3 konstrukce řezu z pole stejně pojmenovanou operací (řez od..do) https://github.com/tisnik/c3-examples/blob/master/c3-containers/09_slice_slicing.c3
46 10_slice_slicing.c3 konstrukce řezu z pole stejně pojmenovanou operací (záporné indexy) https://github.com/tisnik/c3-examples/blob/master/c3-containers/10_slice_slicing.c3
47 11_slice_slicing.c3 konstrukce řezu z pole stejně pojmenovanou operací (určení délky řezu) https://github.com/tisnik/c3-examples/blob/master/c3-containers/11_slice_slicing.c3
48 12_slice_of_slice.c3 konstrukce řezu z jiného řezu https://github.com/tisnik/c3-examples/blob/master/c3-containers/12_slice_of_slice.c3
       
49 13_list_type.c3 vytvoření (konstrukce) seznamu https://github.com/tisnik/c3-examples/blob/master/c3-containers/13_list_type.c3
50 14_list_parameter.c3 předání seznamu do funkce https://github.com/tisnik/c3-examples/blob/master/c3-containers/14_list_parameter.c3
       
51 15_dynamic_array.c3 vytvoření (konstrukce) dynamicky alokovaného pole https://github.com/tisnik/c3-examples/blob/master/c3-containers/15_dynamic_array.c3
       
52 16_string_type.c3 základní typ řetězce string https://github.com/tisnik/c3-examples/blob/master/c3-containers/16_string_type.c3
53 17_string_unicode.c3 Unicode znaky v řetězci typu string https://github.com/tisnik/c3-examples/blob/master/c3-containers/17_string_unicode.c3
54 18_zstring_type.c3 řetězce ukončené nulou (C-string, ASCIIZ) https://github.com/tisnik/c3-examples/blob/master/c3-containers/18_zstring_type.c3
55 19_zstring_unicode.c3 Unicode znaky v řetězci typu zstring https://github.com/tisnik/c3-examples/blob/master/c3-containers/19_zstring_unicode.c3
56 20_string_comparison.c3 porovnávání obsahu řetězců https://github.com/tisnik/c3-examples/blob/master/c3-containers/20_string_comparison.c3

Demonstrační příklady z předchozího článku o jazyku C3:

# Příklad Stručný popis Adresa
57 01_program_stub.c3 struktura programu s uvedeným plným jménem modulu https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/01_program_stub.c3
       
58 02_if.c3 nejjednodušší forma rozvětvení založené na konstrukci if https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/02_if.c3
59 03_if_else.c3 plné rozvětvení realizované konstrukcí if-else https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/03_if_else.c3
60 04_improper_if.c3 nekorektní způsob zápisu programové konstrukce if-else (porovnání s jazykem C) https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/04_improper_if.c3
61 05_improper_if.c3 nekorektní způsob zápisu programové konstrukce if-else (porovnání s jazykem C) https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/05_improper_if.c3
62 06_if_else_if.c3 složitější rozvětvení založené na programové konstrukci if-else if-else https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/06_if_else_if.c3
       
63 07_switch_basic.c3 základní forma vícenásobného rozvětvení založeného na konstrukci switch-case https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/07_switch_basic.c3
64 08_switch_basic.c3 větší množství podmínek a programová konstrukce switch-case https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/08_switch_basic.c3
65 09_switch_condition.c3 podmínky zapsané ve větvích programové konstrukci switch-case vyhodnocované v čase běhu procesu https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/09_switch_condition.c3
66 10_switch_true.c3 konstrukce switch-case bez uvedeného výrazu za klíčovým slovem switch https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/10_switch_true.c3
67 11_switch_break.c3 zápis prázdné větve default v programové konstrukci switch-case https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/11_switch_break.c3
68 12_switch_nextcase.c3 pokračování ve vykonávání konstrukce switch-case vynucené klíčovým slovem nextcase https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/12_switch_nextcase.c3
       
69 13_for_loop.c3 základní forma programové smyčky realizované klíčovým slovem for https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/13_for_loop.c3
70 14_foreach_loop.c3 základní forma programové smyčky typu for-each https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/14_foreach_loop.c3
71 15_foreach_loop.c3 programová smyčka for-each vracející index prvku i hodnotu prvku https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/15_foreach_loop.c3
72 16_foreach_loop.c3 modifikace obsahu pole v programové smyčce for-each https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/16_foreach_loop.c3
73 17_foreach_loop.c3 pokus o modifikaci obsahu procházeného pole https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/17_foreach_loop.c3
74 18_foreach_loop.c3 modifikace procházeného pole přes ukazatel na prvek https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/18_foreach_loop.c3
75 19_foreach_r_loop.c3 programová smyčka for-each, ve které se sekvencí prochází v opačném pořadí https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/19_foreach_r_loop.c3
       
76 20_while_loop.c3 základní forma programové smyčky typu while https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/20_while_loop.c3
77 21_while_loop2.c3 programová smyčka typu while s konstrukcí break https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/21_while_loop2.c3
78 22_nested_loops.c3 realizace vnořených programových smyček https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/22_nested_loops.c3
79 23_break.c3 vnořené programové smyčky a příkaz break: ukončení vnitřní smyčky https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/23_break.c3
80 24_break.c3 vnořené programové smyčky a příkaz break: ukončení vnější smyčky https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/24_break.c3
81 25_break.c3 vnořené programové smyčky a příkaz break, varianta se smyčkami typu while https://github.com/tisnik/c3-examples/blob/master/c3-control-flow/25_break.c3

A konečně následují odkazy na demonstrační příklady z článku dnešního:

# Příklad Stručný popis Adresa
82 01_regular_variable.c3 definice běžné proměnné typu int, přístup k hodnotě této proměnné https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/01_regular_variable.c3
83 02_optional_value.c3 definice proměnné typu Optional int, pokus o přímý přístup k hodnotě této proměnné (nekorektní varianta) https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/02_optional_value.c3
84 03_optional_value.c3 korektní čtení proměnné typu Optional int s detekcí chyby https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/03_optional_value.c3
85 04_optional_value.c3 korektní čtení proměnné typu Optional int s detekcí chyby https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/04_optional_value.c3
86 05_fault.c3 uživatelsky definovaný typ nesoucí informaci o chybě https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/05_fault.c3
87 06_fault.c3 uživatelsky definovaný typ nesoucí informaci o chybě https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/06_fault.c3
88 07_force_unwrap.c3 použití operátoru !! (force unwrap) https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/07_force_unwrap.c3
89 08_force_unwrap.c3 použití operátoru !! (force unwrap) https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/08_force_unwrap.c3
       
90 09_factorial.c3 běžný výpočet faktoriálu bez reakce na neplatný vstup https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/09_factorial.c3
91 10_factorial.c3 výpočet faktoriálu s reakcí na neplatný vstup – řešení bez kontroly návratové hodnoty https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/10_factorial.c3
92 11_factorial.c3 výpočet faktoriálu s reakcí na neplatný vstup – řešení s kontrolou návratové hodnoty https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/11_factorial.c3
       
93 12_defer_basic_usage.c3 konstrukce defer v programovacím jazyce C3 https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/12_defer_basic_usage.c3
94 13_more_defers.c3 pořadí provádění příkazů v blocích defer https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/13_more_defers.c3
95 14_defer_scope.c3 konstrukce defer definovaná ve vnitřních blocích v jazyce C3 https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/14_defer_scope.c3
96 15_defer_return.c3 konstrukce defer a return https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/15_defer_return.c3
       
97 16_init_finalize.c3 funkce označené jako @init a @finalizer https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/16_init_finalize.c3
       
98 defer.go konstrukce defer v programovacím jazyce Go https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/defer.go
99 defer_scope.go konstrukce defer definovaná ve vnitřních blocích v jazyce Go https://github.com/tisnik/c3-examples/blob/master/c3-errors-handling/defer_scope.go

20. Odkazy na Internetu

  1. Programovací jazyk C3: evoluce, nikoli revoluce
    https://www.root.cz/clanky/pro­gramovaci-jazyk-c3-evoluce-nikoli-revoluce/
  2. Programovací jazyk C3: datové typy pro moderní architektury
    https://www.root.cz/clanky/pro­gramovaci-jazyk-c3-datove-typy-pro-moderni-architektury/
  3. Programovací jazyk C3: složené datové typy a kontejnery
    https://www.root.cz/clanky/pro­gramovaci-jazyk-c3-slozene-datove-typy-a-kontejnery/
  4. The C3 Programming Language
    https://c3-lang.org/
  5. C3 For C Programmers
    https://c3-lang.org/language-overview/primer/
  6. C3 is a C-like language trying to be an incremental improvement over C rather than a whole new language
    https://www.reddit.com/r/Pro­grammingLanguages/comments/o­ohij6/c3_is_a_clike_langu­age_trying_to_be_an/
  7. Tiobe index
    https://www.tiobe.com/tiobe-index/
  8. PYPL PopularitY of Programming Language
    https://pypl.github.io/PYPL.html
  9. C3 Tutorial
    https://learn-c3.org/
  10. History of programming languages
    https://devskiller.com/history-of-programming-languages/
  11. History of programming languages (Wikipedia)
    https://en.wikipedia.org/wi­ki/History_of_programming_lan­guages
  12. D language
    https://dlang.org/
  13. Zig programming language
    https://ziglang.org/
  14. V language
    https://vlang.io/
  15. D programming language
    https://en.wikipedia.org/wi­ki/D_(programming_language)
  16. Zig programming language (Wikipedia)
    https://en.wikipedia.org/wi­ki/Zig_(programming_langu­age)
  17. V programming language (Wikipedia)
    https://en.wikipedia.org/wi­ki/V_(programming_language)
  18. Syntax highlighting for C3's programming language
    https://github.com/Airbus5717/c3.vim
  19. Go factorial
    https://gist.github.com/e­simov/9622710
  20. Generational list of programming languages
    https://en.wikipedia.org/wi­ki/Generational_list_of_pro­gramming_languages
  21. The Language Tree: Almost Every Programming Language Ever Made
    https://github.com/Phileo­sopher/langmap
  22. List of C-family programming languages
    https://en.wikipedia.org/wi­ki/List_of_C-family_programming_languages
  23. Compatibility of C and C++
    https://en.wikipedia.org/wi­ki/Compatibility_of_C_and_C%2B%2B
  24. C++23: compatibility with C
    https://www.sandordargo.com/blog/2023/08/23/cpp­23-c-compatibility
  25. Can C++ Run C Code? Understanding Language Compatibility
    https://www.codewithc.com/can-c-run-c-code-understanding-language-compatibility/
  26. C3: Comparisons With Other Languages
    https://c3-lang.org/faq/compare-languages/
  27. C3 Programming Language Gains Traction as Modern C Alternative
    https://biggo.com/news/202504040125_C3_Pro­gramming_Language_Alterna­tive_to_C
  28. The case against a C alternative
    https://c3.handmade.networ­k/blog/p/8486-the_case_against_a_c_alternative
  29. C (programming language) Alternatives
    https://alternativeto.net/software/c-programming-language-/
  30. Seriál Programovací jazyk Go
    https://www.root.cz/seria­ly/programovaci-jazyk-go/
  31. Is C3 the Underdog That Will Overtake Zig and Odin?
    https://bitshifters.cc/2025/05/22/c3-c-tradition.html
  32. „Hello, World!“ program
    https://en.wikipedia.org/wi­ki/%22Hello%2C_World!%22_pro­gram
  33. The C Programming Language
    https://en.wikipedia.org/wi­ki/The_C_Programming_Langu­age
  34. Kontejner (abstraktní datový typ)
    https://cs.wikipedia.org/wi­ki/Kontejner_(abstraktn%C3%AD_da­tov%C3%BD_typ)
  35. Are arrays not considered containers because they are not based off of a class?
    https://stackoverflow.com/qu­estions/37710975/are-arrays-not-considered-containers-because-they-are-not-based-off-of-a-class
  36. Array declaration (C, C++)
    https://en.cppreference.com/w/cpp/lan­guage/array.html
  37. Understanding the Apple ‘goto fail;’ vulnerability
    https://www.blackduck.com/blog/un­derstanding-apple-goto-fail-vulnerability-2.html
  38. Branch (computer science)
    https://en.wikipedia.org/wi­ki/Branch_(computer_scien­ce)
  39. Conditional (computer programming)
    https://en.wikipedia.org/wi­ki/Conditional_(computer_pro­gramming)
  40. Dangling else
    https://en.wikipedia.org/wi­ki/Dangling_else
  41. Switch statement
    https://en.wikipedia.org/wi­ki/Switch_statement
Neutrální ikona do widgetu na odběr článků ze seriálů

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.


Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.