XIII.  

TYPY  PROCEDURA


Turbo Pascal implementuje prostředky pro spouštění podprogramů, aktuálně volených až v průběhu výpočtu programu, a také pro předávání takto zvolených podprogramů procedurám a funkcím formou procedurálních parametrů.

Deklarace typu procedura   Popis typu procedura odpovídá (až na chybějící identifikátor) hlavičce procedury nebo hlavičce funkce. Identifikátory formálních parametrů se sice uvádějí, významný je však pouze jejich počet, pořadí, typ a model volání.

Obrázek 69: Popis typu procedura

Hodnotami procedurálních typů jsou startovací adresy uživatelských podprogramů. Vnitřním tvarem se hodnoty procedurálních typů shodují s hodnotami typů ukazatelových, formálně (z hlediska typové kontroly) však za ukazatele považovány nejsou. Kompatibilita i kompatibilita vzhledem k přiřazení je pro procedurální typy definována tak, že v jejich popisech mohou být odlišné pouze identifikátory formálních parametrů.

Následujícími deklaracemi jsou zavedeny čtyři pojmenované procedurální typy, typ PoleFunkci, jehož komponenty jsou procedurálního typu a proměnná P nepojmenovaného procedurálního typu, kompatibilního s typem Ctvrty.

type Prvni      = procedure;
     Druhy      = procedure (W: Word; var R: Real);
     Treti      = function: Real;
     Ctvrty     = function (T: Real): Real;
     PoleFunkci = array [1..10] of Ctvrty;
var  P          : function (X: Real): Real;
Přiřazovací příkaz   Pokud je na levé straně přiřazovacího příkazu uvedena proměnná procedurálního typu, může být na straně pravé buď proměnná kompatibilního procedurálního typu nebo přímo identifikátor kompatibilní procedury či funkce. Do proměnné vlevo je pak zkopírována hodnota proměnné vpravo resp. dosazena adresa uvedeného podprogramu. Podprogram, jehož adresa má být přiřazena procedurální proměnné, musí (kromě kompatibility) splňovat tyto požadavky:

Poslednímu omezení se lze vyhnout deklarací uživatelského podprogramu, který volá podprogram standardní. Tímto způsobem však nelze zachovat univerzálnost některých standardních podprogramů. Následující procedura MujRead například „umí“ číst pouze jedinou celočíselnou hodnotu ze souboru Input do proměnné typu Integer.

procedure MujRead (var I: Integer); far;
{--------------------------------------}
begin { MujRead }
 Read (I)
end; { MujRead }
Volání podprogramu   Syntax volání podprogramu, jehož adresa je hodnotou procedurální proměnné, odpovídá syntaxi přímého volání tohoto podprogramu s tím, že jeho identifikátor je nahrazen identifikátorem procedurální proměnné.
function Funkce (R: Real): Real; far;
{-----------------------------------}
begin { Funkce }
 if R = 0 then Funkce := 1
          else Funkce := Sin(R)/R
end;  { Funkce }

var P: function (X: Real): Real;

...
P := Funkce;
Writeln ('sin(0)/0   = ', P(0), 'sin(pi)/pi = ', P(Pi));
...
Adresní operátor @ a funkce Addr   Adresní operátor @, aplikovaný na procedurální proměnnou, změní její typ na Pointer. Výsledkem operace není hodnota, nýbrž proměnná typu Pointer. Pokud je třeba získat adresu procedurální proměnné, aplikuje se dvojnásobný adresní operátor. Například @@P je ukazatel na procedurální proměnnou P. Zápis @@P již je výraz, nikoliv přístup k proměnné. Stejným způsobem lze použít i adresní funkci Addr.

Změny typu procedurálních proměnných aplikací operátoru @ lze využít k porovnávání jejich hodnot, neboť pro proměnné procedurálních typů nejsou implementovány relační operace. Za normálních okolností totiž výskyt procedurální proměnné není chápán jako proměnná, nýbrž jako volání podprogramu, který je její hodnotou. Ze stejného důvodu není možné využít ani typecasting.

if @P = @Q then ...                       { správně }
if Pointer(P) = Pointer(Q) then...        { chybně  }
Funkce Seg a Ofs   Rovněž aplikace funkcí SegOfs na procedurální proměnné se liší od aplikace těchto funkcí na proměnné ostatních typů. Výsledkem funkce není hodnota segmentové resp. ofsetové části adresy procedurální proměnné. Výsledkem není žádná hodnota, nýbrž proměnná — Seg (P) resp. Ofs (P) je proměnná typu Word, alokovaná ve vyšším resp. v nižším slově procedurální proměnné P. Hodnotu segmentu resp. ofsetu adresy proměnné P mají například výrazy Seg (@P) resp. Ofs (@P).

Procedurální parametry podprogramů   Hodnoty a proměnné procedurálních typů mohou být naprosto stejně jako hodnoty a proměnné jiných typů předávány jako parametry procedurám a funkcím.


PŘÍKLAD: Program Tabelace vytiskne tabulku funkčních hodnot funkcí sinus a kosinus. Pro tisk tabulky je zavedena procedura Tabulka, jejímž parametrem F je i vlastní tabelovaná funkce. Aby bylo možné uvést jako skutečný parametr přímo identifikátor zvolené funkce, nesmí být tento parametr volán odkazem (funkce SinusCosinus nejsou proměnnými, nýbrž hodnotami procedurálního typu Funkce, deklarovaného jako typ parametru F). V opačném případě by bylo nutné nejdříve přiřadit zvolenou funkci nějaké procedurální proměnné typu Funkce a teprve ji použít jako skutečný parametr ve volání procedury Tabulka.

program Tabelace;
{===============}

 type Funkce = function (X: Real): Real;  { reálná funkce jedné reálné }
                                          { proměnné                   }

 procedure Tabulka (F: Funkce; X, KrokX: Real; Pocet: Byte);
 {---------------------------------------------------------------------}
 { Vytiskne tabulku funkčních hodnot funkce F pro počáteční hodnotu    }
 { argumentu X, jeho přírustek KrokX a počet tabelovaných hodnot Pocet.}

  var I: Byte;                            { pomocná proměnná           }

 begin { Tabulka }
  for I := 1 to Pocet do                  { cyklus řádek tabulky       }
   begin
    Writeln (X:20, F(X):20);              { tisk argumentu a hodnoty   }
    X := X + KrokX                        { aktualizace argumentu      }
   end                                    { další řádka tabulky        }
 end; { Tabulka }

 {$F+}

 function Sinus (X: Real): Real;          { tabelovaná funkce          }
 {---------------------------------------------------------------------}
 begin { Sinus }
  Sinus := Sin (X)
 end; { Sinus }

 function Cosinus (X: Real): Real;        { tabelovaná funkce          }
 {---------------------------------------------------------------------}
 begin { Cosinus }
  Cosinus := Cos (X)
 end; { Cosinus }

 {$F-}

begin { program }
 Tabulka (Sinus, 0, Pi/4, 9);             { tabulka funkce Sinus       }
 Writeln;
 Tabulka (Cosinus, 0, Pi/4, 9)            { tabulka funkce Cosinus     }
end. { program }