Eljáráshívás
Az eljáráshívás formája a következõ:
kifejezés0 ( kifejezés1, kifejezés2, ... , kifejezésN )
- Elõször a kifejezés0 kiértékelõdik és visszaad egy értéket.
- A kifejezés0 általában egy globális név, amihez egy eljárás van hozzárendelve, vagy pedig egy beépített függvény.
- Azonban a kifejezés0 egy eljárásértékeket generáló kifejezés is lehet. Például az (F|G)(x,y) elõször meghívja az F-t, majd pedig a G-t az (x,y) paraméterekkel.
- Az aktuális paraméterlista, a kifejezés1,...,kifejezésN, lehet üres is.
- A paraméterek száma lehet több is, kevesebb is, mint amennyi a definícióban szerepel. Ha többet adunk meg, akkor azokat nem veszi figyelembe, ha kevesebbet, akkor a hiányzó paraméterek értéke &null lesz.
- A paramétereket sorrend szerint adhatjuk át. Pl: F( ,2, ,4 )
- Az Iconban érték szerinti paraméterátadás történik, azonban mivel az adatstukturákat pointer sematikával kezeli, így azoknál valójában ez cím szerinti paraméterátadást jelent. Ha a paraméterlistában változót adunk meg, akkor addig nem történik meg a hívás, amíg a változó értéke nem eldöntött. Például a
write( x:=1 , " " , x+:=1 , " " , x+:=1 )
kódrészlet a
3 3 3
sorozatot fogja kiírni.
- A paraméterek kiértékelése balról jobbra történik. Mindegyiknek szolgáltatnia kell egy értéket, mielõtt meghívásra kerül az eljárás.
- Az eljáráshívás maga lehet sikertelen, avagy visszaadhat egy illetve több értéket is.
Eljárások deklarálása
Az eljárásdeklaráció formája a következõ:
procedure név ( param1 , ... , paramN )
*deklarációk*
initial ...
*kifejezés(ek szekvenciája)*
end
- Az eljárás deklaráció egy eljárás-értéket hoz létre.
- Az eljárás neve egy globális változó lesz, amihez ez az eljárás-érték hozzárendelõdik.
- Ezt az értéket hozzárendelhetjük más változókhoz is, illetve használhatjuk más adatstrukturákban is.
- A param1 , ... , paramN egy nulla vagy több elembõl álló lista. Ez az eljárás formális paraméterlistája.
- Lehetõségünk van arra, hogy az a hívás során több paramétert adnak át, akkor az összes paraméter a paramN-tõl kezdõdõen egy listába kerüljön. Ezt a szögletes zárójelek használatával tehetjük meg.
- Az eljárásban szereplõ deklaráció csak local illetve static lehet.
- Az initial kifejezés opcionális.
Kezdeti érték hozzárendelése a paraméterekhez
Lehetõségünk van minden paraméterhez meghatározni egy kezdeti értéket a következõképp:
parameter_nev := kezdeti_ertek
Az Iconban ha nem adunk meg egy paramétert, akkor az értéke &null lesz. A / akkor lesz sikeres, ha &null a paraméter értéke és ekkor értékül adja neki az általunk meghatározott kezdeti értéket.
Visszatérési érték
Az eljárás visszaadhat egy értéket a return kifejezéssel:
return kif
vagy
return
- Ha nem adunk meg kifejezést, akkor &null értékkel tér vissza, különben pedig a kifejezés értékét adja vissza a hívónak.
- A return nem hoz létre generátort, azaz nem lehet folytatni kifejezés kiértékelését a hívás után.
Generátor eljárás
A suspend segítségével az eljárásunkat generátorrá alakíthatjuk. Hasonlóképp működik mind a return, azt leszámítva, hogy így az eljárásunk több értéket is szolgáltathat. Formái:
suspend e1 do e2
suspend e1
suspend
A működése a következõ:
- Kiértékeli az e1 kifejezést, és az értékeket sorban visszaadja a hívónak.
- Amint a vezérlést visszakapja a hívótól, akkor végrehatja az e2-t (ha megadtuk), majd pedig folytatja az e1 kiértékelését.
- Ha nem tud már több értéket generálni az e1, akkor a vezérlés visszaadódik a hívónak.
- Ha nem adjuk meg az e1-t, akkor &null értéket fog szolgáltatni.
- Ha az e1 egy globális változó, akkor a változót adja vissza az eljárás. Ezáltal az értékadás baloldalán is állhat eljáráshívás.
Példa:
procedure G()
suspend |writes(" e1")\3 do writes(" e2")
write()
suspend |writes(" e3")\2
write()
end
procedure main()
every G() do writes(" e4")
end
Ez a program a következõket írja ki:
e1 e4 e2 e1 e4 e2 e1 e4 e2
e3 e4 e3 e4
Initial
Az eljáráson belüli statikus változók megõrzik értéküket az eljáráshívások közben, de természetesen az elsõ hívás problémát jelent: a változóknak ekkor még nincs értékük. Erre szolgál a kezdeti deklaráció:
initial e
A tartalmazott e kifejezés csak egyszer fog lefutni, méghozzá az eljárás legelsõ meghívásakor. Természetesen ezt más változók inicializálására is használhatjuk. Például tegyük fel, hogy van két eljárásunk a enqueue(x) és a dequeue(), amik egy listába tesznek be illetve vesznek ki elemet. A használatuk elõtt azonban inicializálnunk kell a listát:
global queue
procedure enqueue(x)
initial /queue:=list()
...
end
procedure dequeue()
initial /queue:=list()
...
end
Ezáltal mindkettõben ellenõrizzük, hogy inicializáltuk-e már a sort, és ha nem, akkor megtesszük most.