Přetěžování operátorů v programovacím jazyce C3

Dnes
Doba čtení: 54 minut

Sdílet

Programovací jazyk C3
Autor: Root.cz s využitím Zoner AI
Mezi jednu z důležitých vlastností jazyka C3 patří možnost přetěžování vybraných operátorů pro nové datové typy. C3 se snaží o udržení rovnováhy mezi vyjadřovacími schopnostmi jazyka a čitelností a udržovatelností programů.

Obsah

1. Přetěžování operátorů v programovacím jazyce C3

2. Rozdělení programovacích jazyků podle jejich přístupu k operátorům

3. Operátory a další speciální znaky v jazyku C3

4. Krátké připomenutí: definice a volání metod v jazyku C3

5. Metoda pro součet vektorů, která vrací nový vektor

6. Přetížení operátoru + tak, aby se provedl součet dvou vektorů

7. Předání operandů hodnotou nebo odkazem?

8. Několikanásobné přetížení stejného operátoru: přičtení skalární hodnoty vs součet vektorů

9. Přetížení operátoru „zleva“ nebo „zprava“

10. Symetrická varianta přetíženého operátoru součtu

11. Přetížení unárního operátoru – (otočení znaménka)

12. Přetížení operátoru pro porovnání dvou hodnot (rovnost)

13. Přetížení operátoru pro součin tak, aby se prováděl skalární součin dvou vektorů

14. Vynásobení složek vektoru skalární konstantou versus skalární součin vektorů

15. Další operátory, které je možné přetížit

16. Přetížení operátoru pro výběr prvku pro čtení pomocí indexu

17. Klíč ve formě řetězce namísto celočíselného indexu, přetížení přiřazení

18. Přetížení speciálního operátoru len

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

20. Odkazy na Internetu

1. Přetěžování operátorů v programovacím jazyce C3

Operátory hrají v programovacích jazycích odvozených od jazyka C (nebo možná přesněji řečeno už od Algolu 60) velmi důležité role. Ostatně není divu, že poměrně velká část specifikace těchto jazyků je zaměřena právě na popis vlastností operátorů (jejich sémantiky, priority, asociativity, komutativity atd.). V samotném jazyku C je definováno několik desítek operátorů, které mají pevně daný význam – specifikace tedy přesně určuje, pro jaké typy hodnot je možné operátory použít, jakou mají prioritu atd., které operace nejsou povoleny, které jsou nedefinovány apod. V kontextu dnešního článku je zajímavé, že mnohé standardní céčkovské operátory jsou definovány pro různé datové typy, což nepřímo znamená, že specifikace céčka musí obsahovat popis toho, jak se má část programu chovat v případě, že se například sčítá celé číslo s hodnotou s plovoucí řádovou čárkou atd.

V mnoha programovacích jazycích (z nichž mnohé vznikly až po výše zmíněném céčku) se setkáme s takzvanými přetíženými operátory. Jedná se o operátory, jejichž funkce a vlastnosti se mění podle typu operandů. Pravděpodobně nejznámější formou standardně (již v jazyku) přetížených operátorů jsou operátory určené pro provádění základních aritmetických operací, které bývají definovány pro různé numerické datové typy. Ovšem například operátor + může být přetížen vícekrát, typicky pro operaci spojení řetězců (viz například Javu) či například n-tic a seznamů (tak je tento operátor přetížen v Pythonu). V těchto případech se nejenom mění funkce operátoru (protože součet je zcela rozdílná operace od spojení řetězců), ale i jejich další vlastnosti, v tomto případě například komutativita (a nepřímo taktéž asociativita v případě hodnot s plovoucí řádovou čárkou).

Některé programovací jazyky umožňují definici zcela nových operátorů popř. alespoň přetížení existujících operátorů. Z tohoto pohledu můžeme programovací jazyky rozdělit do čtyř skupin na základě dvou vlastností (které jsou na sobě do určité míry nezávislé):

  1. Lze definovat nové operátory?
  2. Lze přetížit stávající operátory?
Poznámka: existující „původní“ operátory jsou v mnoha programovacích jazycích již přetíženy tvůrci jazyka, což ovšem nic neříká o tom, zda je možné je dále přetížit na úrovni programu nebo knihovny. Dobrým příkladem je například již zmíněná Java, v níž není možné dále přetížit operátor + pro různé třídy, například typu BigDecimal, i když by to bylo sémanticky naprosto vyhovující.

2. Rozdělení programovacích jazyků podle jejich přístupu k operátorům

Zajímavé je, že každá ze čtyř možných kombinací zmíněných v úvodní kapitole je obsazena nějakým programovacím jazykem, a to zcela nezávisle na dalších vlastnostech daného jazyka, tedy nezávisle na jeho typovém systému, podpoře objektově orientovaného programování, existence maker atd.:

Jazyky, do nichž nelze přidávat další operátory a existující operátory nelze dále přetěžovat

BASIC
C
Go
Java
JavaScript
Modula-2
Objective-C
Pascal
TypeScript
Visual Basic

Jazyky, do nichž nelze přidávat nové operátory, ale existující operátory je možné přetěžovat

C3
Ada
C#
C++
D
Dart
FreeBASIC
Groovy
Kotlin
Lua
MATLAB
Object Pascal
PHP
Perl
Python
Ruby
Rust
Visual Basic .NET
Poznámka: programovací jazyk C3 patří právě do této kategorie programovacích jazyků. Umožňuje tedy přetěžování operátorů (pro nové datové typy!), ovšem nelze v něm vytvářet operátory nové ani v něm není možné měnit další vlastnosti operátorů, tj. jejich asociativitu, komutativitu ani prioritu.

Jazyky v nichž je možné definovat nové operátory, existující operátory ovšem nelze dále přetěžovat

ML
Pico
Prolog
Smalltalk

Jazyky v nichž lze definovat nové operátory, navíc je možné přetěžovat i existující operátory

ALGOL 68
Eiffel
Fortran
F#
Haskell
Io
Nim
R
Raku
Scala
Swift

3. Operátory a další speciální znaky v jazyku C3

Vzhledem k tomu, že je jazyk C3 odvozen od standardního céčka, nebude větším překvapením, že i v něm nalezneme poměrně velké množství různých operátorů (vlastně ještě větší množství, než v céčku). Tyto operátory jsou společně s dalšími speciálními znaky vypsány pod tímto odstavcem:

&       @       ~       |       ^       :
,       /       $       .       ;       )
>       <       #       {       }       -
(       )       *       [       ]       %
>=      <=      +       +=      -=      !
?       ?:      &&      ??      &=      |=
^=      /=      ..      ==      ({      })
[<      >]      ++      --      %=      !=
||      ::      <<      >>      !!      ...
<<=     >>=

Ty znaky nebo skupiny znaků, které tvoří operátory, by bylo teoreticky možné všechny přetížit, ovšem tvůrci jazyka C3 omezili množství operátorů, které se mohou přetížit, na:

  • Standardní aritmetické operátory +, -, *, / a %
  • Unární operátory + a –
  • Bitové operátory ^, | a &
  • Porovnání == a !=
  • Bitové posuny << a >>
  • Operátor indexování [] pro čtení a/nebo i zápis
  • Speciální operátor len (viz další text)

Přitom se předpokládá, že operátory budou přetíženy „příčetně“, tj. například při implementaci vlastních numerických typů. Zejména se nedoporučuje přístup jazyka C++, který například přetěžuje operátory << a >> pro operace, které nijak nesouvisí s bitovými posuny. Ostatně právě toto „nepříčetné“ přetěžování operátorů vede k tomu, že je přetěžování operátorů některými vývojáři zamítnuto (což vede k onomu pověstnému vylití dítěte s vaničkou).

Poznámka: povšimněte si zejména absence relačních operátorů.

4. Krátké připomenutí: definice a volání metod v jazyku C3

V jazyce C3 je možné operátory přetížit pouze pro nové uživatelsky definované datové typy. Samotné přetěžování se provádí definicí metod, do jejichž hlaviček je přidána informace o tom, že se kromě definice metody provádí i definice přetíženého operátoru. Proto si v krátkosti připomeňme, jak se vlastně v C3 s metodami pracuje. Co jsou to metody? Jedná se vlastně o funkce vztažené k nějakému datovému typu. Metody je možné volat dvěma rozličnými způsoby, které si oba ukážeme v demonstračních příkladech.

Programátoři, co nesnášíte BS, ale máte rádi business! Y Soft je česká firma s globálním dopadem (100+ zemí, 1M+ uživatelů a >100% meziroční růst). R&D úplně bez manažerů (130 developerů). Otevíráme 30 pozic pro Cloud a AI: Praha/Brno/Ostrava/remote. Zodpovědnost ano, mikro-management ne. Pojď někam, kde můžeš věci změnit.

Y Soft logo

Nejprve si zadefinujeme nějaký uživatelský datový typ. Pro jednoduchost se může jednat o reprezentaci vektoru v 3D prostoru pomocí tří složek (s tímto typem se dnes setkáme ještě mnohokrát):

struct Vector3d
{
    int x;
    int y;
    int z;
}

V případě, že budeme chtít pro tento datový typ definovat novou metodu, například metodu určenou pro součet dvou vektorů, může řešení vypadat následovně. Tato metoda mění (mutuje) první vektor, který je jí předán (a proto musí být předán odkazem):

fn void Vector3d.add(Vector3d* first, Vector3d* second)
{
    first.x += second.x;
    first.y += second.y;
    first.z += second.z;
}
Poznámka: ve skutečnosti nemusí být druhý parametr předáván odkazem (přes ukazatel) ale přímo hodnotou (sami si to vyzkoušejte).

Výše uvedenou metodu můžeme volat tak, jakoby se jednalo o funkci umístěnou ve jmenném prostoru Vector3d:

Vector3d v1 = {1, 2, 3};
Vector3d v2 = {10, 10, 10};
 
Vector3d.add(&v1, &v2);

Celý příklad s definicí metody i s jejím voláním může vypadat následovně:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn void Vector3d.add(Vector3d* first, Vector3d* second)
{
    first.x += second.x;
    first.y += second.y;
    first.z += second.z;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d.add(&v1, &v2);
 
    io::printf("[%d %d %d]\n", v1.x, v1.y, v1.z);
}

Otestování funkcionality tohoto demonstračního příkladu je snadné:

[11 12 13]

Varianta, ve které je druhý vektor předán hodnotou a nikoli odkazem:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn void Vector3d.add(Vector3d* first, Vector3d second)
{
    first.x += second.x;
    first.y += second.y;
    first.z += second.z;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d.add(&v1, v2);
 
    io::printf("[%d %d %d]\n", v1.x, v1.y, v1.z);
}

Ovšem na druhou stranu další demonstrační příklad již funkční nebude, resp. nebude modifikovat první vektor předaný do metody (ale jen jeho kopii)!

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn void Vector3d.add(Vector3d first, Vector3d second)
{
    first.x += second.x;
    first.y += second.y;
    first.z += second.z;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d.add(v1, v2);
 
    io::printf("[%d %d %d]\n", v1.x, v1.y, v1.z);
}

Ve skutečnosti není výše uvedené volání metody:

    Vector3d.add(&v1, &v2);

v mnoha programovacích jazycích příliš idiomatické. Z tohoto důvodu nabízí programovací jazyk C3 i známější a dnes používanější způsob zápisu volání metody:

v1.add(&v2);
Poznámka: povšimněte si, že není nutné rozlišovat, jestli je první parametr metody (příjemce) předán hodnotou nebo odkazem (přes ukazatel).

Pro úplnost si uveďme úplný zdrojový kód demonstračního příkladu upraveného do podoby, ve které se používá idiomatičtější způsob zápisu volání metody:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn void Vector3d.add(Vector3d* first, Vector3d* second)
{
    first.x += second.x;
    first.y += second.y;
    first.z += second.z;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    v1.add(&v2);
 
    io::printf("[%d %d %d]\n", v1.x, v1.y, v1.z);
}

Otestování funkcionality:

[11 12 13]

5. Metoda pro součet vektorů, která vrací nový vektor

Ještě předtím, než si ukážeme, jakým způsobem je možné přetížit nějaký aritmetický operátor (nebo všechny operátory) pro naši datovou strukturu Vector3d, provedeme poslední úpravu metody provádějící součet vektorů. Tato metoda totiž může vracet nový vektor, který vznikne součtem obou vstupních vektorů (operandů). To sice nemusí být příliš efektivní z pohledu využití operační paměti, ovšem jedná se o velmi idiomatický způsob implementace:

fn Vector3d Vector3d.add(Vector3d first, Vector3d second)
{
    Vector3d result;
    result.x = first.x + second.x;
    result.y = first.y + second.y;
    result.z = first.z + second.z;
    return result;
}

Volání této metody:

Vector3d v1 = {1, 2, 3};
Vector3d v2 = {10, 10, 10};
 
Vector3d v3 = Vector3d.add(v1, v2);

Tento způsob volání je ukázán v dalším demonstračním příkladu:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn Vector3d Vector3d.add(Vector3d first, Vector3d second)
{
    Vector3d result;
    result.x = first.x + second.x;
    result.y = first.y + second.y;
    result.z = first.z + second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d v3 = Vector3d.add(v1, v2);
 
    io::printf("[%d %d %d]\n", v3.x, v3.y, v3.z);
}

Ovšem (jak již víme z předchozích kapitol) je možné metodu add volat i odlišným způsobem:

Vector3d v1 = {1, 2, 3};
Vector3d v2 = {10, 10, 10};
 
Vector3d v3 = v1.add(v2);

Opět si pro úplnost ukažme, jak vypadá celý zdrojový kód takto upraveného příkladu:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn Vector3d Vector3d.add(Vector3d first, Vector3d second)
{
    Vector3d result;
    result.x = first.x + second.x;
    result.y = first.y + second.y;
    result.z = first.z + second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d v3 = v1.add(v2);
 
    io::printf("[%d %d %d]\n", v3.x, v3.y, v3.z);
}

6. Přetížení operátoru + tak, aby se provedl součet dvou vektorů

Nyní se již konečně dostáváme k přetěžování operátorů. Ve skutečnosti je to v našem případě velmi snadné, protože stačí do původní definici metody add:

fn Vector3d Vector3d.add(Vector3d first, Vector3d second)
{
    Vector3d result;
    result.x = first.x + second.x;
    result.y = first.y + second.y;
    result.z = first.z + second.z;
    return result;
}

Přidat dekorátor, který překladač jazyka C3 „donutí“ přetížit operátor +:

fn Vector3d Vector3d.add(Vector3d first, Vector3d second) @operator(+)
{
    Vector3d result;
    result.x = first.x + second.x;
    result.y = first.y + second.y;
    result.z = first.z + second.z;
    return result;
}

Použití nového operátoru je již zcela idiomatické:

Vector3d v1 = {1, 2, 3};
Vector3d v2 = {10, 10, 10};
 
Vector3d v3 = v1 + v2;

Opět si ukažme celý zdrojový kód takto upraveného demonstračního příkladu:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn Vector3d Vector3d.add(Vector3d first, Vector3d second) @operator(+)
{
    Vector3d result;
    result.x = first.x + second.x;
    result.y = first.y + second.y;
    result.z = first.z + second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d v3 = v1 + v2;
 
    io::printf("[%d %d %d]\n", v3.x, v3.y, v3.z);
}

7. Předání operandů hodnotou nebo odkazem?

Většinou se v definicích metod, které současně přetěžují nějaký aritmetický (binární) operátor, setkáme s tím, že prvním parametrem metody je levý operand popř. reference na tento operand (tedy adresa). To, zda budeme předávat hodnotu nebo referenci, se projevuje pouze na zápisu hlavičky metody, protože její nepřímé volání (přes operand) zůstane naprosto stejné. Ostatně postačuje se podívat na následující dvojici demonstračních příkladů, které se od sebe odlišují pouze hlavičkou metody add:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn Vector3d Vector3d.add(self, Vector3d second) @operator(+)
{
    Vector3d result;
    result.x = self.x + second.x;
    result.y = self.y + second.y;
    result.z = self.z + second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d v3 = v1 + v2;
 
    io::printf("[%d %d %d]\n", v3.x, v3.y, v3.z);
}

Prakticky totožný zápis, ovšem první parametr je do metody předáván odkazem a nikoli hodnotou:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn Vector3d Vector3d.add(&self, Vector3d second) @operator(+)
{
    self.x += second.x;
    self.y += second.y;
    self.z += second.z;
    return *self;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d v3 = v1 + v2;
 
    io::printf("[%d %d %d]\n", v3.x, v3.y, v3.z);
}

8. Několikanásobné přetížení stejného operátoru: přičtení skalární hodnoty vs součet vektorů

V některých případech se setkáme s požadavkem přetížení nějakého operátoru tak, aby na pravé straně akceptoval operandy různého typu. Příkladem může být požadavek, aby bylo možné k našemu vektoru v prostoru přičíst buď skalární hodnotu nebo další vektor. V jazyku C3 je to možné, protože volání metody lze odlišit na základě jejího jména (pochopitelně), přičemž metody odlišných jmen mohou akceptovat odlišné typy parametrů. Ovšem i u dvou metod s odlišným jménem (a odlišnými typy parametrů) lze dekorátorem dopsat přetížení toho stejného operátoru. Můžeme tedy implementovat dvě varianty operátoru +:

fn Vector3d Vector3d.add_scalar(self, int scalar) @operator(+)
    ...
    ...
    ...

a současně:

fn Vector3d Vector3d.add_vector(self, Vector3d second) @operator(+)
    ...
    ...
    ...

Chování takto přetíženého operátoru si můžeme snadno ověřit pokusem o součet vektorů popř. o přičtení skalární hodnoty k vektoru:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn Vector3d Vector3d.add_scalar(self, int scalar) @operator(+)
{
    Vector3d result;
    result.x = self.x + scalar;
    result.y = self.y + scalar;
    result.z = self.z + scalar;
    return result;
}
 
fn Vector3d Vector3d.add_vector(self, Vector3d second) @operator(+)
{
    Vector3d result;
    result.x = self.x + second.x;
    result.y = self.y + second.y;
    result.z = self.z + second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d v3 = v1 + v2;
 
    io::printf("[%d %d %d]\n", v3.x, v3.y, v3.z);
 
    Vector3d v4 = v3 + 100;
    io::printf("[%d %d %d]\n", v4.x, v4.y, v4.z);
}

Výsledky ukazují, že vše funguje podle očekávání:

[11 12 13]
[111 112 113]

9. Přetížení operátoru „zleva“ nebo „zprava“

V demonstračním příkladu z předchozí kapitoly jsme přičítali skalární hodnotu k vektoru, což znamenalo, že se vektor nacházel na levé straně přetíženého operátoru +, zatímco skalární hodnota se nacházela na jeho pravé straně:

Vector3d v4 = v3 + 100;

Co se ovšem stane v případě, že oba operandy prohodíme? V tomto případě bude první operand typu celé číslo a druhý operand typu Vector3d:

Vector3d v4 = 100 + v3;

Můžeme si to vyzkoušet pokusem o překlad následujícího příkladu:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn Vector3d Vector3d.add_scalar(self, int scalar) @operator(+)
{
    Vector3d result;
    result.x = self.x + scalar;
    result.y = self.y + scalar;
    result.z = self.z + scalar;
    return result;
}
 
fn Vector3d Vector3d.add_vector(self, Vector3d second) @operator(+)
{
    Vector3d result;
    result.x = self.x + second.x;
    result.y = self.y + second.y;
    result.z = self.z + second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d v3 = v1 + v2;
 
    io::printf("[%d %d %d]\n", v3.x, v3.y, v3.z);
 
    Vector3d v4 = 100 + v3;
    io::printf("[%d %d %d]\n", v4.x, v4.y, v4.z);
}

Překladač jazyka C3 v tomto případě ohlásí problém, protože není, jakou metodu by měl pro vyžadovaný součet zavolat:

 35:
 36:     io::printf("[%d %d %d]\n", v3.x, v3.y, v3.z);
 37:
 38:     Vector3d v4 = 100 + v3;
                       ^^^^^^^^
(/tmp/ramdisk/c3c/build/add_operator_7.c3:38:19) Error: Cannot do the addition 'int' + 'Vector3d'.

Řešením může být doplnění původní implementace operátoru +:

fn Vector3d Vector3d.add_scalar(self, int scalar) @operator(+)
...
...
...

Za implementaci „otočeného“ operátoru +. Povšimněte si, že nyní namísto dekorátoru @operator použijeme dekorátor @operator_r, kde _r můžeme číst jako reverse:

fn Vector3d Vector3d.add_scalar_r(self, int scalar) @operator_r(+)
...
...
...

Celý zdrojový kód příkladu doplněného o nový „převrácený“ operátor vypadá následovně:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn Vector3d Vector3d.add_scalar(self, int scalar) @operator(+)
{
    Vector3d result;
    result.x = self.x + scalar;
    result.y = self.y + scalar;
    result.z = self.z + scalar;
    return result;
}
 
fn Vector3d Vector3d.add_scalar_r(self, int scalar) @operator_r(+)
{
    Vector3d result;
    result.x = self.x + scalar;
    result.y = self.y + scalar;
    result.z = self.z + scalar;
    return result;
}
 
fn Vector3d Vector3d.add_vector(self, Vector3d second) @operator(+)
{
    Vector3d result;
    result.x = self.x + second.x;
    result.y = self.y + second.y;
    result.z = self.z + second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d v3 = v1 + v2;
 
    io::printf("[%d %d %d]\n", v3.x, v3.y, v3.z);
 
    Vector3d v4 = 100 + v3;
    io::printf("[%d %d %d]\n", v4.x, v4.y, v4.z);
}

Nyní bude možné příklad bez problémů přeložit a spustit:

$ ./c3c compile-run add_operator_8.c3
Program linked to executable './operator_overloading'.
Launching ./operator_overloading
[11 12 13]
[111 112 113]

10. Symetrická varianta přetíženého operátoru součtu

Současná definice přetíženého operátoru + v jeho původní variantě vektor+další_hodnota i v převrácené variantě další_hodnota+vektor je sice v některých případech nutná, ovšem pokud má být implementovaná operace komutativní, je dvojí definice spíše kontraproduktivní (prakticky se totiž opakuje totožný kód, pouze se prohodí parametry metody). Z tohoto důvodu programovací jazyk C3 podporuje „symetrickou“ variantu přetíženého operátoru, která se definuje nikoli pomocí @operator ani @operator_r, ale s využitím dekorátoru @operator_s (suffix s je odvozen od slova symmetric). Pokud je operátor přetížen tímto dekorátorem, bude funkční jak ve své přímé, tak i „převrácené“ variantě.

To tedy znamená, že operátor určený pro přičtení skaláru k vektoru nebo vektoru ke skaláru lze definovat jedinou metodou:

fn Vector3d Vector3d.add_scalar(self, int scalar) @operator_s(+)

Otestujme si to na následujícím demonstračním příkladu, který provede dvě varianty součtu: vektor+vektor (ten je vždy symetrický) a skalár+vektor:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn Vector3d Vector3d.add_scalar(self, int scalar) @operator_s(+)
{
    Vector3d result;
    result.x = self.x + scalar;
    result.y = self.y + scalar;
    result.z = self.z + scalar;
    return result;
}
 
fn Vector3d Vector3d.add_vector(self, Vector3d second) @operator(+)
{
    Vector3d result;
    result.x = self.x + second.x;
    result.y = self.y + second.y;
    result.z = self.z + second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    Vector3d v3 = v1 + v2;
 
    io::printf("[%d %d %d]\n", v3.x, v3.y, v3.z);
 
    Vector3d v4 = 100 + v3;
    io::printf("[%d %d %d]\n", v4.x, v4.y, v4.z);
}

Výsledky:

$ ./c3c compile-run add_operator_9.c3 
Program linked to executable './operator_overloading'.
Launching ./operator_overloading
[11 12 13]
[111 112 113]

11. Přetížení unárního operátoru – (otočení znaménka)

Nyní již umíme realizovat přetížení binárního operátoru (například součtu). Jak se ovšem postupuje v případě, že je zapotřebí přetížit nějaký operátor unární? Typicky se bude jednat o unární operátor -, který (pokud to pro datovou strukturu dává smysl) otáčí znaménko.

Implementace je vlastně velmi jednoduchá, protože stačí nadefinovat metodu s jediným parametrem (self nebo reference na self) a přidat dekorátor pro operátor -. Nemusíme pochopitelně řešit ani „otočenou“ variantu operátorů (s prohozenými operandy) ani jeho symetrickou variantu. Metoda vrátí novou strukturu s převráceným znaménkem:

fn Vector3d Vector3d.unary_minus(self) @operator(-)
{
    Vector3d result;
    result.x = -self.x;
    result.y = -self.y;
    result.z = -self.z;
    return result;
}

Celý demonstrační příklad i s realizací přetíženého unárního operátoru – vypadá následovně:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn Vector3d Vector3d.unary_minus(self) @operator(-)
{
    Vector3d result;
    result.x = -self.x;
    result.y = -self.y;
    result.z = -self.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
 
    io::printf("[%d %d %d]\n", v1.x, v1.y, v1.z);
 
    Vector3d v2 = -v1;
    io::printf("[%d %d %d]\n", v2.x, v2.y, v2.z);
}

Vše si pochopitelně otestujeme:

$ ./c3c compile-run unary_minus.c3
 
[1 2 3]
[-1 -2 -3]

12. Přetížení operátoru pro porovnání dvou hodnot (rovnost)

Dalším operátorem, který je nutné velmi často přetížit, je operátor rovnosti (nebo nerovnosti). Ten může být realizován metodou se dvěma parametry vracející hodnotu typu bool. Metoda je označena pomocí dekorátoru @operator(==):

fn bool Vector3d.compare(self, Vector3d second) @operator(==)
{
    bool result;
    result = self.x == second.x;
    result &= self.y == second.y;
    result &= self.z == second.z;
    return result;
}
Poznámka: automaticky se doplní i přetížený operátor nerovnosti, který vrací negovanou hodnotu rovnosti. Pokud vyžadujete odlišné chování (což je ovšem zvláštní), je možné explicitně přetížit i !=.

Vyzkoušejme si, jak dopadnou výsledky porovnání dvojice vektorů na rovnost i na nerovnost:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn bool Vector3d.compare(self, Vector3d second) @operator(==)
{
    bool result;
    result = self.x == second.x;
    result &= self.y == second.y;
    result &= self.z == second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
    Vector3d v3 = {10, 10, 10};
 
    io::printf("v1 == v2: %b\n", v1 == v2);
    io::printf("v1 == v3: %b\n", v1 == v3);
    io::printf("v2 == v3: %b\n", v2 == v3);
 
    io::printf("v1 != v2: %b\n", v1 != v2);
    io::printf("v1 != v3: %b\n", v1 != v3);
    io::printf("v2 != v3: %b\n", v2 != v3);
}

Ze zobrazených výsledků je patrné, že i když je přetížen pouze operátor ==, lze pro porovnání dvou vektorů použít i operátor !=:

$ ./c3c compile-run equality_operator.c3
 
v1 == v2: 0
v1 == v3: 0
v2 == v3: 1
v1 != v2: 1
v1 != v3: 1
v2 != v3: 0

13. Přetížení operátoru pro součin tak, aby se prováděl skalární součin dvou vektorů

V dalším demonstračním příkladu se ještě na chvíli vrátíme k binárním aritmetickým operátorům. Přetížíme operátor *, který provede skalární součin dvou vektorů, tj. oba operandy budou typu Vector3d a výsledkem bude skalární hodnota. To je pochopitelně v jazyce C3 zcela legální realizace přetížení:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn int Vector3d.dot_product(self, Vector3d second) @operator(*)
{
    int result;
    result = self.x * second.x;
    result += self.y * second.y;
    result += self.z * second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    int dp = v1 * v2;
    io::printf("%d\n", dp);
}

Výsledek výpočtu skalárního součinu obou vektorů:

60

Vzhledem k tomu, že budeme chtít co nejvíce optimální realizaci výpočtu skalárního součinu, můžeme do metody Vector3d.dot_product předávat jeden nebo oba parametry referencí, nikoli hodnotou. Odlišovat se bude hlavička metody, nikoli její tělo (a už vůbec ne volání operátoru):

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn int Vector3d.dot_product(&self, Vector3d second) @operator(*)
{
    int result;
    result = self.x * second.x;
    result += self.y * second.y;
    result += self.z * second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    int dp = v1 * v2;
    io::printf("%d\n", dp);
}

Opět si otestujme funkcionalitu takto upraveného příkladu:

60

14. Vynásobení složek vektoru skalární konstantou versus skalární součin vektorů

Pokusme se nyní zadání ztížit: budeme chtít realizovat jak skalární součin, tak i vynásobení vektoru skalární hodnotou, což jsou dvě zcela odlišné operace. Díky tomu, že každá operace součinu bude definována v odlišné metodě (liší se jejich jména, parametry, i návratový typ), je možné oba operátory celkem bez problémů přetížit (zapisovat se budou stejným znakem). Navíc můžeme násobení vektoru skalárem realizovat symetrickým operátorem, aby bylo možné provádět jak výpočet vektor*skalár, tak i skalár*vektor:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn Vector3d Vector3d.mul_scalar(&self, int scalar) @operator_s(*)
{
    Vector3d result;
    result.x = self.x * scalar;
    result.y = self.y * scalar;
    result.z = self.z * scalar;
    return result;
}
 
fn int Vector3d.dot_product(&self, Vector3d second) @operator(*)
{
    int result;
    result = self.x * second.x;
    result += self.y * second.y;
    result += self.z * second.z;
    return result;
}
 
fn void main()
{
    Vector3d v1 = {1, 2, 3};
    Vector3d v2 = {10, 10, 10};
 
    int dp = v1 * v2;
    io::printf("%d\n", dp);
 
    Vector3d v3 = v1 * 2;
    io::printf("[%d %d %d]\n", v3.x, v3.y, v3.z);
 
    Vector3d v4 = 2 * v2;
    io::printf("[%d %d %d]\n", v4.x, v4.y, v4.z);
}

Z výsledků je patrné, že všechny tři operace jsou definovány:

60            // skalární součin
[2 4 6]       // vektor*skalár
[20 20 20]    // skalár*vektor

15. Další operátory, které je možné přetížit

V rámci předchozích kapitol jsme si ukázali, jakým způsobem je možné přetížit standardní aritmetické operátory, a to jak jejich binární varianty (se dvěma operandy), tak i unární varianty (s jedním operandem). Taktéž jsme si ukázali realizaci operátoru ==. Ovšem programovací jazyk C3 neumožňuje přetěžovat další relační operátory ani například operátory určené pro zvýšení či snížení hodnoty o jedničku (což je možná rozumné rozhodnutí).

Přetížit je možné i operátory indexování [] (pro čtení a/nebo zápis) a navíc i speciální operátor len využitý při realizaci počítaných smyček atd. V dalších kapitolách se zaměříme právě na tyto operátory.

16. Přetížení operátoru pro výběr prvku pro čtení pomocí indexu

V dalším demonstračním příkladu přetížíme (možná poněkud uměle) operátor [] v jeho variantě určené pro čtení prvků vektoru. Tento operátor umožní pro první prvek vektoru použít index 0, pro druhý prvek index 1 atd. Ovšem stále se bude jednat pouze o čtení hodnoty prvku vektoru, nikoli o jejich zápis.

Naivní implementace (bez korektní kontroly chybného indexu) může vypadat následovně:

fn int Vector3d.get(self, usz i) @operator([])
{
    switch (i) {
        case 0: return self.x;
        case 1: return self.y;
        case 2: return self.z;
        default: return 0;
    }
}

Otestujme si, zda je indexování realizováno korektně:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn int Vector3d.get(self, usz i) @operator([])
{
    switch (i) {
        case 0: return self.x;
        case 1: return self.y;
        case 2: return self.z;
        default: return 0;
    }
}
 
fn void main()
{
    Vector3d v1 = {10, 20, 30};
 
    for (int i=0; i<=3; i++) {
        io::printf("v1[%d] = %d\n", i, v1[i]);
    }
}

Výsledky vypadají rozumně (i pro nekorektní index):

v1[0] = 10
v1[1] = 20
v1[2] = 30
v1[3] = 0

Samozřejmě i v tomto případě je možné do metody Vector3d.get předávat vektor odkazem (referencí) a nikoli hodnotou (tedy kopií):

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn int Vector3d.get(&self, usz i) @operator([])
{
    switch (i) {
        case 0: return self.x;
        case 1: return self.y;
        case 2: return self.z;
        default: return 0;
    }

}
 
fn void main()
{
    Vector3d v1 = {10, 20, 30};
 
    for (int i=0; i<=3; i++) {
        io::printf("v1[%d] = %d\n", i, v1[i]);
    }
}

Výsledky budou opět korektní:

v1[0] = 10
v1[1] = 20
v1[2] = 30
v1[3] = 0

17. Klíč ve formě řetězce namísto celočíselného indexu, přetížení přiřazení

Operátor indexování ovšem může být přetížen i takovým způsobem, že se namísto celočíselného indexu použije klíč. Opět si ukažme (umělý) příklad, ve kterém umožníme prvky vektoru vybírat s využitím klíčů „x“, „y“ nebo „z“. Tato varianta přetíženého operátoru bude využitelnější například tehdy, pokud se bude implementovat nějaká forma slovníku atd.:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn int Vector3d.get(&self, String key) @operator([])
{
    switch (key) {
        case "x": return self.x;
        case "y": return self.y;
        case "z": return self.z;
        default: return 0;
    }
}
 
fn void main()
{
    Vector3d v1 = {10, 20, 30};

    io::printf("v1[x] = %d\n", v1["x"]);
    io::printf("v1[y] = %d\n", v1["y"]);
    io::printf("v1[z] = %d\n", v1["z"]);
}

Otestování ukazuje, že je vše korektní:

v1[x] = 10
v1[y] = 20
v1[z] = 30

V dalším demonstračním příkladu je navíc přetížen i operátor indexování pro zápis, tj. pro přiřazení nové hodnoty do vybraného prvku. Tento operátor se (v době přetížení) jmenuje []=. Pro zajímavost budeme opět implementovat variantu tohoto operátoru s klíči „x“, „y“ a „z“ a nikoli s celočíselnými indexy:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn int Vector3d.get(&self, String key) @operator([])
{
    switch (key) {
        case "x": return self.x;
        case "y": return self.y;
        case "z": return self.z;
        default: return 0;
    }
}
 
fn void Vector3d.set(&self, String key, int new_value) @operator([]=)
{
    switch (key) {
        case "x": self.x=new_value;
        case "y": self.y=new_value;
        case "z": self.z=new_value;
    }
}
 
fn void main()
{
    Vector3d v1 = {10, 20, 30};
 
    io::printf("v1[x] = %d\n", v1["x"]);
    io::printf("v1[y] = %d\n", v1["y"]);
    io::printf("v1[z] = %d\n", v1["z"]);
 
    v1["x"] = 100;
    v1["y"] = 200;
    v1["z"] = 300;
 
    io::printf("v1[x] = %d\n", v1["x"]);
    io::printf("v1[y] = %d\n", v1["y"]);
    io::printf("v1[z] = %d\n", v1["z"]);
}

Otestování funkcionality:

v1[x] = 10
v1[y] = 20
v1[z] = 30
 
v1[x] = 100
v1[y] = 200
v1[z] = 300

18. Přetížení speciálního operátoru len

Poslední operátor, který se v dnešním článku pokusíme přetížit, se jmenuje len. V našem konkrétním případě bude tento operátor vracet konstantní hodnotu 3 (protože náš vektor má tři složky):

fn usz Vector3d.len(&self) @operator(len)
{
    return 3;
}

Tento operátor se, společně s přetíženým operátorem indexování, používá pro implementaci programových smyček typu for-each. Operátor len vrací počet iterací a interně se bude volat operátor pro indexování (výběr/čtení) prvků:

foreach (item : v1)
{
    io::printf("%d ", item);
}
io::printn();

Opět si vše otestujeme:

module operator_overloading;
import std::io;
 
struct Vector3d
{
    int x;
    int y;
    int z;
}
 
fn int Vector3d.get(&self, usz i) @operator([])
{
    switch (i) {
        case 0: return self.x;
        case 1: return self.y;
        case 2: return self.z;
        default: return 0;
    }
}
 
fn void Vector3d.set(&self, usz i, int new_value) @operator([]=)
{
    switch (i) {
        case 0: self.x=new_value;
        case 1: self.y=new_value;
        case 2: self.z=new_value;
    }
}
 
fn usz Vector3d.len(&self) @operator(len)
{
    return 3;
}
 
fn void main()
{
    Vector3d v1 = {10, 20, 30};
 
    foreach (item : v1)
    {
        io::printf("%d ", item);
    }
    io::printn();
 
    v1[0] = 100;
    v1[1] = 200;
    v1[2] = 300;
 
    foreach (item : v1)
    {
        io::printf("%d ", item);
    }
    io::printn();
}

Výsledek ukazuje, že je skutečně možné naším vektorem „procházet“ prvek po prvku:

10 20 30
100 200 300

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 ze čtvrtého 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

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

# 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

Následují odkazy na demonstrační příklady z článku předchozího:

# Příklad Stručný popis Adresa
100 01_regular_function.c3 deklarace běžných funkcí v jazyku C3 https://github.com/tisnik/c3-examples/blob/master/c3-functions/01_regular_function.c3
101 02_check_arguments.c3 kontrola parametrů předávaných do funkce překladačem jazyka C3 https://github.com/tisnik/c3-examples/blob/master/c3-functions/02_check_arguments.c3
       
102 03_default_arguments.c3 funkce s jedním parametrem, který má nastavenou výchozí hodnotu a jedním běžným parametrem (korektní pořadí parametrů) https://github.com/tisnik/c3-examples/blob/master/c3-functions/03_default_arguments.c3
103 04_default_arguments.c3 funkce se všemi parametry s nastavenu výchozí hodnotou https://github.com/tisnik/c3-examples/blob/master/c3-functions/04_default_arguments.c3
104 05_default_arguments.c3 funkce s jedním parametrem, který má nastavenou výchozí hodnotu a jedním běžným parametrem (nekorektní pořadí parametrů) https://github.com/tisnik/c3-examples/blob/master/c3-functions/05_default_arguments.c3
       
105 06_named_arguments.c3 explicitní uvedení jmen parametrů při volání funkce https://github.com/tisnik/c3-examples/blob/master/c3-functions/06_named_arguments.c3
106 07_named_arguments.c3 explicitní uvedení jmen parametrů při volání funkce https://github.com/tisnik/c3-examples/blob/master/c3-functions/07_named_arguments.c3
107 08_named_default_arguments.c3 pojmenování parametrů s výchozí hodnotou při volání funkce https://github.com/tisnik/c3-examples/blob/master/c3-functions/08_named_default_ar­guments.c3
       
108 09_sum.c3 realizace funkce pro výpočet součtu všech předaných hodnot https://github.com/tisnik/c3-examples/blob/master/c3-functions/09_sum.c3
109 10_sum.c3 předání obsahu pole do funkce s proměnným počtem parametrů https://github.com/tisnik/c3-examples/blob/master/c3-functions/10_sum.c3
110 11_varargs.c3 pořadí předávání parametrů do funkce s proměnným počtem parametrů (nekorektní způsob použití) https://github.com/tisnik/c3-examples/blob/master/c3-functions/11_varargs.c3
111 12_varargs.c3 pořadí předávání parametrů do funkce s proměnným počtem parametrů (korektní způsob použití) https://github.com/tisnik/c3-examples/blob/master/c3-functions/12_varargs.c3
       
112 13_optional.c3 funkce vracející hodnotu typu Optional https://github.com/tisnik/c3-examples/blob/master/c3-functions/13_optional.c3
113 14_optional.c3 využití operátoru ?? https://github.com/tisnik/c3-examples/blob/master/c3-functions/14_optional.c3
       
114 15_contract.c3 kontrakty uvedené u funkcí https://github.com/tisnik/c3-examples/blob/master/c3-functions/15_contract.c3
115 16_contract.c3 kontrakty uvedené u funkcí https://github.com/tisnik/c3-examples/blob/master/c3-functions/16_contract.c3
       
116 17_c_declaration.c3 deklarace funkce bez parametrů „céčkovým způsobem“ (nekorektní zápis) https://github.com/tisnik/c3-examples/blob/master/c3-functions/17_c_declaration.c3
117 18_check_return_type.c3 kontrola návratové hodnoty překladačem jazyka C3 https://github.com/tisnik/c3-examples/blob/master/c3-functions/18_check_return_type.c3
118 19_check_return_value.c3 kontrola počtu návratových hodnot překladačem jazyka C3 https://github.com/tisnik/c3-examples/blob/master/c3-functions/19_check_return_value.c3
119 20_in_out_params.c3 předání ukazatelů do volané funkce https://github.com/tisnik/c3-examples/blob/master/c3-functions/20_in_out_params.c3
120 21_in_out_params.c3 označení ukazatelů kontrakty [in] a [out] https://github.com/tisnik/c3-examples/blob/master/c3-functions/21_in_out_params.c3
121 22_in_out_params.c3 označení ukazatelů kontrakty [in] a [out] https://github.com/tisnik/c3-examples/blob/master/c3-functions/22_in_out_params.c3
122 23_void_pointer.c3 předávání ukazatelů typu void * do volané funkce https://github.com/tisnik/c3-examples/blob/master/c3-functions/23_void_pointer.c3
123 24_contract.c3 kontrakt zapsaný před hlavičkou funkce https://github.com/tisnik/c3-examples/blob/master/c3-functions/24_contract.c4

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

# Příklad Stručný popis Adresa
124 25_function_type.c3 definice nového datového typu „funkce“ https://github.com/tisnik/c3-examples/blob/master/c3-functions/25_function_type.c3
       
125 26_short_function.c3 zkrácený způsob zápisu běžné funkce https://github.com/tisnik/c3-examples/blob/master/c3-functions/26_short_function.c3
126 27_short_default_argument.c3 zkrácený způsob zápisu funkce s výchozí hodnotou parametru https://github.com/tisnik/c3-examples/blob/master/c3-functions/27_short_default_argument.c3
127 28_short_default_argument.c3 zkrácený způsob zápisu funkce s výchozí hodnotou parametrů https://github.com/tisnik/c3-examples/blob/master/c3-functions/28_short_default_argument.c3
128 29_short_named_argument.c3 zkrácený způsob zápisu funkce, při jejím volání jsou explicitně uvedena jména parametrů https://github.com/tisnik/c3-examples/blob/master/c3-functions/29_short_named_argument.c3
129 30_short_first.c3 zkrácený způsob zápisu funkce akceptující proměnný počet parametrů https://github.com/tisnik/c3-examples/blob/master/c3-functions/30_short_first.c3
130 31_short_ternary.c3 zkrácený způsob zápisu funkce, která ve svém těle vyžaduje ternární operátor https://github.com/tisnik/c3-examples/blob/master/c3-functions/31_short_ternary.c3
       
131 32_anonymous.c3 příklad, v němž jsou definovány dvě logicky podobné funkce https://github.com/tisnik/c3-examples/blob/master/c3-functions/32_anonymous.c3
132 33_anonymous.c3 využití anonymních funkcí namísto dvojice logicky podobných funkcí https://github.com/tisnik/c3-examples/blob/master/c3-functions/33_anonymous.c3
133 34_anonymous.c3 definice a zavolání anonymní funkce provedené na jediném řádku zdrojového kódu https://github.com/tisnik/c3-examples/blob/master/c3-functions/34_anonymous.c3
134 35_anonymous.c3 pokus o definici uzávěru (closure) https://github.com/tisnik/c3-examples/blob/master/c3-functions/35_anonymous.c3
       
135 36_function_pointers.c3 předání ukazatele na funkce https://github.com/tisnik/c3-examples/blob/master/c3-functions/36_function_pointers.c3
136 37_function_pointers.c3 předání ukazatele na funkce (zkrácený zápis funkce) https://github.com/tisnik/c3-examples/blob/master/c3-functions/37_function_pointers.c3
137 38_return_function.c3 funkce vracející jinou funkci https://github.com/tisnik/c3-examples/blob/master/c3-functions/38_return_function.c3
       
138 39_call_c_function.c3 volání standardní céčkové funkce puts https://github.com/tisnik/c3-examples/blob/master/c3-functions/39_call_c_function.c3
139 40_call_c_function.c3 volání nativní céčkové funkce add https://github.com/tisnik/c3-examples/blob/master/c3-functions/40_call_c_function.c3
140 41_call_c_function.c3 volání nativní céčkové funkce multiply s korektními datovými typy https://github.com/tisnik/c3-examples/blob/master/c3-functions/41_call_c_function.c3
141 42_call_c_function.c3 volání nativní céčkové funkce akceptující pole (první způsob) https://github.com/tisnik/c3-examples/blob/master/c3-functions/42_call_c_function.c3
142 43_call_c_function.c3 volání nativní céčkové funkce akceptující pole (druhý způsob) https://github.com/tisnik/c3-examples/blob/master/c3-functions/43_call_c_function.c3
141 42_call_c_function.c3 volání nativní céčkové funkce akceptující pole (první způsob) https://github.com/tisnik/c3-examples/blob/master/c3-functions/42_call_c_function.c3
       
143 44_method.c3 zavolání metody (první způsob) https://github.com/tisnik/c3-examples/blob/master/c3-functions/44_method.c3
144 45_method.c3 zavolání metody (druhý způsob) https://github.com/tisnik/c3-examples/blob/master/c3-functions/45_method.c3

Příklady z článku s popisem makrosystému jazyka C3:

# Příklad Stručný popis Adresa
145 01_add_macro.c3 jednoduché makro, které může být expandováno v rámci výrazu https://github.com/tisnik/c3-examples/blob/master/c3-macros/01_add_macro.c3
146 02_add_macro.c3 makro je generické, lze použít s hodnotami různých typů https://github.com/tisnik/c3-examples/blob/master/c3-macros/02_add_macro.c3
       
147 03_macro_expansion1.c expanze makro provedená preprocesorem jazyka C (parametry nejsou uzávorkovány) https://github.com/tisnik/c3-examples/blob/master/c3-macros/03_macro_expansion1.c
148 03_macro_expansion2.c expanze makro provedená preprocesorem jazyka C (parametry jsou uzávorkovány) https://github.com/tisnik/c3-examples/blob/master/c3-macros/03_macro_expansion2.c
149 03_macro_expansion.c3 řešení v jazyku C3 bez nutnosti uzávorkování parametrů makra https://github.com/tisnik/c3-examples/blob/master/c3-macros/03_macro_expansion.c3
150 04_macro_expansion1.c expanze makro provedená preprocesorem jazyka C (tělo makra není v závorkách) https://github.com/tisnik/c3-examples/blob/master/c3-macros/04_macro_expansion1.c
151 04_macro_expansion2.c expanze makro provedená preprocesorem jazyka C (tělo makra je v závorkách) https://github.com/tisnik/c3-examples/blob/master/c3-macros/04_macro_expansion2.c
152 04_macro_expansion.c3 řešení v jazyku C3 bez nutnosti zápisu těla makra do závorek https://github.com/tisnik/c3-examples/blob/master/c3-macros/04_macro_expansion.c3
       
153 05_typed_macro.c3 makro s definicí typů parametrů https://github.com/tisnik/c3-examples/blob/master/c3-macros/05_typed_macro.c3
154 06_typed_macro.c3 makro s definicí typů parametrů: příklad jeho expanze https://github.com/tisnik/c3-examples/blob/master/c3-macros/06_typed_macro.c3
       
155 07_compile_time1.c3 expanze makra v čase překladu: nefunkční varianta s konstantami https://github.com/tisnik/c3-examples/blob/master/c3-macros/07_compile_time1.c3
156 08_compile_time2.c3 expanze makra v čase překladu: funkční varianta s konstantami https://github.com/tisnik/c3-examples/blob/master/c3-macros/08_compile_time2.c3
157 09_compile_time3.c3 expanze makra v čase překladu: nefunkční varianta s proměnnými https://github.com/tisnik/c3-examples/blob/master/c3-macros/09_compile_time3.c3
       
158 10_swap_macro1.c3 realizace makra pro prohození obsahu dvou proměnných: nefunkční varianta https://github.com/tisnik/c3-examples/blob/master/c3-macros/10_swap_macro1.c3
159 11_swap_macro2.c3 realizace makra pro prohození obsahu dvou proměnných: funkční varianta https://github.com/tisnik/c3-examples/blob/master/c3-macros/11_swap_macro2.c3
       
160 12_varargs.c3 makro s proměnným počtem argumentů https://github.com/tisnik/c3-examples/blob/master/c3-macros/12_varargs.c3

Demonstrační příklady uvedené v minulém článku s popisem nedefinovaného chování v C3:

# Příklad Stručný popis Adresa
161 01_div_by_zero.c3 nedefinované chování při dělení nulou https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/01_div_by_zero.c3
162 02_mod_by_zero.c3 nedefinované chování při výpočtu zbytku po dělení nulou https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/02_mod_by_zero.c3
163 03_min_int1.c3 změna znaménka nejmenší celočíselné hodnoty (daného typu) se znaménkem https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/03_min_int1.c3
164 04_min_int2.c3 změna znaménka nejmenší celočíselné hodnoty operací součinu https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/04_min_int2.c3
165 05_undefined_value.c3 nedefinované hodnoty lokálních konstant v různých režimech překladu https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/05_undefined_value.c3
166 06_out_of_bounds1.c3 přístup k prvku pole s indexem, který přesahuje meze pole https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/06_out_of_bounds1.c3
167 07_out_of_bounds2.c3 přístup k prvku pole s indexem, který přesahuje meze pole https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/07_out_of_bounds2.c3
168 08_null_pointer.c3 přístup do paměti přes nulový ukazatel https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/08_null_pointer.c3
169 09_contract.c3 nedodržení specifikovaného kontraktu: podmínka pro vstupní parametry https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/09_contract.c3
170 10_contract.c3 nedodržení specifikovaného kontraktu: podmínka pro výslednou hodnotu https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/10_contract.c3
171 11_out_of_bounds_slice.c3 překročení meze u řezů (slice) https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/11_out_of_bounds_slice.c3
172 12_local_variable_pointer.c přístup k lokální proměnné mimo oblast její platnosti (příklad v C) https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/12_local_variable_pointer.c
173 12_local_variable_pointer.c3 přístup k lokální proměnné mimo oblast její platnosti (příklad v C3) https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/12_local_variable_pointer.c3
174 13_div_by_minus_one.c3 změna znaménka nejmenší celočíselné hodnoty operací podílu https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/13_div_by_minus_one.c3
175 14_signed_overflow.c3 přetečení celočíselné hodnoty se znaménkem https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/14_signed_overflow.c3
176 15_negative_shift.c3 bitový posun o zápornou hodnotu https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/15_negative_shift.c3
177 16_large_shift.c3 bitový posun o hodnotu přesahující bitovou šířku operandu https://github.com/tisnik/c3-examples/blob/master/c3-undefined-behaviour/16_large_shift.c3
# Příklad Stručný popis Adresa
178 add_operator1.c3 metoda add definovaná pro dvojici vektorů https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/add_operator1.c3
179 add_operator2.c3 odlišný způsob volání metody add pro provedení součtu dvou vektorů https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/add_operator2.c3
180 add_operator3.c3 přetížení operátoru + pro součet dvou vektorů https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/add_operator3.c3
181 add_operator4.c3 idiomatický způsob zápisu definice přetíženého operátoru + https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/add_operator4.c3
182 add_operator5.c3 úprava předchozího příkladu: předání vektoru odkazem, nikoli hodnotou https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/add_operator5.c3
183 add_operator6.c3 současná definice přičtení skalární hodnoty i součtu dvou vektorů https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/add_operator6.c3
184 add_operator7.c3 otestování komutativity operace součtu https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/add_operator7.c3
185 add_operator8.c3 přetížení operátoru součtu pro prohozené operandy https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/add_operator8.c3
186 add_operator9.c3 symetrická operace součtu https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/add_operator9.c3
       
187 dot_product1.c3 skalární součin volaný přetíženým operátorem * https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/dot_product1.c3
188 dot_product2.c3 úprava předchozího příkladu: předání vektoru odkazem, nikoli hodnotou https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/dot_product2.c3
189 dot_product3.c3 skalární součin vs. násobení vektoru skalární konstantou https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/dot_product3.c3
       
190 equality_operator.c3 přetížení operátoru rovnosti https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/equality_operator.c3
191 unary_minus.c3 přetížení operátoru pro unární – (otočení znaménka) https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/unary_minus.c3
       
192 index_operator1.c3 přetížení operátoru indexování pro celočíselné indexy https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/index_operator1.c3
193 index_operator2.c3 úprava předchozího příkladu: předání vektoru odkazem, nikoli hodnotou https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/index_operator2.c3
194 index_operator3.c3 přetížení operátoru indexování pro klíče, nikoli celočíselné indexy https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/index_operator3.c3
195 index_set_operator.c3 přetížení operátoru indexování pro zápis do objektu https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/index_set_operator.c3
196 len_operator.c3 přetížení speciálního operátoru len https://github.com/tisnik/c3-examples/blob/master/c3-operators-overloading/len_operator.c3

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
  42. Compiler correctness
    https://en.wikipedia.org/wi­ki/Compiler_correctness
  43. Anonymous function
    https://en.wikipedia.org/wi­ki/Anonymous_function
  44. Closure (computer programming)
    https://en.wikipedia.org/wi­ki/Closure_(computer_program­ming)
  45. How to implement closures in C
    https://hokstad.com/how-to-implement-closures
  46. An Overview of Macros in Rust
    http://words.steveklabnik.com/an-overview-of-macros-in-rust
  47. A Practical Intro to Macros in Rust 1.0
    https://danielkeep.github.io/practical-intro-to-macros.html
  48. The Rust Programming Language: macros
    https://doc.rust-lang.org/beta/book/macros.html
  49. Rust by example: 15 macro_rules!
    http://rustbyexample.com/macros.html
  50. Undefined behavior
    https://en.wikipedia.org/wi­ki/Undefined_behavior
  51. Undefined Behavior in C and C++
    https://www.geeksforgeeks­.org/cpp/undefined-behavior-c-cpp/
  52. The Rust reference: Behavior considered undefined
    https://doc.rust-lang.org/reference/behavior-considered-undefined.html#behavior-considered-undefined
  53. Why would a language have a concept of undefined behavior instead of raising an error?
    https://langdev.stackexchan­ge.com/questions/481/why-would-a-language-have-a-concept-of-undefined-behavior-instead-of-raising-an
  54. Undefined behavior
    https://riptutorial.com/c/to­pic/364/undefined-behavior
  55. C3: Undefined Behaviour
    https://c3-lang.org/language-rules/undefined-behaviour/
  56. Undefined behavior in C and C++
    https://russellw.github.io/undefined-behavior
  57. C3 goes game and maths friendly with operator overloading
    https://c3.handmade.networ­k/blog/p/9019-c3_goes_game_and_maths_fri­endly_with_operator_overlo­ading
  58. Are operator overloadings in C++ more trouble than they're worth?
    https://stackoverflow.com/qu­estions/707081/are-operator-overloadings-in-c-more-trouble-than-theyre-worth
  59. Why is operator overloading sometimes considered a bad practice?
    https://www.reddit.com/r/Pro­grammingLanguages/comments/19cl30z/why_is_o­perator_overloading_someti­mes_considered/
  60. I don't understand the arguments against operator overloading
    https://softwareengineerin­g.stackexchange.com/questi­ons/25154/i-dont-understand-the-arguments-against-operator-overloading
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.