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.
Hozzászólások
Van még egy érdekes lehetőség/következmény. Az alábbi kifejezések mintájára
Például
Külön dolgozni kellett a kiértékelés és értékadás sorrendjéért
Még nincs fenn a repóban.
--
CCC3
Nem fog ez nagyon csúnya, olvashatatlan szintaxist eredményezni?
w
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:
Ennek mintájára
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?
Megoldás:
0021
--
CCC3
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:
Öt sorral lejjebb.
(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:
--
CCC3