De Terugkeer van Dynamisch Typen: Is Het Mogelijk?

Of was statisch typen toch het juiste paradigma?

Foto door Michael Marais op Unsplash

Statisch typen heeft gewonnen! Kijk maar op Quora of Stack Overflow, en je zult zien dat de topantwoorden statisch typen verkiezen.

JavaScript wordt TypeScripted. Python en PHP zijn type-gehint. En de populariteit van Java, Go en Rust is pas nieuw gemunt!

En als je de status quo uitdaagt, zoals DHH deed, loop je het risico geannuleerd te worden.

Om te begrijpen waarom statisch typen heeft gewonnen, moet men eerst de denkwijze achter dit programmeerparadigma begrijpen.

Statisch Typen Is Een Denkwijze Voor Het Een CS-Term Is

Om uit te leggen wat ik bedoel met "een denkwijze," laat me de volgende computerwetenschapstermen kort uitleggen:

Statisch vs. Dynamisch Type Checking: In een statisch getypeerde taal zijn variabele types bekend op compiletijd en veranderen niet zodra ze zijn ingesteld. Voorbeeld: Als x een integer is, zal het dat blijven.

Sterk vs. Zwak Typen: Sterk typen handhaaft strikte type regels, voorkomt impliciete conversies. Voorbeeld: Als x een integer is, kun je het niet samenvoegen met een string.

Zoals je kunt zien, vormen de twee dichotomieën een twee-bij-twee matrix. Een taal kan dynamisch maar sterk getypeerd zijn, bijv. Python. In dergelijke gevallen zijn het waarden, in plaats van variabelen, die de types vasthouden.

Statisch vs Dynamisch, Sterk vs Zwak Typen Matrix

Het combineren van de kenmerken van het rechterbovenkwadrant geeft ons de volgende functies:

We kunnen beslissen welk type een variabele vasthoudt, en ervoor zorgen dat de computer ze nooit zal veranderen of impliciet zal converteren in de loop van de tijd.

De eerste drie woorden van deze zin geven je al een idee van wat ik bedoel met de statische typering denkwijze hier: "We kunnen beslissen."

Dit geeft de programmeur de autoriteit die ze nodig hebben om de juistheid van hun code te waarborgen. Dit resoneert met het volgende citaat:

"Het goede nieuws over computers is dat ze doen wat je ze zegt te doen." — Ted Nelson

Door je te concentreren op deze behoefte aan juistheid, kun je zien dat statisch typen een denkwijze is die verder gaat dan de eerder genoemde computerwetenschapsconcepten.

Laat me Python gebruiken om uit te leggen wat ik bedoel, hoewel je de volgende voorbeelden gemakkelijk kunt vertalen naar je favoriete taal.

De Statische Typering Denkwijze in Python

Het voor de hand liggende voorbeeld is type-hints en mypy, maar dat is slechts het topje van de ijsberg.

Data classes vs dictionaries

Neem het volgende voorbeeld:

def get_user_details() -> Dict:
    return {
        "first_name": "Bart",
        "last_name": "Simpson",
    }

Het is onwaarschijnlijk om deze code in grotere codebases te zien. De programmeur hier kreeg een A voor hun type-hinting inspanningen, maar de Dict zegt niet veel over welke keys deze dictionary bevat.

De aanroeper van deze functie zal breken als de keys van de dictionary worden gekapitaliseerd, bijvoorbeeld, of als het family_name retourneert in plaats van last_name. Strings zijn te, ehm, dynamisch.

Dus deze dictionary wordt meestal vervangen door een object. Objecten hebben vaste attributen met goed gedefinieerde spellingen. Een data class heeft meestal de voorkeur hier aangezien ze de __init__'s boilerplate minimaliseren.

Dus je zult waarschijnlijk de volgende code tegenkomen in grotere codebases:

@dataclass
class UserDetails:
    first_name: str
    last_name: str


def get_user_details():
    return UserDetails(
        first_name="Bart",
        last_name="Simpson",
    )

Ik heb de methode opzettelijk niet type-gehint. Deze denkwijze hangt af van wat men als typen beschouwt.

Ik hoop dat dit voorbeeld verduidelijkte dat typen een denkwijze is die los staat van wat een taal biedt — net als Object Oriented Programming (OOP). Ik schreef vroeger OOP code in talen die geen classes ondersteunen. Evenzo kan men de typering denkwijze toepassen op de meest dynamisch getypeerde taal of de meest statische taal hacken om dynamisch te worden als ze dat willen.

OK, tijd voor nog een voorbeeld.

Enums vs strings

Evenzo hebben enums (enumerated type) de neiging om strings te vervangen in specifieke use cases. Hier is een voorbeeld:

if state == "alive":
    normal_walk()
elif state == "dead":
    lie_down()
elif state == "zombie":
    zombie_walk()

Om dezelfde redenen dat data classes dicts vervangen, wordt de bovenstaande code meestal vervangen door de volgende:

class State(Enum):
    ALIVE = 1
    DEAD = 2
    ZOMBIE = 3


if state == State.ALIVE:
    normal_walk()
elif state == State.DEAD:
    lie_down()
elif state == State.ZOMBIE:
    zombie_walk()

Opnieuw, niet één type werd hier gehint, maar de denkwijze zegevierde.

Ik kan aan meer voorbeelden denken, maar ik hoop dat je mijn punt al hebt begrepen, en ik zou blij zijn als je me laat weten over je favoriete voorbeelden in dezelfde richting.

Ik kan de verdiensten van deze denkwijze niet ontkennen.

Zoals je kunt zien, biedt deze denkwijze veel voordelen. Het voorkomt onnodige fouten. En ik profiteer er elke dag van in mijn code.

Niet alleen ik; mijn IDE ook.

Moderne IDE's, zoals PyCharm, zullen je belonen met code voltooiing en je wijzen op fouten in je code als je type hints en de statische typering denkwijze in het algemeen gebruikt.

Maar is deze denkwijze het panacee van software design? Is er ook een dynamische typering denkwijze? Wat zullen we missen als we dit alternatieve denkwijze opgeven?

Om deze vragen te beantwoorden, moet ik twee gerelateerde velden vergelijken: software engineering en kunstmatige intelligentie.

Symbolische AI is de Statische Typering van AI

In de vroege dagen van kunstmatige intelligentie was de dominante benadering Symbolische AI. Het hoofdidee is dat menselijke programmeurs de slimmeriken in de kamer zijn.

Ze voorzien de computer van handgemaakte kennis in de vorm van regels, en de computer gebruikt zijn rekenkracht om oplossingen voor de problemen bij de hand te zoeken en te vinden op basis van de gegeven regels.

Ik kan deze benadering als volgt samenvatten:

We kunnen beslissen welke regels te gebruiken bij het oplossen van een probleem, en ervoor zorgen dat de computer ze nooit verandert of impliciet bewerkt in de loop van de tijd.

Ik hoop dat je de overeenkomsten kunt zien tussen mijn Symbolische AI definitie en mijn statisch-en-sterk typen definitie:

We kunnen beslissen welk type een variabele vasthoudt, en ervoor zorgen dat de computer ze nooit zal veranderen of impliciet zal converteren in de loop van de tijd.

De uitdaging met beide denkwijzen is dat we, in het streven naar juistheid, de mogelijkheden van onze software beperken tot alleen wat we kunnen begrijpen en binnen onze eigen mentale beperkingen kunnen passen.

En als Symbolische AI de statische typering van AI is, dan is machine learning zijn dynamische typering.

In beide velden zijn we heen en weer geschakeld van de ene kant van de dichotomie naar de andere.

Een stap terug doen, kan men deze dichotomie generaliseren en terugvoeren naar David Hume's "Probleem van Inductie" en de dichotomie tussen deductief en inductief redeneren.

Het traceren van de historische oorsprong van deze dichotomie laat iemand argumenten van beide kanten lenen om hun standpunt te rechtvaardigen. Pre-Hume boden oude Griekse en Indiase filosofen ook ondersteunende argumenten. Maar laten we ons nu concentreren op één argument.

In deductie vs inductie komt juistheid ten koste van algemeenheid.

De "Alive-Dead-Zombie" code hierboven zal crashen als het toevallig Jezus Christus tegenkomt. En we weten allemaal wat er gebeurde met Symbolische AI, gezien het inductiekamp—machine learning, deep learning en large language models — tegenwoordig zijn kont schopt.

Natuurlijk geldt hetzelfde juistheidsargument in AI. Niemand vertrouwt de outputs van ChatGPT, maar je kunt het niet negeren, gezien zijn bruikbaarheid.

En trouwens, er is een voortzetting van Ted Nelson's eerdere citaat dat ik noemde. Hij voegde het volgende erachter:

"Het slechte nieuws is dat ze doen wat je ze zegt te doen." — Ted Nelson

Je wilt niet dat computers altijd doen wat je ze zegt te doen. Soms wil je dat ze doen wat je wilt dat ze doen. En de twee zijn niet altijd hetzelfde.

Daarom geloof ik dat er een toekomst is waar computertalen zullen doen wat ik wil dat ze doen.

De Computertalen van de Toekomst

Natuurlijk kan niemand de toekomst zien, maar zoals William Gibson zegt: "De toekomst is al hier — het is gewoon niet gelijkmatig verdeeld."

Dus hints van hoe computertalen eruit zullen zien kunnen worden gevonden op plaatsen anders dan programmeren.

Neem het volgende voorbeeld, waar men deze JavaScript eigenaardigheid kan wijten aan zijn zwakke typering:

"11" + 1 // Geeft ons '111'
"11" - 1 // Geeft ons 10

Omgekeerd was Python 2 even eigenaardig vanwege zijn sterke typering deze keer.

3 / 2 # Geeft ons 1 in plaats van 1.5

Raad eens wie niet zo eigenaardig is als de vorige twee talen? ChatGPT!

Prompt: 1 + 3

De som van 1 en 3 is 4.

Prompt: "2" + "2"

De expressie "2" + "2" voegt de twee strings samen, resulterend in "22".

Prompt: 1/1/2020 + two weeks

Als we aannemen dat "1/1/2020" 1 januari 2020 vertegenwoordigt, zou het toevoegen van twee weken aan die datum resulteren in 15 januari 2020.

Dit geeft me ideeën over hoe toekomstige programmeertalen zich zullen gedragen.

En totdat deze nieuwe talen zich materialiseren, zal ik ideeën uit elk paradigma mixen en matchen zonder dogmatisch te zijn over één en slechts één juiste benadering voor het oplossen van problemen.


Tarek Amr, 22 juli 2023

Vertalingen: [EN], [AR]