CA - Visual Objects

Alprogramok, modulok

Szintaxis

Alprogramból itt is kétféle van, az eljárás és a függvény. A kettő között lényeges különbség, hogy az eljárásnak nem lehet visszatérő értéke. Általában azt szokták mondani, hogy függvényt akkor használunk amikor valamit ki akarunk számolni, eljárást pedig minden másra. Az osztályoknál még előjön majd a metódus is. Ha egy függvény vagy eljárás statikus, akkor csak az adott modulban látszik. Mindkettőnél megadható a hivási konvenció, például pascal.

static function add(a, b) as int pascal return a + b function Start(p) ? add(3, 4) // vagy do add with 3, 4 _Accept("") return nil

A lehetséges hívási konvenciók: Az eljárás teljesen hasonló, viszont mindig nil -t ad vissza, ebbe mi nem szólhatunk bele. Egy érdekes különbség, hogy megadhatunk úgynevezett INIT eljárásokat. Ezek az alkalmazás indításakor automatikusan meghívódnak, még a Start() rutin előtt. Három prioritási szint van, ezek a hívások sorrendjét befolyásolják, vagyis először az _INIT1 eljárások hívódnak meg, aztán az _INIT2 -esek, és utána az _INIT3 -asok. A reference guide hangsúlyozza, hogy a hibakezelő rutinok _INIT1 -esek, ezért olyat mi lehetőleg ne használjunk. Ezenkívül az INIT eljárásokra van néhány megszorítás is:
procedure test as void pascal _INIT2 ? "elso, haha" function Start(p) ? "nahanyadiklesz" // output: elso, haha nahanyadiklesz

Még egy baromi érdekes dolog, ami függvényeknél és eljárásoknál is működik, az export local utasítás. Itt előjönnek a kódblokkok is, amikről nem írtam még, de most megnézzük milyen állatok is azok. Képzeljük el a kódblokkot úgy, mint egy programrészletet amit akár paraméterként is átadhatunk egy függvénynek. Nézzünk egy példát.

function Start(p) local cb as codeblock cb := {|x| x + 2} ? Eval(cb, 10) _Accept("") return nil // output: 12

Nagyon hasonlít az új C++ szabvány lambda kifejezéseire. Most képzeljük el, hogy írtunk egy kódblokkot, ami mondjuk az x() függvény egy lokális változóját használja, majd a kódblokkot átadjuk paraméterként az y() függvénynek. Mi a fene lesz azzal a változóval? Itt jön be a képbe az export local, ennek segítségével a kódblokkban láthatóvá válnak a hívó függvény lokális változói.

function x as void export local local i := 3 as int local cb as codeblock cb := { |x| x + i } ? y(cb) function y(cb as codeblock) as int return Eval(cb, 5) // output: 8

A vicc az, hogy nálam export local nélkül is megy. Hehe.

Paraméterátadás

Eddig csak érték szerinti paraméterátadást láttunk, de persze létezik cím szerinti is. Ekkor az as kulcsszó helyett a ref -et kell használni, és a függvény hívásakor az adott paramétert a @ operátorral kell átadni.

function x(a ref int) as void a := 2 function Start(p) local i as int x(@i) ? i _Accept("") return nil // output: 2

Túlterhelés

Egy modulon belül nem lehet két azonos nevű elem, így függvényeket nem tudunk túlterhelni. A rosszabb hír, hogy ha egy elem az egész alkalmazásban látszik, akkor aztán tényleg sehol nem lehet ugyanolyan nevű elem.

Rekurzió

Természetesen egy függvény hívhatja önmagát is.

function Factorial(n as int) as int if n = 0 .or. n = 1 return 1 endif return Factorial(n - 1) * n

Mily meglepő, eljárásokra is működik. A Factorial2 eljárást lehetne szebben is csinálni, például külön átadni az értéket, de most lusta voltam.

procedure Factorial2(n ref int) local tmp as int if n = 0 .or. n = 1 n := 1 return endif tmp := n - 1 Factorial2(@tmp) n := n * tmp function Start(p) local i := 5 as int ? Factorial(3) Factorial2(@i) ? i _Accept("") return nil // output: 6 120

Megpróbáltam kódblokkal is, de nem enged elágazást (önmagát hívni még igen, de stack overflowot kaptam). Sajnos erről sem találni túl sokat a helpben.