Dynamische talen (vervolg)

Een voordeel van static typed languages is dat de IDE je makkelijker kan helpen met autocomplete. Je bent minder lang bezig met het zoeken naar de methode die je wilt gebruiken. En als de methode nog niet bestaat wil de IDE wel een stub voor je genereren op de juiste plek. Je kunt dus vrij snel code schrijven.

Code moet je echter ook lezen en dat doen we eigenlijk veel meer dan code schrijven. Als de code makkelijker te lezen is en dus makkelijker te begrijpen kunnen we ook sneller programmeren.

Wat voorbeelden van moeilijk leesbare code zien we in Java met generics:

1
Map <Long, CompanyDataInt> companiesMap = new HashMap <Long, CompanyDataInt>();

Het kan nog erger als je een collectie van een collectie typesafe wilt maken. De zelfde code nu in Smalltalk:

1
companiesMap := MappedCollection new.

Een stuk minder code en veel sneller te lezen en te begrijpen. Een voorbeeld waar extra code wel toegevoegde waarde heeft zien we bij named arguments.

In onderstaande Java code moet je de methode definitie kennen om te weten wat de rol van de argumenten is.

1
companiesMap.put(company.getCompanyId(), company);

Smalltalk bevat named arguments:

1
companiesMap at: (company companyID) put: company.

Nu net zo veel code, maar de named arguments geven beter weer wat de rollen van de argumenten zijn. Het is extra informatie voor de lezer en niet voor de compiler.

Dynamische talen

Ik merk dat ik nog moeite heb met uitleggen wat de voordelen zijn van dynamic typed languages t.o.v. static typed languages, maar laat me het toch proberen.

In static typed languages bepaald het type welke boodschappen je kunt sturen naar een object. Maar heel wat objecten kunnen hetzelfde gedrag tonen terwijl ze niet van hetzelfde type hoeven te zijn.

Je kunt je fiets op slot doen en je kunt je huis op slot doen. Qua gedrag vergelijkbare acties met als doel het object te beveiligen. Fiets en huis hoeven echter niet in dezelfde class hierarchie te zitten. Fiets kan vervoermiddel als base class hebben en een huis kan gebouw als base class hebben. Als je nu een "beveiliger" object hebt die alle objecten op slot moet zetten is het voor dit object lastiger om door de collectie van de te beveiligen objecten te lopen en te zeggen: "gaOpSlot". Je moet eerst een "sluitbaar object" interface definieren met een "gaOpSlot" methode en deze door fiets en huis laten implementeren. De beveiliger kan dan zijn actie op een collectie van "sluitbare" objecten uitvoeren.

fiets

In een dynamische taal hoeft dat niet. Je geeft de te beveiligen objecten aan de beveiliger. Deze stuurt de boodschap "gaOpSlot" naar zowel fiets als huis en deze gaan op slot. En als er objecten zijn die niet op slot kunnen, zoals een televisie, dan krijgt de beveiliger een exceptie: "boodschap niet begrepen" terug. Deze kan dan afgevangen worden en de beveiliger gaat gewoon verder met de volgende objecten die wel op slot kunnen.

In een dynamische taal gaat het er dus om wat een object kan en niet wat het is. Als je op slot kunt, boeit het niet of je een fiets, huis of kluis bent.

Nu is een interface definieren niet zo een probleem, maar is wel wat overhead. En voordat je denkt heb je een "verkoopbaar", "verzekerbaar", enz. interface erbij. De hierarchie en leesbaarheid van de code wordt er niet beter op.

De overhead en complexiteit maakt dan ook dat we in static typed languages minder gedrag in de objecten zelf stoppen. We kiezen ervoor om aparte service, manager of controller objecten te definieren. De domein objecten zijn vaak niet meer dan een abstractie bovenop de database tabellen en hebben geen gedrag. En dit is in feite gewoon structureel programmeren met iets intelligentere datatypes.