Volt már szó róla kb. egy éve, hogy talán érdemes volna megcsinálni a postfix függvényhívást. Hát itt van. Két új szabályt vettem fel a Lemon nyelvtanba:
expr ::= expr : : func ( parlist )
expr ::= expr : : func
A postfix függvényhívásból ugyanaz a kód generálódik, mint a nyíl jobb oldalán álló hagyományos függvényhívásból.
x::func(a,b,c) -> func(x,a,b,c)
x::func -> func(x)
A postfix függvényhívás operátora a '::'. Egy-karakteres operátor nem lehetséges, mert már minden szóbajöhető karakter foglalt ('.' a névtér határoló, ':' a metódushívás). De nem olyan rossz ez a '::', hasonlít a metódushíváshoz, de mégis meg lehet különböztetni.
A ::-tól balra levő akármilyen kifejezés (precedencia!) lesz a ::-tól jobbra álló akármilyen (pl. névtérből vett) függvény első paramétere, miközben az esetleges többi paraméter eggyel hátrébb csúszik. Mintha minden függvény az első argumentumának a metódusa volna.
Példa:
#define OGGNAME1(x) strtran(atail(split(x,dirsep())),".ogg","")
#define OGGNAME2(x) (x)::split(dirsep())::atail::strtran(".ogg","")
Ezek a makrók egy ogg fájl teljes specifikációjából kiveszik a path és kiterjesztés nélküli fájlnevet. (Persze más eszközök is volnának erre, ez csak egy példa.) A fájlspecifikációt felvágja a dirsep-eknél, a keletkező tömbből veszi az utolsó elemet, abból kihagyja az .ogg kiterjesztést. Az első makró hagyományos, a második postfix függvényhívással van megírva.
Ellene szól: új szintaktika, kicsivel hosszabb kód, ügyelni kell a precedenciára.
Mellette szól: balról jobbra olvasható kód, kevesebb távoli zárójelpár.
Megjegyzés: Természetesen a függvényeknek csak egy implementációjuk van, ami azonban kétféle szintaktikával is meghívható. A fordító kiegyenlíti a különbséget, ezért a hatékonyság is egyforma.
- 5612 megtekintés
Hozzászólások
Van még egy érdekes lehetőség/következmény. Az alábbi kifejezések mintájára
x:=x+y <=> x+=y
x:=x*y <=> x*=y
...
x:=x::y <=> x::=y <=> x:=y(x)
Például
x::str::alltrim::padl(10,"0") //x nem vátozik
x::=str::alltrim::padl(10,"0") //x egyúttal megkapja az eredményt
Külön dolgozni kellett a kiértékelés és értékadás sorrendjéért
x::=f::g::h <=> x:=h(g(f(x)))
Még nincs fenn a repóban.
--
CCC3
- A hozzászóláshoz be kell jelentkezni
Nem fog ez nagyon csúnya, olvashatatlan szintaxist eredményezni?
w
- A hozzászóláshoz be kell jelentkezni
Hát, hogy csúnya-e, az azon múlik, hogy kinek mi tetszik.
Érdekelne, hogy ismer-e valaki hasonlót más nyelvekben.
Azóta még egyszer átdolgoztam az egészet, hogy a lehető legáltalánosabb legyen. Egy példa:
x*=y+1 <=> x*=(y+1)
<=> x:=x*(y+1) //C-ben is, Clipperben is
Ennek mintájára
x::=y+1 <=> x::=(y()+1)
<=> x:=x::(y()+1)
<=> x:=x::y+1
<=> x:=y(x)+1
Itt az a lényeg, hogy a '::'-nek ugyanaz a precedenciája, mint a ':'-nek (magas), a '::='-nek pedig ugyanaz a precedenciája, mint a '*='-nek (alacsony).
Amikor a '::' nem közvetlenül a függvény baloldalán van, mert, pl. közben van a zárójel, akkor a függvényhívást jelölő () nem hagyható el.
A szabály legáltalánosabb formája a Lemon nyelvtanban:
expr ::= expr '::' expr
ahol a '::' jobboldalán álló kifejezést alkotó fa (a nyelvtani elemzőben ez egy fa) baloldali ágain haladva (tehát a fa bal szélén) valahol függvényhívásnak kell lennie.
Persze meg lehet lenni a '::=' operátor nélkül, de egy matematikus nem bírja megállni, hogy egy ilyen általánosítási lehetőséget ki ne használjon. Ha már van '::', akkor lennie kell '::='-nek is. Tehát továbbra is az a kérdés, hogy érdemes-e bevenni a postfix függvényhívást.
Beraktam a repóba, lehet próbálgatni.
Szerk:
Ez vajon mit ír ki?
function main()
local x:="1"
? x::(val()+20)::str::ltrim::padl(4,"0")
Megoldás:
0021
--
CCC3
- A hozzászóláshoz be kell jelentkezni
A "C# 2008" könyv 14. fejezetében (486. oldal) látom a CCC postfix függvényhívás rokonát. C#-ben bővítő metódusoknak hívják a tüneményt.
Különbségek:
C#-ben a bővítő metódusokat spéci szintaktikával kell definiálni, viszont a közönséges metódushívással azonos szintaktikával lehet használni. A fordító a típusok vizsgálata alapján kitalálja, hogy mikor melyik eset áll fenn.
A CCC fordító nem vizsgálja a típusokat, ezért a használatkor van szükség spéci szintaktikára (a normális metódushívás : operátora helyett ::), viszont akármilyen függvényre működik.
A C#-es dolog akkor volna több egyszerű (forrás-)szöveg transzformációnál (ahogy a CCC-ben is van), ha használni lehetne interfész implementálására. 493. oldal, 1. bekezdés, 1. sor:
Ha az olvasó először találkozik a bővítő metódusokkal, akkor tekinthet azokra úgy, mint egy lehetőségre a típus ... publikus szerződésének kibővítéséhez.
Öt sorral lejjebb.
... a bővítő metódusok valójában egyáltalán nem bővítik a típus publikus szerződését.
(Megj. Elég sok ilyen van a könyvben. Amúgy a próbák mutatják, hogy a bővítő metódusokat a fordító nem veszi számításba, mikor az a kérdés, hogy a típus milyen interfészeket implementál.)
Emellett a CCC postfix függvényhívásnak van az a formája, ami értéket ad az lvalue-knak:
x:="hopp"
x::upper //nagybetűre, x nem változik
x::=upper //nagybetűre, x magkapja az eredményt (hasonlóan, mint '+='-nél)
--
CCC3
- A hozzászóláshoz be kell jelentkezni