2.2.1 The Naming Model
Het is nuttig om een model te hebben van hoe namen worden geassocieerd met specifieke objecten. Een systeemontwerper maakt een naamgevingsschema, dat uit drie elementen bestaat. Het eerste element is een naamruimte, die bestaat uit een alfabet van symbolen samen met syntaxisregels die specificeren welke namen aanvaardbaar zijn. Het tweede element is een naam-toewijzingsalgoritme, dat sommige (niet noodzakelijk alle) namen van de naamruimte associeert met sommige (ook weer niet noodzakelijk alle) waarden in een universum van waarden, dat het derde en laatste element van het naamgevingsschema is. Een waarde kan een object zijn, of een andere naam uit de oorspronkelijke naamruimte of uit een andere naamruimte. Een afbeelding van een naam naar een waarde is een voorbeeld van een binding, en wanneer een dergelijke afbeelding bestaat, wordt gezegd dat de naam aan de waarde is gebonden. Figuur 2.10 illustreert dit.
In de meeste systemen zijn gewoonlijk verschillende naamgevingsschema’s tegelijkertijd in werking. Een systeem kan bijvoorbeeld een naamgevingsschema gebruiken voor de namen van e-mail-postbussen, een tweede voor Internet-hosts, een derde voor bestanden, en een vierde voor virtuele geheugenadressen. Wanneer een programma-interpreter een naam tegenkomt, moet hij weten welk naamgevingsschema hij moet aanroepen. De omgeving waarin de naam wordt gebruikt geeft meestal genoeg informatie om het naamgevingsschema te identificeren. Bijvoorbeeld, in een toepassingsprogramma weet de auteur van dat programma dat het programma moet verwachten dat bestandsnamen alleen door het bestandssysteem worden geïnterpreteerd en Internet hostnamen alleen door een netwerkdienst worden geïnterpreteerd.
De interpreter die de naam tegenkomt voert het naam-toewijzingsalgoritme van het juiste naamgevingsschema uit. Het name-mapping algoritme lost de naam op, hetgeen betekent dat het de bijbehorende waarde ontdekt en retourneert (om deze reden wordt het name-mapping algoritme ook wel een resolver genoemd). Het algoritme voor het toewijzen van namen wordt gewoonlijk aangestuurd door een extra parameter, de zogenaamde context. Voor een gegeven naamgevingsschema kunnen er veel verschillende contexten zijn, en een enkele naam van de naamruimte kan in verschillende waarden worden omgezet wanneer de resolver verschillende contexten gebruikt. Wanneer een persoon bijvoorbeeld in een gewoon gesprek verwijst naar de namen “jij”, “hier”, of “Alice”, hangt de betekenis van elk van die namen af van de context waarin de persoon ze uitspreekt. Aan de andere kant hebben sommige naamsystemen slechts één context. Dergelijke naamsystemen bieden wat men noemt universele naamruimten, en zij hebben de prettige eigenschap dat een naam binnen dat naamsysteem altijd dezelfde betekenis heeft, ongeacht wie hem gebruikt. In de Verenigde Staten bijvoorbeeld vormen de sociale-zekerheidsnummers, waarmee pensioen- en belastingrekeningen van de overheid worden geïdentificeerd, een universele naamruimte. Wanneer er meer dan één context is, kan de interpreter de resolver vertellen welke hij moet gebruiken of kan de resolver een standaardcontext gebruiken.
We kunnen het naamgevingsmodel samenvatten door de volgende conceptuele bewerking van namen te definiëren:
waarde ← resolve (naam, context)
Wanneer een interpreter een naam in een object tegenkomt, gaat hij eerst na om welk naamgevingsschema het gaat en dus welke versie van resolve hij moet aanroepen. Het identificeert dan een geschikte context, lost de naam op in die context, en vervangt de naam door de opgeloste waarde terwijl het doorgaat met interpreteren. De variabele context vertelt resolve welke context te gebruiken. Die variabele bevat een naam die bekend staat als een contextverwijzing.
In een processor zijn registernummers namen. In een eenvoudige processor liggen zowel de verzameling van register-namen, als de registers waaraan die namen gebonden zijn, vast op het tijdstip van ontwerp. In de meeste andere systemen die namen gebruiken (inclusief het register naamgevingsschema van sommige krachtige processoren), is het mogelijk om nieuwe bindingen te maken en oude te verwijderen, de naamruimte op te sommen om een lijst van bestaande bindingen te verkrijgen, en twee namen te vergelijken. Voor deze doeleinden definiëren we nog vier conceptuele operaties:
status ← bind (naam, waarde, context)
status ← ontbind (naam, context)
lijst ← opsomming (context)
resultaat ← vergelijk (naam1, naam2)
De eerste bewerking verandert de context door een nieuwe binding toe te voegen; het statusresultaat meldt of de wijziging al dan niet is geslaagd (het kan mislukken als de voorgestelde naam in strijd is met de syntaxisregels van de naamruimte). Na een succesvolle aanroep van bind, zal resolve de nieuwe waarde voor naam teruggeven.* De tweede bewerking, unbind, verwijdert een bestaande binding uit de context, waarbij de status opnieuw succes of falen meldt (misschien omdat er geen bestaande binding was). Na een succesvolle aanroep van unbind, zal resolve niet langer die waarde voor naam teruggeven. De bind en unbind operaties staan het gebruik van namen toe om verbindingen tussen objecten te maken en die verbindingen later te wijzigen. Een ontwerper van een object kan, door een naam te gebruiken om te verwijzen naar een componentobject, het object kiezen waaraan die naam gebonden is, hetzij op dat moment of op een later tijdstip door bind aan te roepen, en een binding elimineren die niet langer gepast is door unbind aan te roepen, allemaal zonder het object dat de naam gebruikt te wijzigen. Deze mogelijkheid om bindingen uit te stellen en te veranderen is een krachtig gereedschap dat in het ontwerp van bijna alle systemen wordt gebruikt. Sommige implementaties van namen bieden een enumerate functie, die een lijst teruggeeft van alle namen die in de context kunnen worden opgelost. Sommige implementaties van opsommen kunnen ook een lijst teruggeven van alle waarden die momenteel in de context gebonden zijn. Tenslotte rapporteert de vergelijkingsfunctie (waar of onwaar) of naam1 al dan niet hetzelfde is als naam2. De betekenis van “hetzelfde” is een interessante vraag die wordt behandeld in Paragraaf 2.2.5, en het kan nodig zijn om extra contextargumenten te leveren.
Verschillende naamgevingssystemen hebben verschillende regels over de uniciteit van naam-naar-waarde koppelingen. Sommige naamgevingsschema’s hebben de regel dat een naam moet overeenkomen met precies één waarde in een gegeven context en dat een waarde slechts één naam mag hebben, terwijl in andere naamgevingsschema’s één naam kan overeenkomen met meerdere waarden, of één waarde meerdere namen kan hebben, zelfs in dezelfde context. Een ander soort uniekheidsregel is die van een unieke identifier-naamruimte, die een reeks namen verschaft die nooit opnieuw zullen worden gebruikt gedurende de levensduur van de naamruimte en, eenmaal gebonden, altijd gebonden zullen blijven aan dezelfde waarde. Van een dergelijke naam wordt gezegd dat hij een stabiele binding heeft. Indien een unieke identifier-naamruimte ook de regel heeft dat een waarde slechts één naam kan hebben, worden de unieke namen nuttig voor het bijhouden van objecten over een lange periode, voor het vergelijken van referenties om te zien of zij naar hetzelfde object verwijzen, en voor de coördinatie van meervoudige kopieën in systemen waar objecten worden gerepliceerd voor prestaties of betrouwbaarheid. Zo vormt het rekeningnummer van de klant in de meeste factureringssystemen een unieke identificatienaamruimte. Het rekeningnummer zal altijd verwijzen naar de rekening van dezelfde klant zolang die rekening bestaat, ondanks wijzigingen in het adres, het telefoonnummer of zelfs de persoonsnaam van de klant. Als een rekening van een klant wordt verwijderd, zal het rekeningnummer van die klant niet opnieuw worden gebruikt voor een andere rekening van een klant. Genoemde velden binnen de rekening, zoals het verschuldigde saldo, kunnen van tijd tot tijd veranderen, maar de binding tussen het rekeningnummer van de klant en de rekening zelf is stabiel.
Het algoritme voor het toewijzen van namen en een enkele context wijzen niet noodzakelijk alle namen van de naamruimte toe aan waarden. Een mogelijk resultaat van het uitvoeren van resol kan dus een “not-found” resultaat zijn, dat resol aan de aanroeper kan meedelen als een gereserveerde waarde of als een uitzondering. Aan de andere kant, als het naamgevingsschema toestaat dat één naam overeenkomt met meerdere waarden, kan een mogelijk resultaat een lijst van waarden zijn. In dat geval kan de ontkoppelbewerking een extra argument vereisen dat specificeert welke waarde moet worden ontkoppeld. Tenslotte voorzien sommige naamgevingsschema’s in reverse lookup, hetgeen betekent dat een aanroeper een waarde als argument kan geven aan het naamtoewijzingsalgoritme, en kan achterhalen welke naam of namen aan die waarde zijn gebonden.
Figuur 2.10 illustreert het naamgevingsmodel, met een naamruimte, het bijbehorende universum van waarden, een naamtoewijzingsalgoritme, en een context die het naamtoewijzingsalgoritme bestuurt.
In de praktijk komt men drie vaak gebruikte naam-toewijzingsalgoritmen tegen:
Tabel lookup
■
Recursieve lookup
■
Multiple lookup
De meest voorkomende implementatie van een context is een tabel van {naam, waarde} paren. Wanneer de implementatie van een context een tabel is, is het naam-toewijzingsalgoritme slechts een opzoeking van de naam in die tabel. De tabel zelf kan complex zijn, met hashing of B-trees, maar het basisidee is nog steeds hetzelfde. Het binden van een nieuwe naam aan een waarde bestaat uit het toevoegen van dat {naam, waarde} paar aan de tabel. Figuur 2.11 illustreert deze algemene implementatie van het naamgevingsmodel. Er is een dergelijke tabel voor elke context, en verschillende contexten kunnen verschillende bindingen voor dezelfde naam bevatten.
Echte voorbeelden van zowel het algemene naamgevingsmodel als de implementatie van tabelopzoeking zijn er in overvloed:
Een telefoonboek is een tabelopzoekingscontext waarin namen van personen en organisaties aan telefoonnummers worden gekoppeld. Net als in het voorbeeld van het datacommunicatienetwerk zijn telefoonnummers zelf namen die door de telefoonmaatschappij worden omgezet in fysieke telefoonlijnen, met behulp van een algoritme voor het toewijzen van namen waarbij netnummers, centrales en fysieke schakelapparatuur betrokken zijn. De telefoonboeken van Boston en San Francisco zijn twee contexten van hetzelfde naamgevingsschema; een bepaalde naam kan in beide telefoonboeken voorkomen, maar als dat zo is, is hij waarschijnlijk gebonden aan verschillende telefoonnummers.
Kleine gehele getallen geven de registers van een processor een naam. De waarde is het register zelf, en de toewijzing van de naam aan de waarde wordt bewerkstelligd door bedrading.
Geheugencellen krijgen een soortgelijke naam met de getallen die adressen worden genoemd, en de toewijzing van de naam aan de waarde wordt eveneens bewerkstelligd door bedrading. Hoofdstuk 5 beschrijft een mechanisme voor het hernoemen van adressen dat bekend staat als virtueel geheugen, dat blokken van virtuele adressen bindt aan blokken van aaneengesloten geheugencellen. Wanneer een systeem meerdere virtuele geheugens implementeert, is elk virtueel geheugen een afzonderlijke context; een gegeven adres kan verwijzen naar een verschillende geheugencel in elk virtueel geheugen. Geheugencellen kunnen ook worden gedeeld tussen virtuele geheugens, in welk geval dezelfde geheugencel dezelfde (of verschillende) adressen kan hebben in verschillende virtuele geheugens, zoals bepaald door de bindingen.
Een typisch computerbestandssysteem gebruikt verschillende lagen van namen en contexten: schijfsectoren, schijfpartities, bestanden en mappen zijn allemaal benoemde objecten. Directories zijn voorbeelden van tabel-opzoek-contexten. Een bepaalde bestandsnaam kan in verschillende directories voorkomen, gebonden aan dezelfde of verschillende bestanden. Paragraaf 2.5 geeft een casestudy van naamgeving in het unix-bestandssysteem.
Computers maken verbinding met datacommunicatienetwerken op plaatsen die bekend staan als netwerkaansluitpunten. Netwerkaansluitpunten worden gewoonlijk benoemd met twee verschillende naamgevingsschema’s. De eerste, die binnen het netwerk wordt gebruikt, omvat een naamruimte die bestaat uit getallen in een veld met een vaste lengte. Deze namen zijn gebonden, soms permanent en soms slechts kort, aan fysieke ingangs- en uitgangspunten van het netwerk. Een tweede naamgevingsschema, dat door de cliënten van het netwerk wordt gebruikt, brengt een meer gebruikersvriendelijke universele naamruimte van tekenreeksen over op namen van de eerste naamruimte. Paragraaf 4.4 is een casestudy van het Domain Name System, dat voorziet in gebruikersvriendelijke naamgeving van bevestigingspunten voor het internet.
Een programmeur identificeert procedurevariabelen met namen, en elke activering van de procedure biedt een afzonderlijke context waarin de meeste van dergelijke namen worden opgelost. Sommige namen, aangeduid als “statische” of “globale namen”, kunnen in plaats daarvan worden opgelost in een context die wordt gedeeld door activeringen of door verschillende procedures. Wanneer een procedure wordt gecompileerd, kunnen sommige van de oorspronkelijke gebruikersvriendelijke namen van variabelen worden vervangen door integer identifiers die handiger zijn voor een machine om te manipuleren, maar het naamgevingsmodel blijft van kracht.
Een Uniform Resource Locator (URL) van het World Wide Web wordt aan een specifieke webpagina gekoppeld door een relatief gecompliceerd algoritme dat de URL opdeelt in verschillende samenstellende delen en de delen omzet met behulp van verschillende naamgevingsschema’s; het resultaat identificeert uiteindelijk een specifieke webpagina. Paragraaf 3.2 is een casestudy van dit naamgevingsschema.
In een factureringssysteem voor klanten worden doorgaans ten minste twee soorten namen voor elke klantrekening bijgehouden. Het rekeningnummer geeft de rekening een naam in een unieke identificatienaamruimte, maar er is ook een afzonderlijke naamruimte van persoonsnamen die ook kunnen worden gebruikt om de rekening te identificeren. Beide namen worden gewoonlijk door een database-systeem toegewezen aan rekeningrecords, zodat rekeningen kunnen worden opgezocht hetzij op rekeningnummer hetzij op persoonlijke naam.
Deze voorbeelden benadrukken ook een onderscheid tussen “naming” en binding. Sommige, maar niet alle contexten “noemen” dingen, in die zin dat zij een naam toewijzen aan een voorwerp waarvan algemeen wordt gedacht dat het die naam heeft. Zo “noemt” het telefoonboek noch mensen, noch telefoonlijnen. Ergens anders zijn er contexten die namen verbinden aan mensen en die telefoonnummers verbinden aan bepaalde fysieke telefoons. Het telefoonboek koppelt de namen van mensen aan de namen van telefoons.