Alarmnummer schreef op 28 april 2003 @ 22:54:
Aan de hand van de AST die ik van de parser terug krijg bouw ik de IR op, waar ik dus oa types nodig ben. En dat gedeelte van mijn systeem noem ik de parser. (Misschien zou front-end een betere benaming zijn)
IR? En het maakt me niet zoveel uit hoe je 't noemt als we 't er maar over eens zijn wat het is (en dat is nu duidelijk).

k zit dus een beetje met het feit hoe ik die coersions kan toepassen zonder het type-checken onnodig complex te gaan maken. Ik heb een hele rijke type-strcuctuur in mijn systeem. En een van de types is een 'mutable type'. Een mutable type kan toegewezen worden aan 'dingen' die van waarde kunnen veranderen zoals een var. Je krijg dan het volgende type voor variable a van het type Int: Mutable(Int)
Maar als ik nu a+10 ga doen, dan is er in 1e instantie geen operator gedefinieerd voor Mutable(Int)+Int. Daarom moet je dus die Mutable casten naar Int.
Een simpele (en misschien voldoende?) benadering is om te je bindende operator/functie zo ver mogelijk te 'matchen' en als je vast komt te zitten, de overige gegeven types aan te passen aan wat je wilt hebben. In je voorbeeld van "1 + 1.0" kom je dan tot de conclusie dat de operator + met als eerste argument een int toegepast kan worden. Die operator moet dan ook een int als tweede argument hebben, maar je hebt een float! Die int moet dus naar een float gecoerced worden.
Hoe je de regels van wat je waarheen kunt converteren vastlegt is niet zo interessant. Een simpel system zou gebruik kunnen maken van klassen (zoals in C: zo'n beetje alle numerieke typen kun je heen en weer converteren) of van een hiërarchisch model (een beetje zoals Java: je kunt alleen van hoge naar lage precisie converteren) of alles ertussen in.
Met de voorgestelde methode kun je vrijwel alle expressies eenvoudig typeren. Ambiguïteiten treden pas op, als er meerdere mogelijkheden zijn voor een bepaald argument (bijvoorbeeld, als je in het voorbeeld hierboven ook een operator zou hebben die als tweede argument een boolean krijgt en je 1.0 daar ook naar geconverteerd mag worden). In dat geval zou je (nogal ad-hoc) gewoon een volgorde vast kunnen leggen, of (wat geavanceerder en misschien minder inzichtelijk voor de programmeur) kunnen specificeren welke conversies de voorkeur hebben (van double naar int is minder 'schadelijk' dan van double naar boolean, bijvoorbeeld).
Vervelender is dat je in zo'n geval altijd greedy je beschikbare types matcht en dat is niet echt wenselijk. In bovenstaande systeem zou "1 + 2.3" bijvoorbeeld met een functie op ints afgehandeld worden en "2.3 + 1" met een functie op floats, wat gezien de commutativiteit van de +-operator (en omwille van de nauwkeurigheid) niet echt de bedoeling is.
Ik kan me dan ook een variatie voorstellen waarbij je gaat backtracken. Dat zou wel eens veel werk voor de compiler kunnen worden (in theorie dan; in de praktijk zal het aantal mogelijke operators beperkt zijn, neem ik aan). Je moet dan echter een manier verzinnen om de wenselijkheid van een zekere variant te waarden, zodat je de verschillende mogelijkheden kunt vergelijken.
Het lijkt me belangrijk dat je een mechanisme kiest dat duidelijk en logisch is voor de programmeur (ik zet zelf altijd overal casts en haakjes bij, als ik het even niet meer weet; de compiler kan nog wel zo slim zijn, als ik niet exact weet hoe 'ie werkt, gebruik ik 'm niet). Waarschijnlijk wil je als tweede eis voorrang geven aan conversies waarbij geen of relatief weinig verlies van precisie optreedt, of (als derde criterium) efficient uit te voeren zijn.
Overigens zijn sommige beslissingen daarbij best lastig. Het optellen van een 32-bits int bij een 32-bits float, bijvoorbeeld: bij welke variant (int + int = int of float + float = float) de precisie behouden blijft, is afhankelijk van de feitelijke waarden van de operands. Hoewel in dit geval de variant met floats waarschijnlijk de voorkeur heeft, is die voorkeur bij het optellen van een 64-bits integer bij een 32-bits float weer minder duidelijk. Argument is in beide gevallen natuurlijk dat het converteren van een integer naar een float
gemiddeld minder precisieverlies oplevert dan het converteren van een float naar een integer.