Vijf Vragen over Taalontwerp
Mei 2001
(Dit zijn enkele notities die ik heb gemaakt voor een paneldiscussie over het ontwerpen van programmeertalen op MIT op 10 mei 2001.)
1. Programmeertalen zijn voor mensen.
Programmeertalen zijn hoe mensen met computers praten. De computer zou net zo blij zijn om elke taal te spreken die ondubbelzinnig was. De reden dat we high-level talen hebben, is omdat mensen geen machinecode kunnen verwerken. Het punt van programmeertalen is om te voorkomen dat onze arme, tere menselijke hersenen overweldigd worden door een massa details.
Architecten weten dat sommige soorten ontwerpproblemen persoonlijker zijn dan andere. Een van de schoonste, meest abstracte ontwerpproblemen is het ontwerpen van bruggen. Daar is je taak grotendeels een kwestie van het overspannen van een gegeven afstand met het minste materiaal. Het andere uiterste is het ontwerpen van stoelen. Stoelontwerpers moeten hun tijd besteden aan het nadenken over menselijke billen.
Software varieert op dezelfde manier. Het ontwerpen van algoritmen voor het routeren van gegevens door een netwerk is een mooi, abstract probleem, zoals het ontwerpen van bruggen. Terwijl het ontwerpen van programmeertalen is als het ontwerpen van stoelen: het draait allemaal om het omgaan met menselijke zwakheden.
De meesten van ons haten het om dit toe te geven. Het ontwerpen van systemen met grote wiskundige elegantie klinkt voor de meesten van ons veel aantrekkelijker dan het toegeven aan menselijke zwakheden. En er is een rol voor wiskundige elegantie: sommige soorten elegantie maken programma's gemakkelijker te begrijpen. Maar elegantie is geen doel op zich.
En als ik zeg dat talen moeten worden ontworpen om aan menselijke zwakheden te voldoen, bedoel ik niet dat talen moeten worden ontworpen voor slechte programmeurs. Sterker nog, ik denk dat je zou moeten ontwerpen voor de beste programmeurs, maar zelfs de beste programmeurs hebben beperkingen. Ik denk niet dat iemand het leuk zou vinden om te programmeren in een taal waarin alle variabelen de letter x met integer subscripts zijn.
2. Ontwerp voor jezelf en je vrienden.
Als je naar de geschiedenis van programmeertalen kijkt, werden veel van de beste talen ontworpen voor hun eigen auteurs om te gebruiken, en veel van de slechtste talen werden ontworpen om door andere mensen te worden gebruikt.
Wanneer talen voor andere mensen worden ontworpen, is het altijd voor een specifieke groep andere mensen: mensen die niet zo slim zijn als de taalontwerper. Dus krijg je een taal die op je neerbuigt. Cobol is het meest extreme geval, maar veel talen worden doordrongen van deze geest.
Het heeft niets te maken met hoe abstract de taal is. C is behoorlijk low-level, maar het werd ontworpen voor zijn auteurs om te gebruiken, en daarom houden hackers ervan.
Het argument voor het ontwerpen van talen voor slechte programmeurs is dat er meer slechte programmeurs dan goede programmeurs zijn. Dat is misschien zo. Maar die paar goede programmeurs schrijven een onevenredig groot percentage van de software.
Ik ben geïnteresseerd in de vraag hoe je een taal ontwerpt die de allerbeste hackers leuk zullen vinden? Ik denk toevallig dat dit identiek is aan de vraag hoe je een goede programmeertaal ontwerpt, maar zelfs als dat niet zo is, is het tenminste een interessante vraag.
3. Geef de programmeur zoveel mogelijk controle.
Veel talen (vooral die ontworpen zijn voor andere mensen) hebben de houding van een gouvernante: ze proberen je te weerhouden van dingen die volgens hen niet goed voor je zijn. Ik hou van de tegenovergestelde aanpak: geef de programmeur zoveel mogelijk controle.
Toen ik Lisp voor het eerst leerde, vond ik het meest aantrekkelijke dat het mij als een gelijkwaardige partner beschouwde. In de andere talen die ik tot dan toe had geleerd, was er de taal en was er mijn programma, geschreven in de taal, en de twee waren erg gescheiden. Maar in Lisp waren de functies en macro's die ik schreef net als degene die de taal zelf vormden. Ik kon de taal herschrijven als ik wilde. Het had dezelfde aantrekkingskracht als open-source software.
4. Streef naar beknoptheid.
Beknoptheid wordt onderschat en zelfs bespot. Maar als je in de harten van hackers kijkt, zul je zien dat ze er echt van houden. Hoe vaak heb je hackers wel eens liefdevol horen spreken over hoe ze in bijvoorbeeld APL met slechts een paar regels code geweldige dingen konden doen? Ik denk dat alles waar echt slimme mensen echt van houden, de moeite waard is om aandacht aan te besteden.
Ik denk dat bijna alles wat je kunt doen om programma's korter te maken, goed is. Er moeten veel bibliotheekfuncties zijn; alles wat impliciet kan zijn, moet dat zijn; de syntaxis moet tot in het extreme beknopt zijn; zelfs de namen van dingen moeten kort zijn.
En het zijn niet alleen programma's die kort moeten zijn. De handleiding moet ook dun zijn. Een groot deel van de handleidingen wordt in beslag genomen door verduidelijkingen, voorbehouden, waarschuwingen en speciale gevallen. Als je jezelf dwingt om de handleiding in te korten, doe je in het beste geval door de dingen in de taal te repareren die zoveel uitleg vereisten.
5. Geef toe wat Hacking is.
Veel mensen zouden willen dat hacking wiskunde was, of op zijn minst iets als een natuurwetenschap. Ik denk dat hacking meer op architectuur lijkt. Architectuur is gerelateerd aan fysica, in die zin dat architecten gebouwen moeten ontwerpen die niet instorten, maar het eigenlijke doel van architecten is om geweldige gebouwen te maken, niet om ontdekkingen te doen over statica.
Wat hackers graag doen, is geweldige programma's maken. En ik denk dat we, althans in onze eigen geest, moeten onthouden dat het een bewonderenswaardige zaak is om geweldige programma's te schrijven, zelfs als dit werk niet gemakkelijk vertaald kan worden naar de conventionele intellectuele valuta van onderzoeksartikelen. Intellectueel is het net zo waardevol om een taal te ontwerpen waar programmeurs van zullen houden als om een vreselijke te ontwerpen die een idee belichaamt waarover je een artikel kunt publiceren.
1. Hoe organiseer je grote bibliotheken?
Bibliotheken worden een steeds belangrijker onderdeel van programmeertalen. Ze worden ook steeds groter, en dit kan gevaarlijk zijn. Als het langer duurt om de bibliotheekfunctie te vinden die doet wat je wilt dan om deze zelf te schrijven, dan doet al die code niets anders dan je handleiding dik maken. (De Symbolics handleidingen waren daar een voorbeeld van.) Dus ik denk dat we zullen moeten werken aan manieren om bibliotheken te organiseren. Het ideaal zou zijn om ze zo te ontwerpen dat de programmeur kan raden welke bibliotheekoproep het juiste zou doen.
2. Zijn mensen echt bang voor prefix-syntaxis?
Dit is een open probleem in de zin dat ik er al jaren over heb nagedacht en nog steeds het antwoord niet weet. Prefix-syntaxis lijkt volkomen natuurlijk voor mij, behalve mogelijk voor wiskunde. Maar het zou kunnen dat een groot deel van de impopulariteit van Lisp simpelweg te wijten is aan een onbekende syntaxis. Of er iets aan gedaan moet worden, als het waar is, is een andere vraag.
3. Wat heb je nodig voor server-gebaseerde software?
Ik denk dat veel van de meest opwindende nieuwe applicaties die in de komende twintig jaar zullen worden geschreven, web-gebaseerde applicaties zullen zijn, wat betekent dat programma's op de server draaien en via een webbrowser met je praten. En om dit soort programma's te schrijven, hebben we misschien wat nieuws nodig.
Eén ding dat we nodig zullen hebben, is ondersteuning voor de nieuwe manier waarop server-gebaseerde apps worden uitgebracht. In plaats van één of twee grote releases per jaar, zoals desktopsoftware, worden server-gebaseerde apps uitgebracht als een reeks kleine wijzigingen. Je kunt wel vijf of tien releases per dag hebben. En in de regel zal iedereen altijd de nieuwste versie gebruiken.
Je weet hoe je programma's kunt ontwerpen om debugbaar te zijn? Welnu, server-gebaseerde software moet evenzo ontworpen zijn om veranderbaar te zijn. Je moet het gemakkelijk kunnen veranderen, of in ieder geval weten wat een kleine verandering is en wat een belangrijke.
Een ander ding dat nuttig kan blijken te zijn voor server-gebaseerde software, verrassend genoeg, zijn continuaties. In web-gebaseerde software kun je iets als continuation-passing style gebruiken om het effect van subroutines te krijgen in de inherent staatloze wereld van een websessie. Misschien zou het de moeite waard zijn om daadwerkelijke continuaties te hebben, als het niet te duur was.
4. Welke nieuwe abstracties zijn er nog te ontdekken?
Ik weet niet hoe redelijk een hoop dit is, maar één ding dat ik persoonlijk echt graag zou willen doen, is een nieuwe abstractie ontdekken - iets dat net zoveel verschil zou maken als first-class functies of recursie of zelfs keyword parameters. Dit is misschien een onmogelijke droom. Deze dingen worden niet zo vaak ontdekt. Maar ik ben altijd op zoek.
1. Je mag elke taal gebruiken die je wilt.
Het schrijven van applicatieprogramma's betekende vroeger het schrijven van desktopsoftware. En in desktopsoftware is er een grote bias om de applicatie in dezelfde taal te schrijven als het besturingssysteem. En dus betekende tien jaar geleden software schrijven grotendeels software schrijven in C. Uiteindelijk evolueerde er een traditie: applicatieprogramma's mogen niet in ongebruikelijke talen worden geschreven. En deze traditie had zo lang om zich te ontwikkelen dat niet-technische mensen zoals managers en durfkapitalisten het ook leerden.
Server-gebaseerde software blaast dit hele model weg. Met server-gebaseerde software kun je elke taal gebruiken die je wilt. Bijna niemand begrijpt dit nog (vooral niet managers en durfkapitalisten). Een paar hackers begrijpen het, en daarom horen we zelfs over nieuwe, onafhankelijke talen zoals Perl en Python. We horen niet over Perl en Python omdat mensen ze gebruiken om Windows-apps te schrijven.
Wat dit voor ons betekent, als mensen die geïnteresseerd zijn in het ontwerpen van programmeertalen, is dat er nu potentieel een echt publiek is voor ons werk.
2. Snelheid komt van profilers.
Taalontwerpers, of in ieder geval taalimplementeerders, schrijven graag compilers die snelle code genereren. Maar ik denk niet dat dit is wat talen snel maakt voor gebruikers. Knuth wees er lang geleden al op dat snelheid alleen ertoe doet in een paar kritieke knelpunten. En iedereen die het heeft geprobeerd, weet dat je niet kunt raden waar deze knelpunten zich bevinden. Profilers zijn de oplossing.
Taalontwerpers lossen het verkeerde probleem op. Gebruikers hebben geen benchmarks nodig om snel te draaien. Wat ze nodig hebben, is een taal die hen kan laten zien welke delen van hun eigen programma's herschreven moeten worden. Daar komt snelheid in de praktijk vandaan. Dus misschien zou het een netto winst zijn als taalimplementeerders de helft van de tijd die ze zouden hebben besteed aan compileroptimalisaties, zouden besteden aan het schrijven van een goede profiler.
3. Je hebt een applicatie nodig om het ontwerp van een taal aan te sturen.
Dit is misschien geen absolute regel, maar het lijkt erop dat de beste talen allemaal samen evolueerden met een bepaalde applicatie waarvoor ze werden gebruikt. C werd geschreven door mensen die het nodig hadden voor systeemprogrammering. Lisp werd mede ontwikkeld om symbolische differentiatie te doen, en McCarthy was zo gretig om te beginnen dat hij differentiatieprogramma's schreef, zelfs in het eerste artikel over Lisp, in 1960.
Het is vooral goed als je applicatie een nieuw probleem oplost. Dat zal je taal ertoe aanzetten om nieuwe functies te hebben die programmeurs nodig hebben. Persoonlijk ben ik geïnteresseerd in het schrijven van een taal die goed zal zijn voor het schrijven van server-gebaseerde applicaties.
[Tijdens het panel maakte Guy Steele ook dit punt, met de aanvullende suggestie dat de applicatie niet het schrijven van de compiler voor je taal mag inhouden, tenzij je taal bedoeld is voor het schrijven van compilers.]
4. Een taal moet goed zijn voor het schrijven van wegwerpprogramma's.
Je weet wat een wegwerpprogramma is: iets dat je snel schrijft voor een beperkte taak. Ik denk dat als je rondkijkt, je zult ontdekken dat veel grote, serieuze programma's begonnen als wegwerpprogramma's. Ik zou niet verbaasd zijn als de meeste programma's begonnen als wegwerpprogramma's. En dus als je een taal wilt maken die goed is voor het schrijven van software in het algemeen, moet deze goed zijn voor het schrijven van wegwerpprogramma's, omdat dat het larvale stadium van de meeste software is.
5. Syntaxis is verbonden met semantiek.
Het is traditioneel om syntaxis en semantiek als volledig gescheiden te beschouwen. Dit zal schokkend klinken, maar het kan zijn dat ze dat niet zijn. Ik denk dat wat je in je taal wilt, gerelateerd kan zijn aan hoe je het uitdrukt.
Ik sprak onlangs met Robert Morris, en hij wees erop dat operator overloading een grotere winst is in talen met infix-syntaxis. In een taal met prefix-syntaxis is elke functie die je definieert effectief een operator. Als je een plus voor een nieuw type getal wilt definiëren dat je hebt bedacht, kun je gewoon een nieuwe functie definiëren om ze op te tellen. Als je dat doet in een taal met infix-syntaxis, is er een groot verschil in uiterlijk tussen het gebruik van een overbelaste operator en een functieaanroep.
1. Nieuwe programmeertalen.
In de jaren zeventig was het in de mode om nieuwe programmeertalen te ontwerpen. Onlangs is dat niet meer zo. Maar ik denk dat server-gebaseerde software nieuwe talen weer in de mode zal maken. Met server-gebaseerde software kun je elke taal gebruiken die je wilt, dus als iemand een taal ontwerpt die beter lijkt dan andere beschikbare talen, zullen er mensen zijn die een risico nemen en deze gebruiken.
2. Tijdverdeling.
Richard Kelsey noemde dit als een idee waarvan de tijd opnieuw is gekomen in het laatste panel, en ik ben het er volledig mee eens. Mijn gok (en de gok van Microsoft, zo lijkt het) is dat veel computergebruik van de desktop naar externe servers zal verhuizen. Met andere woorden, tijdverdeling is terug. En ik denk dat er ondersteuning voor nodig zal zijn op taalniveau. Ik weet bijvoorbeeld dat Richard en Jonathan Rees veel werk hebben verricht aan procesplanning binnen Scheme 48.
3. Efficiëntie.
Onlangs begon het erop te lijken dat computers eindelijk snel genoeg waren. Steeds vaker hoorden we over bytecode, wat mij tenminste impliceert dat we denken dat we cycli over hebben. Maar ik denk niet dat we dat zullen hebben, met server-gebaseerde software. Iemand zal moeten betalen voor de servers waarop de software draait, en het aantal gebruikers dat ze per machine kunnen ondersteunen, zal de deler van hun kapitaalkosten zijn.
Dus ik denk dat efficiëntie ertoe zal doen, althans in computationele knelpunten. Het zal vooral belangrijk zijn om i/o snel te doen, omdat server-gebaseerde applicaties veel i/o doen.
Het kan uiteindelijk blijken dat bytecode geen winst is. Sun en Microsoft lijken op dit moment een soort strijd van de bytecodes te voeren. Maar ze doen het omdat bytecode een handige plek is om zichzelf in het proces in te voegen, niet omdat bytecode op zichzelf een goed idee is. Het kan blijken dat dit hele slagveld wordt omzeild. Dat zou nogal amusant zijn.
1. Clients.
Dit is slechts een gok, maar mijn gok is dat het winnende model voor de meeste applicaties puur server-gebaseerd zal zijn. Het ontwerpen van software die werkt op de aanname dat iedereen jouw client zal hebben, is als het ontwerpen van een samenleving op de aanname dat iedereen gewoon eerlijk zal zijn. Het zou zeker handig zijn, maar je moet aannemen dat het nooit zal gebeuren.
Ik denk dat er een proliferatie zal zijn van apparaten die een soort webtoegang hebben, en alles wat je erover kunt aannemen, is dat ze eenvoudige HTML en formulieren kunnen ondersteunen. Heb je een browser op je mobiele telefoon? Zit er een telefoon in je Palm Pilot? Krijgt je Blackberry een groter scherm? Kun je het web browsen op je Gameboy? Je horloge? Ik weet het niet. En ik hoef het niet te weten als ik wed op alles wat op de server staat. Het is gewoon zoveel robuuster om alle hersenen op de server te hebben.
2. Objectgeoriënteerd programmeren.
Ik realiseer me dat dit een controversieel punt is, maar ik denk niet dat objectgeoriënteerd programmeren zo'n grote zaak is. Ik denk dat het een prima model is voor bepaalde soorten applicaties die dat specifieke soort datastructuur nodig hebben, zoals windowsystemen, simulaties en CAD-programma's. Maar ik zie niet in waarom het het model voor alle programmering zou moeten zijn.
Ik denk dat een deel van de reden waarom mensen in grote bedrijven van objectgeoriënteerd programmeren houden, is omdat het veel oplevert van wat lijkt op werk. Iets dat van nature kan worden weergegeven als, zeg, een lijst met integers, kan nu worden weergegeven als een klasse met allerlei steigers en drukte.
Een andere aantrekkingskracht van objectgeoriënteerd programmeren is dat methoden je enig effect van first-class functies geven. Maar dit is oud nieuws voor Lisp-programmeurs. Als je daadwerkelijke first-class functies hebt, kun je ze gewoon gebruiken op elke manier die geschikt is voor de taak, in plaats van alles in een mal van klassen en methoden te persen.
Wat dit betekent voor taalontwerp, denk ik, is dat je objectgeoriënteerd programmeren niet te diep moet inbouwen. Misschien is het antwoord om meer algemene, onderliggende zaken aan te bieden, en mensen te laten ontwerpen welke objectsystemen ze willen als bibliotheken.
3. Ontwerp door een commissie.
Je taal laten ontwerpen door een commissie is een grote valkuil, en niet alleen om de redenen die iedereen kent. Iedereen weet dat commissies de neiging hebben om onhandige, inconsistente ontwerpen te produceren. Maar ik denk dat een groter gevaar is dat ze geen risico's zullen nemen. Als één persoon de leiding heeft, kan hij risico's nemen waar een commissie nooit mee zou instemmen.
Is het echter noodzakelijk om risico's te nemen om een goede taal te ontwerpen? Veel mensen vermoeden misschien dat taalontwerp iets is waarbij je redelijk dicht bij de conventionele wijsheid moet blijven. Ik wed dat dit niet waar is. In al het andere wat mensen doen, is de beloning evenredig met het risico. Waarom zou taalontwerp anders zijn?