Ja, hallo, liebe Hörerinnen und Hörer, willkommen beim Python-Podcast, heute Episode 54.
Wir reden heute über Types, Typings und Typescript.
Hallihallo.
Hallihallo, willkommen Dominik und...
Hallo Johannes.
Hallo zusammen.
Und hallo Stefan.
Genau.
Ja, hallo Stefan.
Auch ein Gast heute.
Genau.
Ja, wir freuen uns sehr, dass ihr alle da seid und fangen einfach mit News an, wie sonst auch immer.
Ja, würde ich schon sagen.
Was gab es denn Schönes?
Wer möchte anfangen, soll ich?
Ja, fang du mal an.
Na gut, ja, also ehrlich gesagt, das letzte Mal war nicht so lange her, daher habe ich ja nicht so viel gesammelt.
Heißt ein 3.12.1.
Genau, das ist natürlich irgendwie, es stand irgendwie dabei, so 400 Bugfixes und so, also sollte man wahrscheinlich mal installieren und meine Frage dazu wäre halt, bist du jetzt schon umgestiegen auf 3.12, weil du wolltest ja immer nur die erste meiner Version abwarten, aber dann auch, ja?
Ja, also noch nicht mit allen Sachen, aber
mit vielen Sachen.
Also 3.12, das ist bei 1 draufgekommen und
jetzt in meinem Systeminterpreter
zum Beispiel ist das auf 3.12.
Hervorragend. Tja, aber ich glaube
da war nichts,
also außer Bugs ist da nichts irgendwie
passiert. Mein Hauptproblem im Moment
ist halt PyTorch oder sowas, wo es auch im
Dezember einen Release gab, dass es jetzt endlich mit 3.11
funktioniert. Ah, ja, ja.
Ja, ansonsten
genau neue Releases. Es gab
neue Ruby on Rails
Release. Ich gucke da ab und zu mal so
rüber, weil ich halt interessant finde, wie viel
tolles
Zeug da passiert. Und das ist jetzt
deutlich schneller geworden.
Hat irgendwie einen eingebauten
Time-Compiler und
verwendet jetzt einen ähnlichen
Ansatz für den Parser, wie
Python halt auch. Python ist ja jetzt mit
3.9 auf dem Pack-Parser umgestiegen.
Und das
ist, Ruby verwendet da jetzt was
ganz ähnliches. Ist auch so ein
rekursives Dings da, Parsen
ich weiß nicht, ich habe es wieder vergessen, wie das
genau heißt, so ähnlich. Und sie sind
auch umgestiegen von Bison, also dem Pasa-Generator
auf den anderen. Ich habe, finde ich, schon ganz oft
Lob für Ruby gehört, muss ich ehrlich
sagen. Ja, und auch bei dieser
ganzen Just-in-Time-Compile-Geschichte,
da ist, glaube ich, einer
der Hauptsponsoren auch Shopify.
Ja, genau.
Also es gibt ja viele große
Unternehmen, die hauptsächlich
auf Ruby und Rails-Moduliten basieren
und da kommt halt auch
eine Menge Geld rein.
und ja, Python ist ja jetzt auch
dran mit diesem Just-in-Time-Compiler
Thema, da in 3.13 kommt das ja auch.
Das wäre meine News gewesen, Jochen. Achso, sorry.
Dann schieb's mal los.
Ja,
Ende Dezember
ist wohl ein Patch in den 3.13
Branch reingekommen, wo ein JIT-Compiler
drin ist für Python. Also es ist jetzt
richtig im Plan drin, dass Python
in 3.13 einen JIT-Compiler hat, einen Copy-and-Patch
JIT-Compiler, was
auch immer das bedeuten mag.
Da gab es auch angeblich eine wundervolle Diskussion
auf Reddit zu...
Ja, also
es gibt einmal die, ich kann empfehlen,
es gibt Core-PY, das ist
ein Podcast, wo zwei der Core-Entwickler
irgendwie drüber reden. Da gibt es eine
Episode zum Just-In-Time-Compiler.
Und dann... Wer sind dabei?
Shannon und Sean? Oder wie ist das?
Nee, das
sind Pablo Galindo
Salgado, der Release-Manager
auch für die, für 3.13.
Und, äh, Lukas Schlanger.
Ah ja. Genau.
Und, ähm, genau, die haben da einmal drüber geredet
und, äh, daher weiß ich auch,
dass das, ähm, das basiert
hauptsächlich, also warum man das jetzt nochmal
in Angriff nimmt, auf
Geschichten, die in Lua passiert sind.
Da gab's jetzt auch irgendwelche,
ich hab jetzt wieder die Details vergessen, aber so
Papers, äh, die sehr, sehr interessant
aussahen und die halt vermuten lassen,
dass man's relativ leicht, äh, irgendwie auch für Python
verwenden kann und, ähm, ja, das ist
halt ein InPython in, in, in,
Ruby, da werden überall diese
Dinger jetzt gerade eingebaut.
Und hier der, der wegen dem PyPy
auch hier war schon,
der meinte
auch so, oh, er muss jetzt mal sein
Commit-Bit
wieder
hochfahren, quasi aus
erneuern lassen. Ja, es gab ja immer, dass halt die neuen
Versionen deutlich einfacher zu implementieren sind
bei PyPy, wenn das drin ist,
was da in C-Extensions irgendwie dazukommen
sollte, wollte, wenn ich das
richtig verstanden hatte damals.
Ja, also jedenfalls, der macht da jetzt auch mit.
Und das wird auf jeden Fall spannend.
Ein schnelles Python.
Ja, genau.
Ja, ansonsten hätte ich jetzt noch das,
ich habe ja jetzt mich auch hier an dieser Stelle
schon irgendwie ein paar Mal beschwert
über irgendwie sehr holprige Updates von Python.
Über mich?
Über dich.
Entschuldigung.
Ja, gut.
Über Pydentic 2,
über den Umstieg von Pydentic 1 auf 2.
Und jetzt haben das andere Leute auch gemacht,
Simon Willison hat da in letzter Zeit relativ viel zu gepostet,
dass er das irgendwie ungünstig fand.
Und da habe ich dann auch so Sachen gesehen wie,
es gab da ein Issue zu, wo dann einer von Netflix oder so
in relativ freundlichem Ton zunächst schrieb,
das macht bei uns sehr viel Arbeit und das war jetzt alles nicht so günstig.
Und ich habe dann geguckt, der hat dann auch irgendwann beschrieben,
welche Issues, die da reingelaufen sind.
Und das war halt zum Beispiel auch einer von den Dingern,
in die ich da reingerannt bin.
ja, genau, der meinte dann
so, tja, also sauberer wäre es gewesen, wenn man
das Paket irgendwie umbenannt hätte oder so
und das wollten sie aber nicht machen
und dann haben sie gesagt, nee, das geht auch
so oder geht so, aber es ging alles nicht und es war
relativ furchtbar, also
gerade wenn man eine Library ist, hat man damit halt
ein großes Problem, weil man nicht kontrollieren kann,
was in der Applikation, die
einen benutzt, halt irgendwie für eine
Pidentic-Version ist und zum Beispiel
FastAPI hat damit auch ein Riesenproblem gehabt
und wie die das dann letztendlich gemacht
haben, ist, sie haben halt so einen Flag eingeführt,
Pydentic V2, und machen
dann jetzt gerade sowas wie, if Pydentic
V2, 500
Zeilen eingerückt, irgendwie
Kompatibilitätsleer, und dann
else, und dann sonst, und das
haben sie an mehreren Stellen, das ist wirklich absolut schrecklich.
Naja, aber so sieht's halt
aus, also das war, dieses Update war
nicht wirklich
reibungslos, sondern da haben
viele Leute irgendwie eine Menge
Schweiß gelassen, naja.
Also nicht durch.
Okay, also gut, wenn man es nicht zu sehr drin hat.
Ich habe tatsächlich auch
zwischendurch noch auf eins dependen müssen,
weil da so bei zwei Sachen nicht so ging,
was jetzt irgendwie geht, aber ja.
Ein bisschen nervig.
Johannes, hast du noch was?
Nee, also in der TypeScript-Welt
gibt es sowas nicht.
Aber jetzt können wir uns über TypeScript-Versionen unterhalten.
Apropos,
ich habe gehört, dass ein neues Buch erschienen
in der TypeScript-Welt.
Echt, was? Das ist mir ganz neu.
Ja, ich glaube, das muss der Stefan mal so ein bisschen erzählen.
Ist das jetzt mein Intro, oder was?
Ja, das war die softeste Überleitung.
Ja, das war der softeste Übergang,
den der Dominik macht.
Ich habe das jetzt total spannend gefunden,
weil es wird ja immer so
gemunkert,
dass im Web-Bereich
gibt es ja quasi alle drei Minuten
irgendeinen neuen Fachbegriff
oder irgendeinen neuen Bibliothek-Namen
oder irgendein neues JavaScript-Framework,
das irgendeinen abstrusen
Namen hat, mit dem
sie alle nachher irgendwie auseinandersetzen müssen.
und das ist jetzt das zweite Mal, dass ich so in diese Python-Ecke reinschaue
und denke mir, hey, komm, das ist ja da genau das Gleiche.
Den ersten Namen, den ich erkannt habe, das war FastAPI,
weil tatsächlich, das ist spannend, ich bin jetzt seit vier, fünf Monaten
bei uns in der Firma mit einer Gruppe Python-Developern unterwegs,
Data Scientist, ganz klassisch, du hast einen Data Scientist
und das Tool der Wahl ist Python, die Bibliotheken sind da,
Das Übliche mit Langchain, Pipa Pro für diese ganze LLM-Sache.
Und das war so mein erstes Intro in dieser Python-Welt.
Und ich bin schon massiv gescheitert daran, dass ich den Package-Manager auswähle, der passt.
Da gibt es ja dann Conda, Anaconda, Pep oder sind das ganz andere?
Keine Ahnung. Also wie gesagt, das ist ja schon wieder vorbei.
Aber ich weiß, dass ich FastAPI
nach langen, langen Gesprächen mit unseren
Python-Devs in unser Architektur-
Diagramm eingetragen habe für
irgendeinen Server, den wir gemacht haben.
Das war eben das Erste, wo ich mir gedacht habe,
da kenne ich mich jetzt aus, bei FastAPI
da kann ich mitreden.
Funktioniert
Multithreaded, aber nicht Async.
Ist das richtig?
Also kann man wahrscheinlich so betreiben,
wenn man wirklich will, aber nee, es ist tatsächlich
Async. Also unter FastAPI
liegt normalerweise
so würde ich jetzt mal sagen, wenn man
das so betreibt, wie es gedacht ist,
halt Stalett
beziehungsweise UV-Corn
und das ist halt sozusagen die
Lib-UV, also das ist halt eine Adaption
von Nen-UV, was halt auch unter der
Event-Loop bei Node.js
liegt halt für Python.
Ja, und also ist
halt quasi genauso schnell dann auch
und ist Async, ja.
Cool. Das war die
zweite, war dann, dass ich
versucht habe, über
PyO3 eine Brücke
zwischen Async Rust und
Async Python einmal zu schreiben. Das war spannend.
Das war richtig cool.
Was mich da beeindruckt hat,
und mit dem habe ich nicht gerechnet, ist, dass
das vollen Frankischen Interface von Python
ja fantastisch ist.
Also du hast dort dein kompiliertes
SO-Modul dazu und du kannst
auf die Objektliste zugreifen
und kannst die Identifier herauslesen.
Also das Kompilieren
vom Rust-Code war auf jeden Fall anspruchsvoller,
als wir nachher die Symbole in Python
zu loben und zu verwenden, das war richtig,
richtig beeindruckend. Also
coole Sache, möchte ich mir auf jeden Fall mehr anschauen.
Aber das ist es. Also das sind
meine Python-Kenntnisse.
Ja, aber ich finde auch, das Benutzen von
Python ist halt das, was so Spaß macht.
Also High-Level-Interface,
ich glaube, ist sehr gut geeignet.
Py3, auch ein cooles Beispiel. Da gibt es die meisten
Sachen, die es irgendwie kann. Ich glaube, was es nicht kann, ist
irgendwie Iteratoren
ausspucken, richtig, oder so, oder Generatoren.
Ja, das wird wahrscheinlich schwierig sein.
Das kann ich mir gut vorstellen.
Keine Ahnung.
Da ist dieses Typsystem von Rust halt doch sehr, sehr eigen
und sehr schwierig, in andere Sprachen zu integrieren, nehme ich mal an.
Ja, aber ich hatte ja als News ja auch quasi noch ein bisschen Werbung gemacht für dein Buch.
Vielleicht willst du dazu noch irgendwie kurz was sagen?
Ja, dankeschön. Danke für diese Überleitung.
Ich habe tatsächlich in den letzten Jahren TypeScript-Bücher geschrieben.
Das erste Buch, das ich geschrieben habe, war in 2020 TypeScript in 50 Lessons,
das beim Smashing Magazine Verlag rausgekommen ist,
das als angenehmer, unaufgeregter Einstieg in TypeScript als Typsystem auf JavaScript gedacht ist.
Das Zielpublikum waren Entwicklerinnen und Entwickler, die JavaScript schon kennen,
sich dort auch schon wohlfühlen und jetzt merken, jetzt müssen sie TypeScript verwenden,
Wir brauchen die Info, warum man das erstens überhaupt haben will und zweitens, wie das jetzt so richtig funktioniert und warum es da so viel Syntax gibt und warum das so kompliziert ausschaut und versucht, das grundlegende System, Typsystem runterzubrechen auf einfach zu verdauende Lektionen.
Genau, das war das Ziel von dem Buch, das habe ich dann zufälligerweise in 50 Lektionen geschafft, das war ein Riesenspaß, das war quasi mein Corona-Projekt, mein erstes Lockdown-Projekt, wobei es stimmt nicht, ich habe zwischen dem ersten und dem zweiten Lockdown tatsächlich das meiste geschrieben.
Das ist auch tatsächlich ein Schicksal, das sieht auch super aus, also von außen, wenn du in den Schrank stellst.
Wir wissen das, weil wir dieses Buch auch alle haben, zwar als Paltenentwickler, was natürlich auch schon was heißt.
Das macht mich irrsinnig happy.
Ihr kennt sich das nicht vorstellen.
Das sind diese unglaublich schönen Momente,
wenn man sieht,
dass das Buch tatsächlich an Leute kommt
und Leute das verwenden.
Also die Lesepäntchen gesehen herrlich spitze.
Und die Optik ist wirklich ganz, ganz besonders,
weil das war eigentlich auch ein Grund,
warum ich mit Smashing Magazine zusammenarbeiten wollte.
Die haben einfach irrsinnig viel Liebe zum Detail
und versuchen wirklich sehr individuelle Bücher zu machen,
haben eine wunderschöne Typografie,
die sauber zu lesen ist
und verzetteln sich dann in kleinen Finessen so stark.
Und ich habe zum Beispiel,
das Cover wurde gestaltet von Rob Draper,
den habe ich tatsächlich in Düsseldorf kennengelernt,
auf der Björn Tellerrand,
der als Künstler die Intro-Grafiken
zu den Golden Globes gemacht hat,
für Nike und BMX-Fahrräder
beziehungsweise Schuhe designt hat.
Und der mich gefragt hat,
ich habe ihm eine E-Mail geschrieben,
hey, der Robert ist cool,
möchtest du mein Buch designen?
Ja, passt. Und ich habe gedacht, hey, wow, cool.
Ich hoffe, er kostet jetzt nicht eine Million oder so.
Und er hat tatsächlich dann unser Buch, also das Buch gestaltet,
also versucht er mit diesem Kapitel in Lays ein bisschen das Ganze zugänglich zu machen,
freundlich zu machen. Das war uns ganz, ganz wichtig.
Und die Person, die nachher, also die Ari, die nachher das Ganze gesetzt hat
und versucht hat, ein Produkt daraus zu machen, hat dann auch recherchiert
und hat zum Beispiel das Lesebändchen, das rote Lesebändchen,
in der Farbe bestellt von den roten Unterlinien in Visual Studio Code.
Das heißt, das ist der gleiche Farbton.
Und so tief ins Detail geht es dort.
Und das ist halt einfach absolut herrlich für mich,
der praktisch nur den Text beigetragen hat,
dass du siehst, wie andere Leute sich so investieren in dieses Projekt
und versuchen, gemeinsam da irgendwas Cooles draus zu machen.
Also da kriege ich heute noch Gänsehaut.
Und es ist ja für mich so, ich weiß, es ist mein Buch, aber es ist nicht nur mein Buch.
Also da sind so viele Leute daran beteiligt gewesen.
Es war ein irrsinnig cooler Effort von so vielen Menschen.
Und das macht mich einfach jedes Mal wieder glücklich,
wenn ich dann sehe, dass das Leute auch so sehen, sie das in die Bücherregale stellen.
Oder das Beste, was du machen kannst, hast du einen Zoom-Call,
stell es in den Hintergrund und schick mir ein Foto von dem Zoom-Call.
Das ist das Allerbeste. Das macht mir die größte, größte Freude.
Es hat eine Freude für mich gemacht, wie er ein Interview für sein Start-up gemacht hat.
Auf einmal sehe ich, da ist mein Buch im Hintergrund.
Herrlich, also macht riesen Spaß.
Das war das erste TypeScript-Buch.
Ich habe dann noch ein zweites TypeScript-Buch geschrieben.
Das ist erst im September rausgekommen, also ist noch ganz, ganz frisch.
Das ist das TypeScript-Cookbook, das jetzt mit O'Reilly veröffentlicht worden ist.
Das war praktisch eine Auftragsarbeit.
Also O'Reilly hat so diese Acquisition Editors, die suchen halt noch potenziellen Autoren,
schlagen denen Buchprojekte vor oder schlagen vor, hey, möchtest du zu dem Thema was schreiben?
Und sie haben gesagt, sie wollen ein TypeScript-Buch veröffentlichen in diesem Stil wie TypeScript in 50 Lessons,
ob ich mir vorstellen kann, noch ein solches zu schreiben.
Und am Anfang haben wir gedacht, nein, das geht nicht, ich habe jetzt schon ein Buch geschrieben,
ich habe halt einfach eine gewisse Ansicht, eine gewisse Stimme, eine gewisse Idee zu dem Ganzen.
Habe aber gedacht, naja, meine Saisonreile probierst du doch mal, dass du kurz ein Inhaltsverzeichnis unterschreibst, wie du dir ein zweites Buch vorstellen kannst. Und gerade habe ich 100 weitere Einträge gehabt innerhalb von drei Stunden. Also ich bin mir am Nachmittag hingesetzt und habe gedacht, ups, wow, da ist ein Buch da.
Ich bin mit denen in einen Vertrag gegangen und habe dann versucht, den Nachfolger vom TypeScript in 50 Lessons Buch zu schreiben.
Wenn du in TypeScript in 50 Lessons lernst, wie das Typsystem funktioniert, lernst du im TypeScript QuickBook alle Dinge, die schief gehen können.
Dinge, die, wenn du wirklich Programme damit schreibst, wo du merkst, da passt gerade was nicht,
da spielt das Typsystem nicht so mit, wie ich mir das denke,
beziehungsweise brauche ich halt irgendeine Technik oder irgendein Prinzip oder irgendein Pattern,
das ich anwenden kann, um einem gewissen Problem.
Im Moment, ich dachte jetzt, so Typen hast du damit nichts mehr schief gehen kann.
Und mit Typen, mit sicheren statischen Typen sind die Sprachen immer ganz besonders gut.
Genau, da beschreibt man nur mehr Programme, die nur mehr funktionieren und man hat keine Bugs mehr und es ist super-happy.
Ja, genau.
Ja, also ich bin eine super Überleitung tatsächlich auf das Thema, was wir heute machen wollen, oder?
Ja.
Also ganz herzlichen Dank, dass du heute da bist, Stefan, das freut uns sehr.
In Python haben wir ja von Typen auch schon
das eine, andere Mal am Rande gehört.
Ja, wir haben diese Episode immer lange vor uns hergeschoben,
weil wir uns nie ausreichend vorbereitet
gefühlt haben dafür, weil das halt so ein großes Thema ist.
Es gibt auch eine ganz große Anti-Fan-Gemeinde
in Python für Types irgendwie.
Es gibt auch viele, die das nicht so mögen, ja.
Wie seid ihr
da so drauf? Also
habt ihr jetzt Typen schon in eurem Python-Code drinnen
oder ist das eher noch so das Buch mit
sieben Siegeln, das ihr nicht öffnen wollt?
Annotationen nutze ich persönlich sehr gerne
insbesondere dann, wenn ich mit anderen Menschen
arbeite, um einfach so zu dokumentieren,
was macht das denn überhaupt.
Das heißt aber nicht, dass das immer stimmt, was da steht.
Das ist aber gefährlich damit.
Ja, also ich
verwende sie auch schon und ich habe halt
ein Projekt mal so komplett
irgendwie annotiert, einfach nur auch,
weil ich wissen wollte, wie schwierig ist es
denn nun, wie weh tut es denn
irgendwie.
Und ja, das ging schon,
aber es war auch, also ich habe
da jetzt nicht so wahnsinnig viel
irgendwie
Nutzen rausziehen können, aber
ich hatte auch vorher neben dem Ding halt auch schon
100% Test-Coverage, insofern
war da einfach wahrscheinlich nicht mehr so viel
zu, ja auch
das habe ich ja gemacht, um es mal
gemacht zu haben.
Ich habe tatsächlich in den Projekten bei mir jetzt Enforced
MyPi Precommit Hook.
Das ist auch schon, damit gehe ich ziemlich vielen
Leuten auf die Nerven, aber
Gut, dann kannst du überall Objekt hinschreiben, oder?
Das zählt doch auch. Ja, okay, also
da sind die meisten noch nicht draufgekommen.
Oh, da habe ich jetzt ein Geheimnis
verraten, hups.
Annie, oder? Annie, Annie.
So, zack.
Also ich bin beeindruckt von der 100%
Test-Courage. Also ich bin
leider Gottes der faulste
Tester.
Diesseits der Donau.
Ich sage immer,
also ich habe diesen Spruch
gehabt, wie ich noch in einer Agentur gearbeitet habe,
dass ich sage, ja, getestet wird beim Kunden,
nicht, wenn es in Production ist, es soll reichen.
Aber ich, keine Ahnung, liegt es an der Software,
die ich schreibe oder an der Rolle, in der ich bin?
Ich bin sehr, sehr selten jemand,
der wirklich ausgiebige Testsuit schreibt.
Also das ist, glaube ich,
als ich auch Schärfe habe, das ist, glaube ich,
meine größte Schwäche.
Ja, 100% Courage ist auch schon sehr...
Ja, ich finde es beeindruckend, wirklich.
Ja, das haben wir in dem Projekt, in dem ich bin,
Ach, 100%, also 100% Branch
Coverage sogar. Und
TypeScript. Also es ist ja oft
so, dass man das so ein bisschen als
gegensätzliche Pole ansieht,
sag ich mal. Die einen machen Typen und die anderen machen
Testing. Und das ist schön, Stefan,
dass du das jetzt bestätigt hast, aber
Ich bin quasi
das Typen-Paradebeispiel.
Ich meine, das Ding ist,
JavaScript und Python
haben ja die gleiche Eigenschaft,
dass beides in der Praxis
dynamisch typisiert
Sprachen sind. Sprich, natürlich gibt es
Typen, sonst könntest du mit den ganzen Werten nichts
anfangen. Es ist aber relativ egal, was das für ein
ist. Du kannst dann
ein Number oder ein Integer einer
Variable zuweisen und im nächsten Schritt
dann String und keiner regt sich auf und keiner beschwert sich.
Das funktioniert halt einfach.
Oder du kannst verschiedene Typen mischen. Du kannst
ein String mit einer Zahl kombinieren.
Das geht nicht.
Okay, cool. Dann seid ihr schon mal einen Riesenschritt weiter
als in JavaScript.
Das ist ja das große Problem an JavaScript, oder?
Dass du solche implizite Konversionen
drin hast. Ja, also
das heißt ja immer weak getyped
versus strong getyped, aber
ich weiß nicht, ob das irgendein Sinn ergibt.
Aber diese ganzen Bezeichnungen sind ja alle nur so ein bisschen.
Also die schöneren
Bezeichnungen sind meiner Meinung nach statisch und
dynamisch, wo du einfach weißt, okay,
definierst du den Typen im Vorhinein
oder wird er definiert durch die Verwendung?
Weak und strong,
also schwach und stark,
sind sehr
schwache Bezeichnungen, meiner Meinung
nach. C zum Beispiel hat
ein statisches
Typsystem, aber ein sehr, sehr schwaches. Ob du jetzt
einen Character hast oder ein Integer oder irgendwas anderes,
es ist einfach komplett wurscht.
Du kannst alles damit machen. Und kannst auch hin und her wechseln
und kannst auch Bitfiddling mit allem möglichen
Scheiß machen. Genau, genau, genau.
Wundervolle Bühne. Und vor dem
ist das Statische eigentlich das Wichtige,
weil es eine ein bisschen andere Herangehensweise
ans Programmieren
voraussetzt.
Du machst dir einfach mehr Gedanken über
die
mögliche Wertemenge
einer Variable, bevor du
an wer zuweist. Das schließt jetzt nicht aus,
dass du sagen kannst, hey, du bekommst
einen Typen durch Typ-Inferenz, das mache
ich sehr, sehr gerne, weil ich sage, hey, diese Variable
x ist 3 und dann weißt du,
dass das ein Number oder Integer oder was auch immer ist.
Das geht natürlich auch, das machen auch moderne
Programmiersprachen sehr, sehr, sehr gerne.
Grundlegend, dass du halt
mit wenig Annotationen machen kannst.
Nichtsdestotrotz
definierst du Verträge zwischen
Bausteinen deines Codes, zwischen den Functions,
zwischen Methoden in deinen Klassen etc.,
in denen du sagst, du erwartest aber jetzt diesen Wertebereich und nichts anderes
und du lässt auch nichts anderes zu.
Und TypeScript ist meiner Meinung nach da sehr, sehr spannend,
weil TypeScript versucht, eine sehr dynamische, dynamisch typisierte Programmiersprache
und generell sehr dynamische Programmiersprache wie JavaScript
in einer gewissen Art und Weise zu formalisieren.
Also das Ziel ist ja jetzt nicht, dort eine komplett neue Programmiersprache zu definieren
oder zu entwickeln, sondern auf Basis einer bestehenden irgendwie ein Regelwerk zu finden,
damit alle beteiligten Programmierinnen und Programmierer irgendwas zu diskutieren haben
und wissen, was da eigentlich vor sich geht.
Nichts ist schlimmer, wenn du ein halbes Jahr, nachdem du dein Programm geschrieben hast,
wieder zurückgehst und dir fragst, was war denn diese Variable X nochmal?
Also was habe ich mir da eigentlich gedacht?
Und dann hast du irgend so eine fette Wurst am Code und musst herauslesen,
was du eigentlich damit machst.
Und das ist etwas, was mich immer komplett verwirrt hat.
Ich habe da nie ein funktionales Programmierparadigmen ausprobiert,
viel mit asynchronen Promises gearbeitet in Not.
Irgendwelche dynamischen Objekte gehabt, wo ich ständig neue Keys hinzugefügt habe
und wieder entfernt habe.
Und das war kurz und effektiv und schnell und schön.
Und drei Monate später habe ich nicht mehr gewusst, was ich dort mache.
Wenn ich das Programm heute lese, ich kenne mich nicht aus.
Und ich würde es auch heute nicht mehr so machen.
Einfach weil, gut österreichisch, sorry, Graut und Ruben einfach zusammenschmeißt und hofft, dass am Ende alles funktioniert.
Und das ist gut für kleine Skripte, das ist gut, wenn du irgendwie geschwind was runterheckst.
Aber wenn ihr wirklich mit einem Team versucht, reale Software zu machen, dann ist das, glaube ich, die niedrigste Schwelle, die du hast,
um zu dokumentieren, was jetzt von deiner Software und von den Nutzern deiner Software überhaupt erwartet wird.
Und ich glaube, deswegen sind Typen so wichtig. Und deswegen, glaube ich, sind Typen auch in Python sehr, sehr interessant, weil du ja da die gleichen Voraussetzungen hast. Also du musst ja wissen, was erwartet jetzt deine Funktion dort. Und je mehr Bibliotheken, die du hast, wie gesagt, ich wäre schon gesagt, ich bin jetzt in diesem Luncheon und LLM-Wahnsinn irgendwie gefangen, da hast du sehr, sehr komplexe Objekte, die du da hin und her schickst.
Woher sollst du wissen, oder woher soll ich wissen, der kein Python schreibt, sondern nur lest, was da jetzt eigentlich erwartet wird und was ich da rauskriege?
Das finde ich auch, also das tatsächlich so als Dokumentationstyp
für Python ist das, was ich auch am häufigsten
gerne mag, also in kleinen Closures,
in kleinen Methoden oder Funktionen irgendwie
die Argumente so zu annotieren,
dass beim Riesen klar wird, was denn
der Mensch da haben möchte, der
diese API bereitstellt,
dass ich das irgendwie zusammengebaut kriege oder so, oder
verstehe, was er denn da braucht oder sowas.
Das sehe ich anders.
Ja, ich weiß nicht so.
Aber das hätte ich ja heute hier.
Ja, genau.
Also ich finde, dass das Argument, was der Dominik bringt, das stimmt, wenn man nur simple Funktionen hat. Also wenn man wissen will, ob da jetzt ein Integer oder ein String rein muss. Und man hat vier Parameter und die haben alle simple Typen.
Aber für mich fällt es auseinander, wenn die Typen komplex werden, weil dann hast du irgendwelche benannten Typen, die irgendwelche interne Struktur haben, die völlig opak ist und dann hast du 17 verschiedene Varianten davon und am Ende weißt du genauso wenig, was da rein muss und was nicht. Und das hat alles so seine Grenzen.
Ja, ich habe letzte Woche mit einem Freund telefoniert, da haben wir uns auch kurz über Type Annotations unterhalten und der meinte so, ja, schön und gut und ich sehe die Vorteile und so, ich finde es einfach irgendwie hässlich, weil irgendwie, okay, die IDE, ja, okay, das ist eigentlich alles gesagt.
die Ästhetik ist immer das Argument.
Ja.
IDE kann damit was anfangen oder so, wenn man das jetzt
anguckt, der meinte so, ja, dann hat man bei den ganzen
modernen Libraries heutzutage, dann hast du da
irgendwie Funktionen und da hast
du pro Zeile
einen Parameter, weil da kommt immer
der Name des Parameters, dann
kommt halt die Typannotation,
die einem nicht viel sagt und dann kommt nochmal ein Kommentar,
der erklärt, was die Typannotation einem eigentlich
sagen will und das dann so
untereinander. Dann meinte er so, das erinnert mich total an
C-Code aus den 80ern, ich weiß nicht,
Ich mag das nicht.
Das ist nicht Python.
Ja, aber
dieses Argument höre ich auch häufig, wenn man
jetzt so bei den Alten,
zum Beispiel übernächste Woche wieder
oder als nächstes, ich weiß nicht.
Auch hier aufs Python-User.
Und das nächste, nächste Mittwoch.
Das nächste Woche, ja.
Genau, gehen. Da gibt es dann die
alteingesessenen,
die sagen auch immer so,
immer nur Aks, Quaks, Sternchen, Sternchen.
Nein, das nicht, aber
Jaja, aber das ist schon so ein Punkt,
mit dem viele Probleme haben, ja.
Ich kenne genug Python, dass ich den Witz
mit Aks-Quaks verstanden habe.
Da gehörst du schon
zu den Oberlehrern.
Ja, also gut, also
ich
bin immer sehr kritisch,
wenn es darum geht, dass man
die Ästhetik bewertet, weil
ich schreibe sehr viel in Rust. Rust ist
eine sehr unästhetische Sprache. Du hast
quasi, hey, wie viel Syntax
kann eine Programmiersprache vertragen? Und Rust sagt,
Ja, also her damit.
Aber dafür ist mir halt
zu jedem Zeitpunkt absolut
hundertprozentig klar, was passiert.
Und das ist halt auch ein Vorteil,
den man nicht leugnen kann. Gerade wenn man in Teams
arbeitet. Und da nehme ich halt die paar
Annotationen, die ich da habe, einfach hin.
irgendwas hat jetzt da geblinkt, ich bin kurz rausgekommen.
Und verstehe zumindest,
was passiert. Und ich muss ganz ehrlich sagen,
was ich rein jetzt sehe von dem, was
wie Python
Typings umsetzt,
ist das eh sehr
minimalistisch. Also da kann man sich noch
weit, weit mehr verausgaben. Also ich finde das gar nicht
einmal so hässlich.
Ja, ich finde
das Problem ist halt, dass
diese Typsysteme
oft zu weit getrieben werden.
Und das treibt dann Blüten.
Ja, also für alles und jedes und nochmal die letzte.
Genau, für alles und jedes. Und das muss dann alles ein benannter
Typ sein und das geht dann,
Also ich habe hier ein Beispiel aus der Apple-Dokumentation.
Da gibt es einen Typen, der heißt
CN Label Contact Relation Younger Cousin,
Mother, Siblings, Daughter or Father, Sisters, Daughter.
Das ist ein Typ.
Wunderschön.
Ja, ob man den jetzt braucht oder nicht.
Auf der anderen Seite hier ein Beispiel aus der .NET-Bibliothek.
Die Links sind dann alle in den Show Notes.
Da gibt es eine Methode, die heißt Run.
Die hat 30 Argumente.
31, das erste ist ein Object, das heißt Makro.
Das zweite ist ein Object, das heißt Arc 1.
Das dritte ist ein Object, das heißt Arc 2.
Und so geht es weiter bis Arc 30.
Grandios.
Da bringen mir die Typen nichts.
Da sagen mir die Typen nicht, was das macht.
Und zwar in beide Richtungen nicht.
Und es gibt halt da diese Fetischisten, die sagen,
du musst aber überall benannte Typen drin haben
und du musst das Typsystem vollständig aufbauen.
ausnutzen. Und
das geht mir genauso auf den Senkel wie die alten Herren,
die dann sagen, nein,
Typ-Annotationen ist ekelhaft
und hässlich und wie in den 80ern.
Irgendwo in der Mitte ist dieses Maß.
Du hast mich gerade
an etwas Wunderbares erinnert. Ich bin ja
in einer Java-Welt
groß geworden.
Und habe gelitten dort.
Ich auch.
Ich komme aus der
Nähe von Linz und direkt
also auf dem anderen Bergerl gegenüber, wohnt einer der Erfinder vom Spring-Framework.
Also wir kennen uns, unsere Kinder gehen gemeinsam in die Schule und solche Sachen.
Und da gibt es eine Klasse, das ist die Has this type pattern tried to sneak in some generic or parameterized type pattern matching stuff anywhere visitor.
Und das ist fantastisch.
Also bei uns in der Firma haben die Java-Developer diese Weißkin-Monitore,
aber nicht, dass sie irgendwie dort mehrere Fenster nebeneinander hinkriegen,
sondern ich sage immer, das ist, damit sie die Klassennamen ohne Zeilenhundbruch durchstehen können.
Und das ist natürlich, das ist Mumpitz, das ist ganz klar.
Ich denke, man muss die ganzen Sachen immer ein bisschen pragmatischer sehen
und halt auch einen richtigen Nutzen oder wissen, welchen Nutzen man daraus zieht.
Das gilt für alles in der Softwareentwicklung meiner Meinung nach.
Das ist der Anzug.
Genau. Was ich am liebsten habe zum Beispiel,
also ich schreibe immer noch sehr, sehr viel
Node und wenn ich starte damit,
dann habe ich
einmal keine Typen zu Beginn, weil ich ja selbst
nicht weiß, wie mein Software am Ende ausschaut.
Aber wenn ich dann fertig bin, wenn ich dann ein paar Funktionen extrahiert
habe, dann lasse ich mir ein paar Typen
einführen, einfach nur, dass ich festgelegt habe,
was ich hier an dieser Stelle
erwarte, damit, wenn ich zurückgehe
oder wer von meinen Kolleginnen oder Kollegen
zurückgeht, auch weiß,
was dort zu erwarten war.
Und um das geht es eigentlich. Und gerade in
Types gibt. Also gerade auch in meinem Buch gibt es
ein paar Beispiele drinnen.
Da kann man sich schon richtig, richtig vorausgucken.
Da gibt es irrsinnig mächtige Werkzeuge
wie String Template Literal Types oder
Tappel Types, Variadic Tappel Types.
Das sind Dinge, wo ich mir denke,
Wahnsinn, dass das überhaupt geht.
Also beeindruckend technisch, dass das geht.
Aber die Use Cases
dafür sind halt stark limitiert und man muss wirklich überlegen,
ob das dafür steht. Und ich habe dort
drei Lektionen, wo wir
ein funktionales
Programmiertool wie
wie Currying, versuchen, auf drei sehr, sehr komplexe Orten umzusetzen und zu sagen,
aber überleg dir, ob diese Typen jetzt das gerechtfertigen, was du da als Funktion schreibst,
oder ob du nicht lieber eine Funktion nimmst, die viel, viel weniger kann,
aber genauso einfach zu verwenden ist und die einfach zu typisieren ist,
mit der du besser die Typinformationen rauskriegst.
Und das stelle ich dann auch so zur Diskussion.
Also man muss halt immer abwägen können, wie rechtfertigst du den Einsatz dieses Werkzeugs
und wie weit treibst du das?
Ja, ich glaube, das ist tatsächlich gar nicht so einfach rauszufinden.
Ja, und
ich glaube aber, dass da noch ein anderes Problem
dahinter ist und ich bin sehr froh,
Stefan, dass du da gesagt hast, dass du
gegen Tests bist
oder gegen große Testcoverage
und du hast jetzt gerade eben so ein bisschen deinen Ansatz
beschrieben, wie du Programme schreibst
und du hast was gesagt,
was meiner Meinung nach ganz wichtig ist.
Du hast gesagt, du fängst an, ein Programm zu schreiben und weißt
noch nicht, wie es am Ende ausschauen wird.
Und das
geht mir genauso. Und das ist einer
der Gründe, warum ich
Python
mag, weil mir das die Freiheit
gibt, da so explorativ rumzugehen,
ohne mir groß Gedanken machen
zu müssen, wie es denn jetzt sauber zusammenpasst.
Und ich glaube, dass das ein Programmierstil
ist. Ich nenne das
exploratives Programmieren. Ich muss so ein bisschen
diesen Space erkunden, muss so ein bisschen sehen,
was kann ich, was schaffe ich, was mache
ich. Und das ist halt
mein Stil. Ich gehe da rein und sage, jetzt machen wir
erstmal irgendwas. Es gibt aber auch Leute,
die da vielleicht mathematischer
rangehen und die sagen, okay, ich habe hier
einen Plan und eigentlich auf dem Papier habe ich es ja
schon hingeschrieben,
dann kann ich auch die Tests zuerst schreiben, weil ich weiß
ja schon, was das machen soll. Ich weiß ja schon, wie es am Ende ausschaut.
Oder ich kann gleich die richtigen Typen
reinschreiben. Ja, da muss man sich ja das Akronym
ändern und einfach Type-Driven-Development
von einem neuen
Stand starten.
Und da
ja, das
sind, glaube ich, einfach zwei verschiedene
Arten zu programmieren, die eben
verschiedene Dinge eher bevorzugen.
Es
ist tatsächlich, glaube ich, auch ein bisschen von der Sprache
abhängig, weil, also ich glaube,
Python und JavaScript unterstützen ja diese Art
des explorativen Programmierens sehr, sehr stark.
Einfach eben in dem sie die Typen auch
entfernen. Also du kannst sie wirklich einfach mal
herumprobieren und schauen, was rauskommt.
Und schauen, wie weit
du mit deinen Ideen kommst.
Was ich spannend finde,
also ich bin jetzt seit einigen Jahren auch sehr,
sehr stark im Lasten drin, ich habe das jetzt schon erwähnt, und sorry,
Das ist der klassische Rust-Nutzer.
Nicht, dass ich ständig sage, dass er Rust verwendet,
aber es ist halt wirklich so.
Die Sprache macht einiges sehr, sehr richtig.
Du hast in Rust eine sehr stark typisierte Programmiersprache
mit einem fantastischen Typsystem.
Das ist grandios, dass das so funktioniert, wie es funktioniert.
Das heißt, du kannst dir gar nicht leisten,
dass du einfach nur mal schaust,
wo kommst du mit deinen Wertebereichen überhaupt am Ende hin.
Aber trotzdem schafft es Rust, dass du explorativ arbeiten kannst,
weil einfach die Mittel, die zur Verfügung gestellt werden, so zugänglich sein können,
weil die Typen, die von Haus aus schon drinnen sind, so entgegenkommen sind.
Das heißt, du kommst mit ein paar Basistypen aus der Standardbibliothek
und den üblichen Wertebereichen schon sehr, sehr weit,
bevor du dir selbst deine eigenen Strukturen und Interfaces, nenne ich es jetzt einmal,
heißen anders, überlegen musst.
Und das ist sehr, sehr spannend.
Es ist aber trotzdem ein anderer Wert des Programmierens.
Also das Endresultat schaut auch dann anders aus.
Also ich mag das aber auch gerne, so Models oder so Dataclasses irgendwie zu bauen
und dann zu gucken, hey, was sind das denn überhaupt für Objekte
und dir halt dann direkt zur Annotation zu verwenden.
Das ist so strukturell sehr klar.
Nein, es schließt sich auch nicht aus.
Also ich denke mir, die Gefahr liegt wahrscheinlich,
dass man sich auf eines komplett verschreibt.
Auch das, was der Johannes wieder gesagt hat, ganz richtig ist,
es ist am Ende des Tages ein Werkzeug und es muss irgendeinen Job erfüllen.
Und wenn das gut funktioniert, dass du dir vorher Gedanken darüber machst,
welche Daten du benötigst, dann ist das absolut legitim meiner Meinung nach.
Also ich finde die gerade so angenehm.
Wichtig ist, dass die Sprache mit der du arbeitest, das unterstützt.
Ja, ich glaube auch eben.
Aber ich meine, das hat natürlich einen Preis,
weil es halt zusätzliche Komplexität unter Umständen halt auch einführt
und es dann halt vielleicht auch unzugänglicher macht.
Also worauf ich eigentlich hinaus will ist,
naja, je nach Use Case kann es halt unterschiedlich nützlich sein.
Also wenn man halt zum Beispiel eben in einem Team
an einer großen Software schreibt,
dann kann es halt sein, dass es sehr viel bringt,
auch irgendwie möglichst viele Hürden zu errichten,
bevor irgendwie Code...
Du willst quasi gar nicht, dass die Entwickler irgendwas machen.
Ja, das ist leider halt eine Strategie, das ist schwer zu unterscheiden von irgendwie, man versucht Fehler zu vermeiden, bevor sie dann produktiv gehen, zu bloß nicht deployen, was dann halt auch viele Leute machen, was halt irgendwie auch blöde Konsequenzen hat unter Umständen dann, weil also viele Sachen, also man hat dann zum Beispiel nicht nur ein Staging-System, sondern noch so drei andere oder vier andere und führt immer mehr hinzu, sodass man bloß nicht nach Produktionen deployen muss.
Ich habe zwei Abteilungen bei uns kennengelernt, die haben einen Employment-Release-Zyklus so alle sechs Monate.
Ja, genau. In den sechs Monaten passiert halt auch nichts, aber es ist halt vielleicht auch irgendwie ein Konflikt mit anderen Zielen.
Hast du etwa diesen Artikel über Move Fast and Break Things gelesen, der kürzlich rausgekommen ist?
Ja, genau.
Ja, richtig.
Genau, also an der Stelle macht es ja
vielleicht, wenn man in so einer Situation ist,
sehr viel Sinn, da
von den Leuten zu verlangen, dass sie sich erst Gedanken
machen und dass halt man versucht, möglichst viele
Fehler zu fangen, bevor
sie halt in der Produktion aufschlagen,
weil da ist es halt viel teurer, sie halt zu
entfernen. Aber
es kann halt total anders sein, wenn jetzt jemand
zum Beispiel, und das ist halt eine der Stärken
bei Python, bei JavaScript
auch ein bisschen anders,
dass
es halt vor allen Dingen auch von Leuten benutzt wird, die
sich selber gar nicht als professionelle
Programmierer sehen würden, sondern die eher sagen würden,
naja, ich bin eigentlich eher so
Data Scientist oder ein Analyst
oder sowas oder halt
irgendwie jemand, der irgendwie, keine Ahnung,
Roboter irgendwie dazu bringt, irgendwie
lustige Dinge zu machen oder sowas.
Oder Teilchenbeschleuniger.
Oder Teilchenbeschleuniger, also solche Sachen, genau.
Und ich will gar nicht jetzt irgendwie
Typtheorie
verstehen oder irgendwie
keine Ahnung, auch Unitests
und da sind wir auch bei einem Ding, wo die
Sachen so ein bisschen ähnlich sind. Also ich dachte auch
lange Zeit irgendwie
Unitests sind was ganz anderes
und Typisierung
ist ein
anderes Ende von einem Spektrum und ich bin eher so
Teamtest, aber inzwischen denke ich so, naja,
das ist schon relativ ähnlich auch. Ich meine auch Unitesting
ist halt so eine Sache, die man sich erst
irgendwie erschließen muss und für manche Leute
macht das einfach, wenn man halt irgendwie
so in einem Jupyter-Notebook Sachen macht.
Ja,
manchmal macht es schon Sinn, das zu testen, aber für viele
Leute ist es auch nicht, lohnt es sich, weiß ich nicht,
ob es sich wirklich lohnt, da so tief einzusteigen.
Und, aber, ich meine,
klar, wenn man jetzt große Software in einem Team
entwickelt, dann, klar, hat man Tests und
eine CI-Pipeline und weiß ich nicht,
diesen ganzen Kram halt, ne?
Ja, das Stichwort da ist
doch Programming by Contract, oder? Und das
ist halt eine Möglichkeit, so einen Contract
zu schreiben. Aber, also
ich bin da in so einem Zwiespalt, ja, einerseits
bin ich total genervt von solchen Typsystemen, die dann
sehr präzise sind und die dann
ich habe auch, ich bin auch mit Java aufgewachsen
Stefan, also ich zähle deinen Schmerz
und dann
wirkt man sich ab und macht
ein Pair aus Int und
String und dann weißt du aber nicht, wie du an den
zweiten dran kommst und ach, das ist
alles ganz schön. Aber auf
der anderen Seite gibt es
nicht die Möglichkeit zu sagen, ganz
triviale Sachen zu sagen. Zum Beispiel hier
muss eine Zahl rauskommen, die immer größer ist als 0
oder immer kleiner als 0. Größer als 0 geht
ja tatsächlich noch, aber kleiner als 0
kannst du nicht sagen. Du kannst nicht sagen, hier
muss was rauskommen, was zwischen 0 und 1 liegt.
Und das ist irgendwie so
eine weirde Sache.
Ich bin da so im Zwiespalt. Ich hätte gerne
keine Typsysteme, aber wenn ich Typsysteme hätte,
hätte ich gerne so welche, die so exakt sind,
dass ich sowas sagen kann.
Und dass mir dann auch der Compiler sagen kann,
Moment, hier rufst du eine Funktion aus mit einer Zahl,
die zwischen 0 und 1 sein kann,
aber die muss zwischen 0 und
minus 1 sein.
Nee, das ist nicht Validierung, sondern das ist
Nee, das sind sogenannte Value-Types.
Das kannst du auch in ein Typ-System reingießen,
wenn du das möchtest.
Das ist quasi keine Sprache.
Ich glaube, ich habe eine mal gesehen.
Eifel.
Eifel, ja genau.
Also grundsätzlich im funktionalen Programmierbereich
hast du das relativ häufig.
Ja, es gibt da so ein paar Erweiterungen.
Aber ich würde mal annehmen,
nicht in den populären oder weitverbreiteten Programmierungen.
Nee, nicht in denen, die man benutzt irgendwo.
Oder die man schon mal gehört hat.
Aus einem ganz einfachen Grund, weil du halt unter den Wertebereichen von einer Zahl
tatsächlich irgendwelche Bytes liegen, die von einer CPU ausgelesen werden.
Ja, klar.
Wenn dir das Typsystem das erlaubt, dass du dort irgendwas zwischen Minus 1 und Plus 1
zum Beispiel definierst, oder mein Gott, eine ganze Zahl zwischen 25, was auch immer,
dann schiebst du die Validierungen nur an eine andere Stelle.
Ja gut, aber das machst du mit dem Typsystem generell, oder?
Also ich meine, sobald der PipeScript-Compiler
durch ist, ist er weg.
Das ist sehr richtig, genau.
Ich glaube, in Python genauso, wenn ich mich nicht täusche.
Ja, generell.
In Python sind die Annotationen erstmal gar nichts.
Genau, das ist in Python auch so leicht anders.
Das wissen auch viele Leute.
Das ist halt, wenn man zu den praktischen Dingen kommt,
die halt damit problematisch sind, also ich bin ja häufiger
auch irgendwie in unterschiedlichen
Firmenkontexten da so unterwegs
und das,
was ich in letzter Zeit halt häufig sehe,
ist halt sowas wie Leute
annotieren halt irgendwie ganz viel,
aber
sie haben keinen statischen
Type-Checker, der da drüber laufen würde. Und in Python
ist halt auch keiner eingebaut, was vielleicht auch nicht so gut
ist. Und man müsste da
und dann mache ich dann sowas wie
ich lasse mal MyPy drüber laufen und die Leute
verwenden alle TypeDict und sowas und denken
halt, ja, das überprüft jetzt, ob meine ganzen
Werte da so
meine ganzen Werte in dem Dict halt so
den richtigen Typ haben
und so. Und Python selber
macht da gar nichts. Das überprüft überhaupt nichts.
es ignoriert die Annotationen einfach.
Ich lasse dann MyPy drüberlaufen und kriege dann so
400 Fehler. Und dann denke ich mir so, okay,
ja, also du hast da schön deine Annahmen
darüber, wie die ganzen Typen aussehen, dokumentiert, aber die
sind halt leider alle falsch. Das stimmt überhaupt
gar nicht. Und ja, da ist
dann, denkt man sich, warum hat man sich denn überhaupt die Mühe gemacht?
Also es ist halt irgendwie...
Ja, wie ist denn der Zustand
der Entwicklungsumgebungen in Python?
Kommt drauf an.
Also auch die hängen halt daran, ob du
MyPy zum Beispiel
als Static Type Shaper Extension
richtig konfiguriert hast.
Und ob dann auch MyPi
die Stubs halt lesen kann,
die halt notwendig sind oder halt auch nicht.
Die müssen halt alle dann...
Aber viele IDEs behandeln das doch auch selber schon.
Ja, ja, genau.
Da gibt es ja auch dann, ich weiß gar nicht jetzt,
was bei VS Code
dann normalerweise verwendet wird.
MyPi ist eine Extension.
Ja, aber ich meine, wenn jetzt zum Beispiel einfach nur das...
Also IntelliJ macht das selber.
Ja, die haben einen proprietären, dann gibt es irgendwie MyPi, klar.
Und es gibt halt noch PyRide
und der Language-Server
für Python, kann es sein,
dass er selber von Microsoft
in TypeScript geschrieben ist?
Ja, es ist
nämlich spannend, weil ich
denke, TypeScript
hat da einige richtige Entscheidungen getroffen
auf dem Gebiet.
Die ihr jetzt alle angesprochen habt,
was kompliziert und was komplex
in Python ist,
nämlich, dass die Sprache
dir zwar ein Typsystem
anbietet, cool,
aber eigentlich nichts damit machst, sondern du brauchst
eh nur einen extra Typ-Checker und
anscheinend wie bei den Package-Managern gibt es
dort auch mehrere, wo du dir dann noch aussuchen
kannst, welcher gefällt dir jetzt und
welcher passt zu dir und so weiter
und ich finde das grandios, dass es Auswahl gibt,
keine Frage, aber es erhöht natürlich auch die
Komplexität. Und TypeScript
hat, TypeScript
selbst ist ja eigentlich
mehrere Dinge. Es ist zum einen einmal ein Typ-System,
cool, also wie werden Typen geschrieben,
definiert, wie sind sie im Zusammenhang.
Es ist auch ein Typ-Checker dabei,
also der TypeScript-Compiler
TSC macht in erster Linie mal
Type-Checking, aber
kompiliert dann auch tatsächlich JavaScript-Code,
den du ausführen kannst. Also es gibt so jetzt
Proposals, dass du auch Typ-Annotationen
irgendwann einmal in JavaScript schreiben können
solltest, ähnlich wie in Python, wir sind dort einfach
von der Runtime ignoriert,
aber da sind wir noch nicht, also da kommen wir erst hin.
Das heißt, du brauchst auch den Compiler.
Das heißt, wir haben Typ-System, Typ-Checker, Compiler und noch auch
ganz, ganz wichtig, eine Integration
in Editoren und Entwicklungsumgebungen.
Und das war eigentlich, also dieser gesamte Tooling-Aspekt rundherum,
nicht nur das Typ-System anzubieten, sondern auch Werkzeuge anzubieten,
dass du nachher zu validem JavaScript-Code kommst und du deine Fehler siehst
und die Fehler auch sofort in deinem Editor und deiner IDE dargestellt werden,
sind meiner Meinung nach genau die Punkte, die nachher auch den,
unter Anführungszeichen, Ziegelszug von TypeScript auch zu verantworten gehabt haben.
Weil ohne dem hast du halt nur die Hälfte der Dinge. Du brauchst halt irgendwie alles, damit du sauber entwickeln kannst. Und wenn ich mir denke, dass ich Visual Studio Code aufmache, wo TypeScript schon drinnen ist und ich mache irgendein JavaScript-File auf und es läuft im Hintergrund schon der TypeScript-Compiler und checkt meinen JavaScript-Code und versucht zu inferieren und zu verstehen, was ich schon geschrieben habe ohne einzige Typ-Annotation und ich kriege aus dem raus schon Autocomplete und die ersten Warnings,
dass vielleicht irgendwas nicht ganz rund läuft und schief geht.
Das ist so viel wert,
ohne dass ich eine Zeile TypeScript schreibe,
wo ich mir denke,
ja, das ist eigentlich eine richtig gute Idee gewesen.
Ja, absolut.
Da kann Python sich, glaube ich,
auch noch eine Scheibe abschneiden davon,
weil da gibt es noch so ein paar Löcher.
Also wenn ich jetzt sage,
ich installiere PyCharm oder wie auch immer,
welche Idee,
und die kommt schon mit einem Typinterpreter
oder einem TypeChecker mit,
Das wäre natürlich göttlich nett, dass du einfach
sagst, hey, du brauchst nicht mehr die Typernotation
schreiben, aber die IDE
hat irgendeinen Type-Checker schon
per T-Fold drinnen. Wahrscheinlich schreiben sie ihn selbst,
weil JetBrains schreibt das irgendwie selbst.
Haben sie.
Der von JetBrains ist
der ist super gut.
Das ist einer der Gründe, warum
man PyCharm verwendet, weil die halt
die beste Typ-Inferenz haben.
Man merkt schon,
dass das so der Java ist.
Aber das können sie, also da sind sie richtig, richtig gut.
Schon wieder Rust, für Rust haben sie auch einen eigenen geschrieben.
Also die ganze Welt verwendet Rust Analyzer.
Außer du nimmst Rust Rover von JetBrains, dann ist da ein eigener drinnen und sie haben auch Recht damit.
Also das ist halt alles richtig gut integriert in die Werkzeuge, die sie zur Verfügung stellen.
Ja, auch ein zusätzlicher Effekt, den das hat, dass halt quasi bei Python halt der statische Type Checker halt nicht so wirklich zur Sprache dazugehört.
Ist halt auch, dass bei TypeScript ist es halt so, dass was sich sozusagen in der TypeScript-Sprache tut, auch immer sofort verfügbar ist. Und das ist bei Python nicht so, weil die statischen TypeChecker vor allen Dingen von den großen Wendeln gebaut werden, halt nicht MyPy, Dropbox, ich weiß nicht, ob die immer noch da so hauptsächlich dran sind, aber dann gibt es noch einen von Google, es gibt noch PyWrite.
Die hängen sowieso immer so ein bisschen
in den Versionen hinterher, weil
sie ihre Code-Basis sowieso nicht
an der aktuellsten Version halten können, weil sie das
gar nicht schaffen, weil das einfach zu viel Arbeit ist.
Das heißt, normalerweise
bei MyPi hängst du halt immer so eine
Version irgendwie von dem, was die Sprache eigentlich
kann, zurück, was halt auch total
doof ist einfach.
Du musst ja auch noch darauf einigen, welches
Subset des Typsystems du jetzt verwendest.
Ja.
Genau.
Da kann ja gar nichts schief gehen.
Ja, aber TypeScript-Versionen gibt es ja jetzt auch und ich habe auch schon Freude damit gehabt.
Ja, also das TypeScript-Version-Management ist sehr stark in der Kritik, sehr keine Frage.
Also das, jedes Release ist ein Breaking Change.
Ja, und das ist aber einfach ein schwieriges Problem.
Also ich glaube tatsächlich, dass TypeScript einfach dadurch, dass es eine jüngere Sprache ist,
gewisse Fehler vermeiden konnte, die man halt vor 20 oder 25 oder 30 Jahren machen musste mit den ganzen alten Sprachen.
aber manche Sachen sind halt
immer noch nicht gelöst und Version Hell
gehört halt dazu
Wobei auch sagen wir, das TypeScript ist schon
historisch gewachsen, also du merkst
schon die dunklen Flecken
der Vergangenheit und versuchst sie zu ignorieren
das ist halt so, das passiert halt
so wie Sachen verwendet werden
hast du nachher die Probleme
Ja und das muss sich ja auch
an JavaScript orientieren, also es muss ja
JavaScript kompatibel sein und da kriegst du halt
viel, sag ich mal
Ja, auch da kriegst du halt Historie, wenn ich es sehr freundlich ausdrücken will.
Ein kleines bisschen Programmiersprachen-Historie mitgeliefert.
Ja, ja, ja, ja, ja, aber ich wollte gerade nochmal auf Java ein, wo wir das gerade hatten.
Schon alles gesagt.
Das ist leider schon ein bisschen drüber, aber davon wieder weg.
Aber da hatte ich nämlich auch noch so eine schöne, da habe ich letztens was sehr, sehr Schönes gelesen, dass halt einer der Autoren, auch von der Sprachspezifikation von Java, hat halt irgendwann mal so geschrieben zu den Generics, also dass sie die Generics eingeführt haben.
Also ja, das war irgendwie ein Fehler. Und dann hat er irgendwie noch, in dem Buch selber findet man auch irgendwo so eine sehr schöne Fußnote, wo halt quasi die Annotation von Inam, Inam ist auch ein Partner ein Problem, aber in Java halt auch.
Und Inam ist halt irgendwie definiert als, ich suche gerade, ob ich das hier finde, ah ja genau, ist eine generische Klasse definiert als Inam, Spitze, Klammer, T, Extens, Inam, Spitze, Klammer, T, Klammer, Zu, Klammer, Zu.
Also diese rekursive Definition ist halt so ein bisschen schwierig zu verstehen.
Wir haben inzwischen aufgegeben, es zu versuchen, Leuten zu erklären.
Es gibt irgendwie Spezialisten,
die uns versichert haben,
über Typtheorie, die uns versichert haben,
dass das schon alles okay ist und kein Problem
und wir sollen uns einfach nicht so viel
Gedanken drüber machen, was wir
sehr gerne annehmen.
Das Spannende ist ja bei den Java-Generics,
dass die
als einziges Element
im Typsystem von Java
keine Auswirkungen
auf die Gestaltung der Laufzeit
Objekte haben. Also das sind auch
so, nach dem
Compile-Schritt wird das einfach entfernt und
nie wieder angesehen.
Und das ist halt das Beeindruckende daran.
Also das war halt auch so, oh shit, das brauchen
wir jetzt, wir müssen das jetzt machen, im Release 1.5
glaube ich war das, und das war
die einfachste und unproblematischste
Art, wie wir dazu kommen.
Und
alle Implikationen, die das hat, die werden bis heute
mitgezogen. Du kannst quasi generische
Klassen nie wirklich optimieren.
Geht einfach nicht. Was halt spannend
ist, weil die hast du halt überall, du hast überall
Generics drin.
Deswegen werden auch
oft nur in der
Standardbibliothek das generische
Object verwendet, anstatt dass du einen generischen
Typ-Parameter hast.
Was ich mit Inam sein kann, weiß ich sowieso nicht.
Also ich habe das gesehen bei unseren Kollegen
und das ist kein Inam.
Das ist kein Inam.
Ich finde das eigentlich jetzt ein guter
Zeitpunkt, um nochmal so ein bisschen zu erklären,
worum es überhaupt geht und was da alles so drin ist.
Wir sind jetzt auch schon auf so einem relativ hohen
Frug-Level unterwegs, aber wir haben auch
viele
Menschen, die uns zuhören, die vielleicht noch gar nicht
wissen, was denn ein Generic überhaupt ist
und vielleicht sollten wir das einmal kurz
ja
wissen wollen, aber jetzt
kriegen sie es halt mal gesagt.
Im GFG-Nich gibt
es auch Generics in Python.
Ja, genau.
Wovon
geht an?
Also das ist ja,
diese Generics in den Typ-Annotationen,
das ist ja wirklich nur sehr instruktiv,
nur sehr so vage gesagt.
Da ist die Erasure ja noch viel größer.
Johannes, was ist denn bitte ein Generic?
Ein Generic ist eine Spezialisierung eines Typen
anhand eines anderen Typen.
Und das klassische Beispiel ist da die Java-Liste.
In Python hast du ja eine Liste,
die, sag ich mal, dynamisch typisiert ist.
Das heißt, wenn du eine Liste hast,
kannst du da eine Zahl reintun und einen String und
eine komplexe
Zahl und ein Objekt und noch eine Liste.
Das ist immer sehr unterhaltsam, wenn man das
in den, wenn ich das in den
Seminaren mache, wenn ich den Leuten Programmieren
beibringe, die vielleicht schon mal eine Programmiersprache
gesehen haben oder die schon was
davon gehört haben und dann zeige ich hier so, jetzt kannst du da,
du kannst noch eine Liste auch reintun oder ein Dictionary
kannst du auch einfach in deine Liste reintun.
Und in Java geht
das nicht. In Java hat jede Liste
einen Typen. Das heißt, du kannst,
wenn du einfach nur List sagst, dann
meinst du Liste von Object. Das heißt, alles, was
du da reinschauen kannst, ist Object. Aber
du kannst diese Liste
spezieller gestalten, indem
du eben diesen Generic-Mechanismus
verwendest und sagst, du hast jetzt nicht eine Liste
von Object, sondern du hast eine Liste von
String. Das heißt, der Compiler
weiß an bestimmten Stellen, dass
dieser Typ, den du da hingeschrieben hast,
der vorher vielleicht nur ein Platzhalter war,
in TypeScript verwendet man
dann oft T oder K oder V, das ist
auch in Stefans Buch,
kommt es mehrmals vor.
Und dass du dann eben zu einem bestimmten Zeitpunkt diesen generischen Typen ersetzt durch einen konkreten Typen und sagst, okay, ich habe jetzt hier nicht eine Liste von Objects, sondern ich habe ganz klar eine Liste von String. Und dann kann der Compiler oder eben das Typsystem überprüfen, dass du da tatsächlich lauter Strings drin hast.
Der Code, den du da ausführst, ist genau der gleiche, aber du hast jetzt eben einen spezifischen Typen für eine Liste von Strings gemacht. Und das hat gewisse Vorteile, zum Beispiel, wenn du da ein Objekt rausholst, kriegst du dann halt eben nicht nur ein generisches Object zurück, sondern du kriegst dann tatsächlich einen String zurück. Das ist der große Vorteil, den Java davon hat, dass du diese Accessor-Methoden hast, die dir die spezifischen Sachen rausgeben. War das korrekt erklärt, Stefan?
Es ist cool.
Als Experte.
Gott, Experte.
Ich bin nie ein Experte, ich bin einfach nur
aufgehoben und schreibe den ganzen Mist auf.
Ja gut, aber das macht dich zum Experte.
Aber nein, das beschreibt es ziemlich gut.
Du kannst mit
Typparametern dir die Entscheidung
auf den tatsächlichen
Typen für später aufheben.
Das ist das, was dort passiert.
Und ebenso sagst du, dann wird das eine Arraylist
von String oder eine Arraylist von
Integer und du
substituierst diesen Typparameter mit
einem konkreten Typen und kriegst
nachher auch solche
konkreten Typen wieder retour.
In manchem Programmiersprachen kannst du dann auch noch
so Dinge wie Constraints
oder Bounds angeben, wo du eben
sagst, hey, du hast dort jetzt einen beliebigen
Typparameter, ja, aber er muss
einem gewissen Subtypen
entsprechen. Das heißt, er muss eine gewisse
Funktionalität zur Verfügung haben oder
muss, also
TypeScript ist ja
strukturell typisiert,
was bedeutet, dass du einfach
sagst, hey, solange die Methoden dort sind und
solange die Properties dort sind,
passt schon, muss nicht den gleichen Namen
haben, muss nicht in irgendeiner Hierarchie sein, sondern
Hauptsache, schaut irgendwie so aus
wie das eine, was ich da erwarten
würde und dann haut das schon hin.
Und dann kriegst du halt zum einen
die Sicherheit, dass du nicht irgendwelche
Typen reingibst, die nicht damit funktionieren
würden.
Und zum anderen
kriegst du halt noch mehr Informationen über deinen
Typ noch heraus, wenn du ihn dann vermeidest.
Wie macht man das denn? Ein Python-Protokoll?
Doch, in Python ist das seit 3.8. im Grunde auch so oder kann man das so machen.
Man kann auch nominal typisiert das Ganze machen, aber da geht das jetzt auch.
Genau, mit Typing-Protokolls geht das auch.
Ja, genau.
Habt ihr das schon mal irgendwo gesehen?
Ja, ich verwende das.
Also ich finde das eine großartige Idee, aber ich habe es noch nie irgendwo verwendet gesehen.
Ja, ja, doch. Also ich kenne es auch vor allen Dingen aus dem Fluent Python Buch von Luciano Ramallo.
Und der hat sich auch mit diesem Typisierungsthema stark beschäftigt und hat dann diverse Fehler in der TypeShed Repository, wo halt die ganzen, wo auch die Standardbibliothek von Python annotiert ist, hat er da gefunden.
Und viele davon konnte er fixen mit diesem Structural Typing-Ansatz.
Also Fehler im Sinne von halt die Annotationen waren halt irgendwie,
da waren halt False Positives oder halt False Negatives möglich.
Auch sehr interessant, wenn man sich halt anguckt,
welche Fehler sind häufiger.
False Positives sind viel, viel häufiger bei Typ-Annotationen
als False Negatives.
Also in der Python-Standard-Bibliothek waren es irgendwie achtmal so häufig.
Was halt auch ein Hinweis darauf ist, dass es halt für Leute wichtiger ist, dass halt die, also falls positiv heißt, eine Annotation hat gesagt, nee, du kommst hier nicht rein, du bist nicht der richtige Typ, dein Typ ist hier nicht gefragt.
sozusagen, obwohl es eigentlich doch
okay gewesen wäre und
also offenbar
ist es halt irgendwie so
mehr opportun, irgendwie auf der Seite von
strikter zu sein, zu irren
als umgekehrt.
Was ja auch so ein bisschen
vielleicht damit zusammenhängt, welche Leute
das, für welche Leute das halt vor allen Dingen gut ist,
nämlich die, die halt versuchen wollen, möglichst viel
da draußen zu halten und wenn sie ein bisschen zu viel draußen
halten, ist es besser, als was durchzulassen,
was halt dann irgendwie knallt zur Laufzeit.
Das wäre dann Full Snagged.
Ja, genau.
Und ja, der hat das lange erklärt in dem Buch
und da habe ich das halt quasi her.
Und ja, ich finde das eigentlich sehr nett,
weil damit kann man im Grunde genau das Gleiche machen
wie ein Typescript mit diesen Intersection- und Union-Types.
Was ja auch irgendwie so, das ist halt so sehr cool eigentlich,
dass das geht.
Und das geht halt, wenn man jetzt so mit Abstract Base Classes das Ganze macht und nominal, geht das halt nicht so richtig.
Das Problem ist, wenn du nominal arbeitest, du brauchst da auf dem Schlag eine Hierarchie auf.
Auch wenn die implizit ist durch die Basistypen, die du definierst.
Und das kannst du sehr schön und elegant umschiffen, indem du sagst, hey, alles, was ich erwarte, ist einfach nur, dass das Ding so ausschaut oder diese Werte und Eigenschaften hat, die ich an dieser Stelle erwarte.
Methodennamen, Rückgabe-Werte, Property-Typen etc.
Und ich sage mal, eine Programmiersprache wie JavaScript
wäre gar nicht anders zu typisieren gewesen
oder es wäre gar nicht möglich gewesen, die anders zu typisieren als mit einem strukturellen
Typsystem, weil sonst praktisch kein Code mehr funktioniert hätte, den du irgendwie
geschrieben hast. Und das war eben auch so ein Designprinzip von TypeScript, dass sie sagen,
hey, wir wollen bestehenden JavaScript-Code unterstützen und mögliche Fehler
herausfinden und nicht einfach nur
aufgrund von einem
APTR-geschaffenen
Hierarchie-Konstrukt sagen, das passt
oder passt nicht.
Und ich glaube, es kann
man gut vorstellen, dass das Python auch stark
hilft. Ja, definitiv.
Ja, das ist jetzt also seitdem
also, ich meine, ist das auch in, glaube ich,
in Go ist das
ja auch so, mit den Interfaces in Go verhalten sich
im Grunde auch so.
Genau, du implementierst implizit
Interfaces, wenn die Methodensignatur
gleich ist, genau. Dann bist du
kompatibel zum Interface.
Ja, und
also, ne, ich verwende das tatsächlich.
Ich glaube auch, das ist halt, das ist eigentlich sozusagen das,
wo es dann anfängt, Spaß zu machen.
Weil, ehrlich gesagt, mit den Hierarchien,
Klassenhierarchien und so, das ist nicht so
meine Vorstellung von Spaß.
Ja, also, ich glaube, das ist schon ein paar Mal
gemeckert, ja.
Ja, du hast ganz
recht, Johannes. Das ist das, was, oder ich glaube,
es war Johannes, oder was? Ja, genau, das ist das,
was natürlich passiert. Du hast Klassen und dann hast
der Hierarchien davon und dann benutzt du die und fertig.
Das ist dem Konstrukt zu schulden.
Und unter Kante ist
Konstrukt auch nichts dafür. Das ist halt einfach so.
Nee, und das liegt halt auch nahe.
Du hast schon diese Hierarchie
und dann benutzt du sie halt auch weiter. Du hast schon die Struktur.
Also nehmen wir sie.
Aber das
ist dann eben das Problem, worauf du dann triffst.
Du kommst an eine Stelle,
wo du weißt, hier muss ich jetzt eigentlich
nur addieren, aber der Typ, den du verlangen musst,
ist halt irgendein ganz wilder
oder ein ganz abgefahrener oder
irgendeiner, der wo ganz anders in der Hierarchie drin ist.
Und das, genau.
Was mir sehr gut gefällt
am Python-Typ-System, was ich gesehen
habe, nur durchs drüberfliegen, ist
dieses New-Type-Konstrukt, wo du
sagen kannst, hey, es gibt schon einen bestehenden Typen
und der ist vielleicht sehr, sehr
freigebig, der ist vielleicht ein Integer-Dustring oder was auch immer,
aber da kannst du ihm noch dieses eine Label
verschaffen, damit du jetzt nicht irgendwelche unterschiedlichen
Integer-Werte durcheinander kriegst oder
irgendwelche Objektwerte, die ähnlich sind,
durcheinander kriegst. Weil
strukturelle Typ-Systeme funktionieren halt immer bis zu
im Grad, was du sagen musst, hey, aber
dieses eine Ding will ich da jetzt nicht herinnen haben,
weil ich erwarte doch etwas anderes und kann
das durch das Typsystem nicht so ausdrücken.
Mach das Newtype, dann wird es explizit
und dann kannst du genau sagen, hey, an dieser Stelle
erwartest du etwas,
was so ausschaut, aber es muss doch etwas anderes
sein. Und das finde ich eigentlich ganz
brauchbar.
Genau, das benutze ich
genau für diesen Use Case, dass man halt
oft
quasi sowas, zum Beispiel
Integer möchte man einschränken,
in der Range, aber das kann man im Typsystem nicht so richtig ausdrücken
und ich finde, dann reicht oft schon,
um den gleichen Effekt zu haben,
im Newtype einzuführen, also wo ich das dann halt zum Beispiel
aktuell brauche, ist halt, ich habe halt
ein Jahr und ich weiß, dieses Jahr ist halt nur
von 2025 bis 2040
oder irgendwie sowas und
mir reicht
im Grunde, wenn, ich
mache das gar nicht über das Typsystem,
dass diese Range dann sozusagen abgesichert
wird, aber allein dadurch,
dass ich sage, ich definiere den Newtype
hier, der halt eigentlich
ein Int ist, kann mir der Type-Checker
sagen, wenn ich
irgendwie mal ein anderes Int da reingesteckt habe, was ich
nicht mal als Ja irgendwo anders deklariert habe
und krieg dann sozusagen
den Effekt, dass wenn da irgendjemand irgendwas reinsteckt,
was kein Ja ist, dann gibt's halt auch
ein, sagt der Type-Checker halt schon,
okay, nee, das sieht nicht gut aus.
Und so kann man sich halt das
sozusagen so ein bisschen
herbeiemulieren, dass man
irgendwie damit auch überprüft, ob das
inhaltlich Sinn macht.
Aber noch cooler wäre es natürlich, wenn du auch
die Werte angeben könntest.
Entschuldigung, Stefan.
Weißt du?
Also gerade mit dem,
also in TypeScript kannst du
das ein bisschen, du kannst teilweise
Werte oder
geringere Wertbereiche definieren.
Also in TypeScript ist es das Spannende,
wie in jedem Typsystem, du hast
Wertemengen und
du definierst ja nur, ob dieser eine Wert,
den du hast, jetzt in diese Menge passt
oder nicht. Das sind sehr
große Mengen zum Teil, String, Number
oder alle Objects.
Zum Teil sind sie halt auf deine
Objekttypen heruntergebrochen,
wo du sagst, diese Kombination an
Properties, die gewisse Typen haben,
erlaubst du dort oder nicht.
Du kannst aber auch sagen, hey,
dieser einzige
oder einzelne konkrete Wert,
die Zahl 1
des String-Stefan, was auch immer,
kann auch als Typ gelten.
Das heißt, du kannst einen Wert haben, wo du
Du sagst, alles, was diese Variable annehmen darf, ist der Wert 1.
Und das klingt am Anfang doof, weil was machst du mit einer Variable, die nur 1 sein kann?
Du kannst es schenken.
Aber du kannst noch diese Literal-Types oder Value-Types, wie es du benannt hast, Johannes,
kombinieren mit anderen Value-Types.
Und kannst dann zum Beispiel alle validen Augenzahlen eines Würfels darstellen.
1 oder 2 oder 3 oder 4 oder 5 oder 6.
Also damit hast du schon einen sehr engen Wertebereich definiert
und weißt noch aus, wenn ein Wert da reinkommt,
dann hat er garantiert eine dieser sechs Zahlen.
Und das ist spannend, das kannst du auch mit Strings machen.
Und was halt dann wirklich elegant ist, ist,
dass du zum Beispiel Strings mit gewissen Pattern definieren kannst.
Du kannst sagen, hey, du erlaubst alle Strings, die mit on anfangen,
weil du gerade dein Eventsystem implementierst
und du hast halt On-Click, On-Key-Down, On-Key-Press, was auch immer.
Das heißt, es muss mit On anfangen und nachher muss der erste Buchstabe unbedingt ein Großbuchstabe sein.
Solches Tricks akzeptierst du, andere akzeptierst du nicht.
Da kannst du wirklich sehr elegant Wertebereiche definieren, mit denen du korrekte Werte angibst,
mit denen du auch über deine Werte diverse Aussagen treffen kannst, die dir nachher helfen,
die aber jetzt nicht so übermäßig komplex sind.
Dass du jetzt sagst, hey, das ist jetzt viel zu viel Aufwand, das zu definieren.
Mein Lieblingsbeispiel ist immer noch HTTP-Methoden,
Get, Post, Delete, was auch immer.
Oder HTTP-Error-Codes, da gibt es 70 um den Dreh.
Ich weiß jetzt nicht, ob es 201 gibt, ob es 217 noch gibt, weiß ich nicht.
Das kann mir dieser Union-Typ sehr, sehr schön sagen.
hat. Und dann bin ich mir
sicher, dass ich den richtigen
HTTP-Statuscode in meiner
Response schicke und
brauche nicht großartig überlegen,
ob ich noch im richtigen Wertebereich bin oder nicht.
Ich muss mich
einmal korrigieren. Ich habe eben nachgelesen,
Value-Types ist nicht das richtige Wort.
Das bezieht sich auch auf etwas anderes.
Das wird als
Abgrenzung zum Reference-Type verwendet.
Also ob man einen Wert oder
eine Referenz hat. Aber das Konzept
ist
hast du gerade sehr schön erklärt. Vielen Dank, Steffen.
Das ist auch in Kapitel
4 beschrieben von meinem Buch
und da bist du ja noch nicht.
Das haben wir vorhin schon festgestellt, ich habe noch nicht
weit genug gelesen. Aber ich
habe es jetzt wieder rausgeholt und jetzt
lege ich es mir unter das Kopfkissen
und werde das per Diffusion
aufnehmen. So wird die
Matura geschafft mit dem
Mathematikbuch unter dem Kopfkissen.
Funktioniert.
Ich finde, wir müssen noch ein bisschen darüber reden,
wie man das so in Python
dann machen kann noch und wie man das
Typing-Modul vielleicht noch so ein bisschen benutzt.
Wir hatten jetzt ein Newtype, was
irgendwie ganz cool ist. Wir hatten die Generics.
Ja, also Generics, achso, genau.
Wo wir dann schon mal, da habe ich nämlich jetzt heute
eins gehabt, da dachte ich mir so,
oh mein Gott, wenn, hoffentlich fragt das keiner, deswegen frage ich
das jetzt mal, kann mir
einer vielleicht erklären, was der Unterschied zwischen
Co-Variant, Contra-Variant und In-Variant und so
ist, weil das kann man nämlich auch mit angeben
und ich dachte mir so, okay, ich kann es ja angeben, aber
oh Gott, was bedeutet das eigentlich?
Und was macht dann Bound und so?
Ja.
Ich kann es aus einer Typtheorie sagen, was Co- und
Contra-Variant ist. Ich weiß aber nicht, ob das so
auf Python auch zutrifft.
Aber ich versuche
es jetzt mal so zu erklären.
Co-Variant ist, wenn du
Schnell die
Petitfragen.
Nein, es ist irrsinnig schwierig zu erklären.
Lass mich kurz mein zweites Buch aufmachen, weil da wird
Zeichnung.
Also bevor ich jetzt allgemeine
Beschreibungen erkläre, sage ich es lieber mal so.
In einer Co-Varianten-Beziehung
hast du zum Beispiel einen Typ, der
ist String oder Number,
was bedeutet, dass wenn du einen Wert
hast, der Number ist, dann kannst du
dir auf jeden Fall auf diesen einen Typen
zuweisen, der String oder Number sein kann.
Das heißt, je enger dieser Wertebereich
wird,
hat kein Effekt drauf,
kannst du weiterhin darauf zuweisen.
Die Contra-Variante ist genau umgekehrt.
Du kannst zum Beispiel jetzt nicht
eine Funktion, die als ersten Parameter
String oder Number, oder
einen Funktionstypen, der
als ersten Parameter String oder Number erwartet,
kannst du jetzt nicht
eine echte Funktion zuweisen, die
nur String erwartet, weil ja
der Fall, dass auch ein Number als Parameter
sein kann, nicht dadurch abgedeckt wird.
Das heißt, du hast der Typ zwar auch ein Subtyp,
der Parametertyp ist ein Subtyp
vom anderen,
aber nachdem der in einer Funktion steht,
sind die nicht zueinander kompatibel, sondern
nur umgekehrt. Das heißt, du kannst eine Funktion,
einen Funktionstypen definieren, der als ersten
Parameter eine Number angibt, was bedeutet,
dass du auch Funktionen zuweisen kannst,
die String oder Number
erwarten, weil eben dieser eine Fall
abgedeckt ist. Und das ist der Unterschied zwischen
Kovarianz und Kontravarianz. Brauchst du eigentlich nie,
macht halt irgendwelche komischen Fehlermeldungen, wenn du
irgendwelche Sachen zuweisen willst, die dann nicht so funktionieren.
Ist
aber, glaube ich, in der Typtheorie
die korrekte Beschreibung.
Ist nicht kompliziert, ich möchte euch da für die
Shownotes eine Grafik zur Verfügung stellen,
die das wunderschön erklärt.
Und da suche ich mir den Link jetzt wirklich
raus aus meinem Buch, weil das habe ich genau
aus dem Grund habe ich es da reingetan.
Weil das sind die Sachen, die merke ich mir selber nie genau.
Das ist was man immer nachlesen muss. Also in welche
Richtung kann man was irgendwie doch voneinander
erben, wenn ich das richtig verstehe?
Generisieren.
Generisieren. Also ich habe es
jetzt hier auch gerade, wenn jemand
anders spricht, kann ich ja googeln.
Also so wie ich
das jetzt hier verstehe, ist es, das
bezieht sich direkt auf Python hier
und die Qualitätsquelle Stack Overflow
kann man ja auch verlinken.
Es wird hier so erklärt,
du hast zwei Klassen,
Basisklasse und eine abgeleitete Klasse.
Die derived.
Genau.
B und D,
also Basisklasse und abgeleitete Klasse.
Und du hast irgendeine generische Typenliste
mit irgendeinem Typen drin.
Und jetzt ist die Frage,
wenn du eine Liste hast,
die den Typen B hat,
also den Basistypen,
kannst du die dann da verwenden,
wo du eine Liste vom Typen D erwartest, also eine abgeleitete Klasse.
Oder ist es andersrum?
Das wäre dann Co-Variant oder Kontra-Variant.
Genau, das eine ist Co-Variant und das andere ist Kontra-Variant,
weil du eben sagst, okay, wenn du den als Generic verwendest,
dann geht die Beziehung in die eine Richtung
oder die Beziehung geht in die andere Richtung.
Und das ist natürlich schön, dass man da zwei Worte genommen hat,
die exakt gleich klingen.
Also Co-Variant ist, wenn man quasi annotiert mit der Implementierung
und Contra-Variant ist, wenn man mit der
Basis
notiert, ja. Und
Invariant wäre dann, wenn man nicht
beides verwenden darf, weil
der sagt ja halt, nö, das ist nicht genau
das, was ich erwarte.
Ja, irgendwie so. Für genauere Sachen
muss man PEP484 lesen, das haben wir
ja sicherlich alle schon gemacht.
Muss man gar nicht genauer drauf eingehen.
Ich packe die Grafik
in die Show Notes und dann schauen wir mal.
Genau.
Ja, aber genau, ich dachte
auch so, also man kann das ja angeben
und dann dachte ich so, ich hab das noch nie verwendet, ist das
irgendwie, hab ich was, pass ich
was oder? Und was macht dann Bound?
Also weil das
macht man ja irgendwie auch bei den Contra-Variants
oder ist das schon das?
I don't know.
Steht zumindest in der Types, Pricing, Typing.
Tatsächlich ist in dem
PEP484 eine sehr schöne Erklärung drin.
Mit
Employees und Managers.
Wenn du eine Liste, wenn du eine Funktion hast, die eine Liste von Employee nimmst, solltest du da, kannst du da eine Liste von Managers reingeben?
Und für manche Funktionen kann das ja sein, wenn du halt sagst, okay, wir müssen Gehalt auszahlen, das müssen Angestellte kriegen und wenn die Angestellten Manager sind, dann ist es halt so.
Kann aber auch nein sein, dass du zum Beispiel, keine Ahnung, alle die Angestellten aufsetzt.
Alle Angestellten feuern, nur Manager feuern.
Genau. Aber dass du zum Beispiel jemanden hinzufügst zu dieser Liste. Und wenn du sagst, okay, die Funktion nimmt eine Liste, die die Angestellte enthält, dann kannst du in diese Liste auch einen Angestellten reintun. Wenn du aber eine Liste von Managern reingegeben hast, dann geht das nicht.
Und das ist jetzt eben genau so eine Frage, wo du beide Optionen haben kannst, also so eine Situation, wo du beide haben kannst und das tatsächlich auch eigentlich beantworten können musst, ob du da eine abgeleitete oder eine Basisklasse reingeben darfst.
Das ist eine Co-Variante, eine Contra-Variante.
Und der Bound ist dann quasi tatsächlich die,
wenn dann erst die Manager gefallen,
weil das die spezialisiertere Variante ist.
Ja, wir haben noch mehr von dem Typing-Modul,
damit wir uns noch mehr schöne Sachen dazu erzählen können
und mehr ergänzen können mit präzisem Fachwissen.
Und zwar den Type-Adias und die Type-Ware,
die da noch irgendwie dazu können.
Also was ist denn der Unterschied?
Und man kann ja auch noch das schöne Keyword Type
dazu schreiben und sowas.
Ich meine, bei Type-Alias, das
kannst du auch einfach so hinschreiben, es ist nur eine explizitere
Darstellung und manchmal ist es halt
problematisch, wenn du zum Beispiel einfach einen String verwendest,
den du ja auch quasi benutzen kannst,
statt, und manchmal muss man das ja auch
um zyklische Imports zu vermeiden und so,
dann ist halt unklar, was gemeint ist,
wenn man den nicht Type-Alias davor schreibt.
Also beispielsweise, wenn ich jetzt irgendwie eine Union habe,
das kann jetzt mehrere Sachen sein, dann kann ich dann
Type-Alias dafür verwenden, dass das damit
gemeint ist, dass es einen Namen gibt. Ja, aber du könntest ja auch einfach
hinschreiben, myUnion gleich
und dann irgendwie
der Typ, Pipe-Symbol,
der andere.
Das ist dann ein Type-Alias schon.
Das selber kann ich annotieren mit, nein, ist es nicht?
Ja, also du könntest damit dann wieder
annotieren, aber wenn du
jetzt zum Beispiel da Strings verwenden
wollen würdest für die Typ-Typen,
dann geht's
halt nicht mehr so richtig.
Also Type-Alias macht das dann halt
explizit, dass das halt sozusagen...
Und die Type-Ware,
das hatten wir eben, TVK, TKV,
warum TKV jetzt da
im besonderen Sinne, weil ich diese kurzen Dinge
nicht, also einer der Gründe, warum ich Go nicht leiden kann,
sind diese
Ein-Charakter-Variablen-Namen, aber
ja. Ja, das sind halt die Generics, oder, die wir
vorhin hatten. Ja, genau. Stefan, du hast angesetzt.
Erklär uns, was Type war.
Ja, also ich habe jetzt ganz kurz diesen PEP-Vier-Ocht-Vier
aufgemacht und der ist wunderschön.
Der ist super, oder?
Also eine Type-Variable, also ich sage immer
Type-Parameter dazu, aber das ist im Grunde
genau das Gleiche. Das ist eben diese
ein Typ, der später durch
einen konkreten Typ ersetzt wird. Das heißt, du kannst
Also jetzt sagen wir, du hast diese Typvariable
in diesem Beispiel von pep484, das ist st,
seist type wird das heißen dort,
weil da geht es um seist,
wo du sagst, hey, du machst jetzt eine Funktion,
die erlaubt x beliebige Typen,
allerdings kannst du sie durch irgendeinen Bound,
das ist das zweite dort,
der zweite Parameter, einschränken.
Also ein Bound sagt hier,
oder der generelle Typ-Rameter sagt dir,
alle möglichen Werte, aber später nur ein konkreter.
Und der Bound sagt dir, alle möglichen Werte,
die auch diese Eigenschaften erfüllen, später ein konkreter.
Und das ist dort in diesem Beispiel recht gut,
weil da wird Seist als Bound definiert,
was bedeutet, dass du eine Länge definieren können musst
oder eine Länge lesen können musst.
In Python hast du ja nur diese Hilfsfunktion,
du hast ja selten Methoden auf Klassen,
soweit ich das weiß.
Deswegen brauchst du halt überall diese Bounds.
Andererseits könntest du ja sagen,
du hast irgendeine Subklasse oder so.
Aber Bound ist auch etwas,
das kennen wir in anderen Programmiersprachen auch.
In TypeScript wird das als Constraint bezeichnet.
Aber im Grund geht es darum,
dass du einfach vordefinierst,
du hast ein paar Eigenschaften,
die du sicherstellen willst.
In dem Fall, was dort beim PEP484 ist,
mit diesem Upper-Bound, sagst du einfach,
du willst die Möglichkeit haben, eine Länge zu berechnen,
du willst einfach wissen, hey, da gibt es eine Size,
das hat eine gewisse Längegröße,
was auch immer.
Spannend wäre es, ob ich dort einen String reingeben kann,
weil man kann ja die Länge von einem String definieren.
Ja, kannst du.
Alles, was Length von irgendwas hat,
ist Size.
Also ich kenne keinen Python, aber ich habe diesen Code jetzt gelesen
und weiß sofort, was ich da zu erwarten habe,
weil ein String muss auch
eine Länge rauskriegen.
Schon cool.
Ja. Und das ist auch sehr interessant hier, weil also diese Type Variable, die gerade in diesem Beispiel, ich habe es zufällig auch gerade offen, benutzt wird, die wird in dieser Funktion, da wird eine Funktion definiert, die heißt longer und die nimmt zwei Variablen, x und y, die sind beide vom Typ st und der Rückgabewert ist ebenfalls st.
Und das ist eine sehr interessante Sache, weil das eben bedeutet, du kannst hier zwei Sachen reingeben, die von der gleichen Sorte sind und kriegst wieder eins raus, was wieder von der gleichen Sorte ist. Aber wir sagen gar nicht genau, was das für eine Sorte ist, sondern wir sagen nur, das muss als Anforderung haben, das Minimum, was es erfüllen muss, das ist der Bound, ich muss davon die Länge abrufen können.
Und das hat diese Funktion schon sehr genau spezifiziert, die Spezifikation dieser Funktion, also longer x, y ist ja erstmal sehr lose und jetzt durch diese Typvariablen und durch den Bound ist es doch relativ genau spezifiziert und auch sehr exakt, würde ich sagen.
Was ich sehr spannend finde an dem Beispiel, und das ist wahrscheinlich jetzt so ein Python-Eigenwort, aber im ersten Aufruf wird dort dieser generische Typ-Parameter oder diese Type-Var ersetzt durch eine List, das ist glaube ich die eckigen Klammern, im zweiten Aufruf, da hast du geschwungene Klammern, wird es durch ein Set ersetzt, also der Typ wird durch ein Set ersetzt, aber im dritten, da ist im ersten Aufruf eckige Klammern, im zweiten Parameter sind geschwungene Klammern,
da wird der Parent-Type davon eine Collection verwendet,
wo du sagst, hey, okay, ist nicht List, ist nicht Set,
also es könnte beides sein,
du nimmst einfach was, was beide beschreibt.
Finde ich cool, dass das das Typsystem so macht.
Normalerweise würde TypeScript dir da vielleicht einen Fehler werfen.
TypeScript würde da sagen,
hey, wenn du das einmal durch einen Typ ersetzt,
dann musst du auch im zweiten Parameter
den gleichen Typ verwenden
und so findest du aber in der Hierarchie
tatsächlich einen Parent-Type, den du nutzen kannst.
Das ist ziemlich geil.
Also, richtig gut.
Ja, das ist ziemlich schön.
Also, nämlich auch so, dass ich das jetzt
verwenden möchte, muss ich ganz ehrlich sagen.
Ich glaube, ihr habt es so weit.
Sehr gut.
Viele Programmiersprachen-Features
kommen ja durch Knight
umgesetzt. Das ist bei Python
und auch nicht anders.
Viele Sachen sind einfach aus Knight durch andere
Sprachen entstanden.
Also, den größten Knight
habe ich ja durch die Import-Signatur.
das macht einfach so viel einfacher.
In JavaScript ist es umgekehrt,
du importierst zuerst die Einzelelemente
aus dem Paket
und das ist reine Ästhetik, so ist
viel klarer, du spezifisierst
zuerst das Paket und dann importierst du die Sachen
draus, jeder Editor freut sich, wenn er das
so kriegen kann.
Ja, was
mich noch interessieren würde hier an der Stelle,
ist diese Overloads, die da mit drinstehen,
das ist ja auch so eine Sache,
die man nur bei den Type Annotations
findet oder auch woanders, wo halt derselbe
Methodenname mehrfach hintereinander
definiert wird. Was macht denn das genau?
Schreibst du
in Python dort dann beide
Methoden aus? Also implementierst du da
beide Methoden oder
sind es nur die Signaturen?
In Python musst du
dich da anstrengen dafür. Das hat ja nicht mal viel
mit, ja es hat vielleicht schon
was mit Types zu tun, aber
also so richtiges
Overloading gibt es ja gar nicht in Python.
Du fügst eine weitere Signatur
hinzu zur Methode. Ja genau, was macht denn
Aber du hast doch nicht zwei Funktionen,
du hast zwei Signaturen.
Du hast eine Funktion, die,
also es ist so,
der ganz
grundlegende Prozess ist, dass eine Funktion
in Python eine Variable ist,
die halt ein
Funktionssubjekt enthält.
Und diese Variable hat einen Namen und diesen Namen,
der ist eindeutig, den kannst du nur einmal geben.
Und zu diesem Namen kannst du auch nur diese eine Funktion geben.
Was du jetzt aber machst,
um Überladung zu machen,
und ich erkläre es gleich noch für die Zuhörer,
ist, dass
du sagst, du definierst
eine Basismethode und der fügst du
dann eine weitere Signatur hinzu.
Und wenn diese, da ist dann eben so ein
durch Dekoratoren
hast du so einen Mechanismus, der diese Signaturen
entsprechend überprüft. So, was ist
Überladung überhaupt und was erreicht man damit?
Überladung ist, wenn
du eine Funktion, also ganz
klassisch aus dem Java-Umfeld, wenn du eine Funktion
hast, die heißt add
und die definierst du für float und float und dann
kommt hinterher wieder ein float raus.
Dann funktioniert die ganz einwandfrei für Floats, aber du kannst damit nicht Ints adden, kannst keine Integer addieren, weil der Compiler dir sagt, ich habe die Funktion gefunden, aber die geht nur für Floats.
Was du jetzt in Java machst, ist, du schreibst eine zweite Funktion, die auch Add heißt, aber die eine andere Signatur hat und die wird durch das Kompilat eher zu einer anderen Funktion.
Das heißt, zum Zeitpunkt des
Kompilierens kann der Compiler sagen, ah, du meintest
diese Funktion mit der Signatur
oder du meintest diese Funktion mit der
Signatur. Und das geht
auch in TypeScript, wenn ich mich recht erinnere,
dass du überladene
Methoden hast, die dann eben durch
den Compiler zum Zeitpunkt des Compilens
die richtige
Zuweisung bekommen. Die sind dann im
JavaScript-Kompilat, heißen die dann unterschiedlich,
weil die eben da unterschiedlich sind.
Das ist genau der Unterschied.
Nein, ein Overload in TypeScript ist im Grund nur eine andere Funktionssignatur über der tatsächlichen.
Du musst mindestens zwei angeben. Eine, die dem Typsystem mitgeteilt wird als Nutzungssignatur
und eine, die du verwenden kannst, um tatsächlich die Funktion zu implementieren.
Und dann kannst du so viele Overload schreiben, wie du willst.
Und du hast dort einfach unterschiedliche Aufrufe, durch die du durchgehen kannst.
aber im Endeffekt wird nur eine Methode aufgerufen
oder eine Funktion aufgerufen.
Deswegen habe ich genauso nachgefragt,
weil ich bin mir nicht sicher,
wie das jetzt in Python funktioniert,
weil es ist spannend.
Es hat Führungslieder.
Okay.
Genau.
In Python ist es ein bisschen anders.
In Python musst du das eben über Dekoratoren machen,
weil du diesen Namen nicht mehrfach haben darfst.
Und was da im Wesentlichen passiert ist,
du sagst, wenn die Methode aufgerufen wird
zwei Variablen oder mit
Argumenten, die
dieser Signatur entsprechen, dann rufe bitte
diese Subsignatur
auf. Also du fügst da quasi
eine weitere Funktion hinzu, die nur in bestimmten
Fällen aufgerufen wird. Aber das ist
was, was zur Laufzeit passiert. Also zur Laufzeit
wird
dann entschieden, welche
Submethode
aufgerufen wird. Das ist im Wesentlichen
ein Match Case,
der da vorsteht.
Ich weiß nicht, ob das im Typing-Zusammenhang
nicht was anderes ist. Also ich meine, es gibt diese
Overload-Geschichten vielleicht
in Klassen, aber ich meine hier
auch bei Funktionen,
wenn ich jetzt einfach das sozusagen für diese
Typ-Annotation verwenden will, dann ist es
soweit ich sehen kann auch so. Es gibt die Funktion einmal,
aber
ich kann halt viele sozusagen
mit Overload dekorierten
Funktionen haben, die keine Implementationen haben,
aber wo ich sozusagen nur
quasi die unterschiedlichen
möglichen Arten
wie ich das, wie das aufrufen
werden kann, halt annotiere, weil ich das nicht in
eine Annotation schreiben kann, weil geht halt
nicht. Und
ja. Ach so, okay.
Da gibt es zwei, also es gibt
mehrere Overload
Dinge, denke ich.
Genau, also das
ist blöd, ja. Es ist blöd, dass
diese Sachen in unterschiedlichen Sprachen
unterschiedliche Dinge bedeuten.
Also wenn ich der Kaiser wäre,
dann wäre das anders.
Also das ist tatsächlich was, was ich vermisst habe an Python, als ich zu Python gekommen bin aus Java. In Java kannst du sagen, ich habe hier eine Funktion, die heißt Add und die nimmt Integer und ich habe eine Funktion Add, die nimmt Strings und ich habe eine Funktion Add, die nimmt, was weiß ich, Listen.
Und die machen sehr unterschiedliche Dinge, aber im Endeffekt
das gleiche Semantische. Die fügen die
aneinander. Und die heißen
gleich, weil die das gleiche machen.
Und sowas gibt es in Python nicht, weil in Python
musste jedes Mal
einen neuen Namen haben dafür
oder einen neuen Scope oder so.
Und dafür gibt es Single Dispatch.
Ja, das hat
damit zu tun, dass
es möglich ist, dass du
den gleichen Namen mehrmals vergeben kannst.
Ja, weil die beim Kompilieren
die Namen weg sind beim Kompilieren.
Nein, nein, weil die
Funktionssignaturen Typen haben.
Nein, weil die Funktionssignaturen Typen haben.
Weil Java die Typen
erfordert
und dadurch ist
einfach genug Unterschied da, um das
zu identifizieren können.
Genau, es sind unterschiedliche Funktionen.
Also die Funktion addIntInt ist eine andere Funktion
als die Funktion addFloatFloat.
Und darum ist natürlich in JavaScript und Python
halt komplett anders, weil im Endeffekt hast du halt nur
eine Funktion mit ein paar Parametern.
Und die Typen sind ja, wie wir mitbekommen haben,
eigentlich wurscht.
Die sind dann weg.
Ja, zur Laufzeit auf jeden Fall.
Aber diesen Mechanismus, den kriegst du hin,
der heißt Single Dispatch.
From Functools import Single Dispatch.
PEP 443.
Das, was ihr beschrieben habt,
das heißt Overload,
das ist ja was ganz anderes. Python lang
util.
Okay.
Ich hab's jetzt hier aus, von Typing.
Also, so wie ich
das gesehen hab, es gibt auch so ein sehr schönes
Beispiel dafür, das ist auch aus dem
Fluent Python Buch, hab ich das
da, also das ist halt
so ein Beispiel für Methoden, die halt
eigentlich in, also, die hat auch so ein
Problem, dass man mit Type
Annotationen halt so hat,
beschreiben nämlich, dass man
die Typannotationen nicht so
also die ist ja auch eine Sprache, ist halt eine andere
Art, das hinzuschreiben
und die ist halt nicht so expressiv wie Python selber.
Das heißt, wenn ich jetzt Funktionen habe, wie zum Beispiel
min und max, jetzt weiß ich gar nicht, ob es das
in der JavaScript-Welt auch so
gibt, aber die
kann ich halt sehr schön in Python hinschreiben
so in irgendwie so
20 Zeilen oder sowas
und ist sehr schön zu lesen,
ist nicht kompliziert.
Und die Typ-Annotation dafür ist aber sehr, sehr schwer, weil das halt so super generisch ist.
Und dann kann man noch ein Callback übergeben, das halt irgendwie zum Sortieren verwendet wird und sowas.
Und ja, die korrekten Type-Annotationen für Min und Max sind halt sehr viel länger als die Implementation.
Und das liegt halt daran, dass man das in dieser neuen Annotationssprache halt nicht so gut hinschreiten kann.
Und dafür, also da hast du dann halt so irgendwie, ich weiß nicht, zig Overloads, weil du kannst das sowieso immer nur quasi für einen Teil der, wie man das aufrufen kann, halt annotieren.
Und dann musst du das halt, musst du halt zehn Dinger übereinander häufen, um das halt irgendwie abgebildet zu kriegen.
Und ja, und auch in diesen Dingern sind dann halt, waren halt lange Fehler drin und die sind halt auch echt schwer zu finden.
Also ja.
Und die machen ja auch überhaupt gar nichts, diese Fehler, jetzt mal ganz ehrlich.
Ja gut, na gut, also irgendjemand hat dann halt, es kann ja sein, du rufst das halt auf, lässt es auf eine bestimmte Art und dann läuft dein Typechecker drüber und der sagt, der spuckt dir dann halt irgendeine Fehlermeldung aus, die vollkommen unverständlich ist und das verdirbt dir halt den Vormittag oder so, weil du verstehst gar nicht, wo das Problem ist.
Und dann war es halt nicht mal wirklich ein Problem,
sondern es war einfach nur etwas, was halt
in den Annotationen kaputt war.
Und du hast es korrekt aufgerufen.
Das ist ja schon ärgerlich.
Also ich meine, ja, also
ja, gut.
Zugegeben, ja.
Aber
Aber was war jetzt die Lösung, Jochen?
Ich habe dich jetzt unterbrochen, aber
gibt es da jetzt eine Lösung dafür? Kann ich jetzt da Overload sagen?
Genau. Und du kannst jetzt sozusagen,
wenn du eine Funktion
annotieren möchtest, aber das halt die
Annotationen nicht einfach so hinschreiben kannst, dann kannst
du die möglichen Arten,
wie das halt, also
wenn du mehrere
Annotationen hinschreiben musst
für die Funktion, kannst du das per Overload
hinschreiben. Hast dann halt der
Methoden-Body oder Funktions-Body
ist einfach Ellipsis, also
Punkt, Punkt, Punkt und
genau, dann kannst du halt alle
Arten, wie man das Ding halt getypt
aufrufen kann, halt hinschreiben.
So richtig schön sieht das aber auch nicht aus.
Ne, das sieht nicht schön aus.
Ich würde es zum Beispiel in TypeScript
auch nicht immer verwenden.
Meistens ist es ein Codespell, wenn du
Methoden oder Funktionen
hast, die mehr können
soll, als für das, was
sie beschreibt. Ja, so ein bisschen
so eine Krücke, warum machen wir das dann nicht?
Vielleicht, wenn man so ein Public-API-Interface
hat, was unbedingt benutzt bleiben muss,
aus irgendwelchen Gründen.
Vielleicht für Legacy oder sowas.
In JavaScript gibt es es, weil
also in TypeScript gibt es das, weil du halt
in JavaScript Parameter
weglassen kannst
oder
Parameter
in unterschiedlichen Positionen auch was anderes heißen
und da hat TypeScript
irgendeine Methode gebraucht, um das darzustellen
und deswegen
haben wir es. Ja, gut, wenn man
Sternchen, Quark schreibt oder sowas.
Also gerade dieses Ads-Beispiel von Johannes,
das würde ich eigentlich jetzt
in TypeScript mit
mit Generics umsetzen
hat.
Ja gut, wenn du jetzt
die Methode
Add für Integer und die Methode Add für Stringen
hast, musst du ja schon zwei unterschiedliche
Implementierungen haben auch.
Also an irgendeiner Stelle musst du ja deine
Implementierung verzweigen.
Nicht in
JavaScript. Ja, wenn du Plus verwendest,
okay, aber dann musst du das Plus irgendwo hin
verzweigen, weil das macht ja sehr unterschiedliche Dinge.
Ja.
Dann könnte ich das dann dann Etto überschreiben.
Ja, ja.
Ja.
Was mir noch
fehlt, wir haben schon relativ viel
gesagt, was ist sowas wie, ich glaube es ist eben
schon einmal gefallen, sowas wie rekursive Types oder sowas.
Wenn ich zum Beispiel einen Jason-Type definiere.
Hier, sag doch nicht sowas.
Kapitel 7.
Bin ich ja noch weit entfernt von Kapitel 7.
Ja, also rekursive Types
rekursive Types ist schon
nötig. Wenn du jetzt zum Beispiel
eine Liste definieren willst, eine einfach
verkettete Liste, dann hast du dort
einen Knoten und du verweist auf den nächsten
Knoten.
Aber das ist eigentlich
nur ein Typsystem-Fu, also du musst
irgendwie die Möglichkeit
haben, dass du Typen definieren kannst,
die sich selbst
referenzieren können, wenn nötig.
Also wie JSON-Objekte
oder sowas zum Beispiel tatsächlich?
Zum Beispiel, ja, genau. Also in JSON
kann es ja auch sein, dass du
naja, schwierig.
Ja, eine Liste von Objekten habe,
in denen andere Listen stecken, die wieder irgendwie
Teugs haben oder so. Ja, genau.
Oder ein Array von Arrays,
wenn du schon dabei bist.
Aber ich habe eben mal mit
jemandem vom TypeScript-Team gesprochen,
bezüglich rekursiven Typen.
Das ist meistens
Implementierungsdatei, wie tief der Compiler
dort denn gehen kann. Also was sind die,
wie
ist der Compiler entwickelt?
dass er bald genug sagen kann, hey, da stoppe ich jetzt
und passe nicht mehr weiter. Also wie geht der Compiler
mit der Regression?
Typsysteme können das eigentlich.
Also auch in der IDE, ich weiß nicht, bei JSON-Type
oder sowas, bis wie viel Level-Tief
darf der denn gucken, ob das noch
stimmt?
Und da werden es auch immer besser.
Das ist der Mathematik-Egal.
Das ist der Mathematik-Egal, die guckt
Ja.
Genau.
Ja, da kommt dann wieder darauf an, welche Art von Mathematik, wenn man den konstruktiven Zweig anhängt. Das gibt es gar nicht.
Wenn du schon in der Grundvorlesung, also ich habe ja eine mathematische Ausbildung genossen an der Universität, da werden dann die natürlichen Zahlen nochmal definiert und die werden rekursiv definiert.
Da gibt es eigentlich nur eine natürliche Zahl.
Das ist die 0 oder die 1, je nachdem, wo du anfangen willst.
Und dann sagt man einfach, jede Zahl hat einen Nachfolger
und zack, hast du alle natürlichen Zahlen beisammen.
Also es geht schon weit rein mit der Rekursion
und die geht auch weit genug in der Mathematik.
Ja, ich weiß nicht, haben wir noch?
Ah, was mir noch einfällt, genau.
Das schließt so ein bisschen an das Pidentik-Thema von eben an.
Ich meine, das ist ja jetzt etwas, was man, also
die Typen werden ja
zur Laufzeit ignoriert
in Python, aber
nicht immer und man müsste es auch nicht, weil
im Grunde kann man rausfinden,
wie die Annotationen sind
und es gibt halt auch Software, die das macht,
wie zum Beispiel Pydentic.
Ja, oder MyPy.
Oder FastAPI. Oder FastAPI.
Ja, genau.
Gibt es sowas eigentlich in TypeScript auch?
Weil, ich meine, gut,
Das wird ja kompiliert zu JavaScript, aber es gibt ja jetzt auch, glaube ich, Interpreter, die direkt TypeScript interpretieren.
So Deno oder sowas macht das, glaube ich. Ich weiß nicht so genau.
Könnte das ja im Grunde genommen tun.
Das ist ja ein weitverbreiteter Irrglaube, dass Deno direkt TypeScript interpretiert.
Deno hat nur einen TypeScript-Compiler inkludiert und kompiliert TypeScript, bevor er das JavaScript ausführt.
Also tatsächlich, ich sage mal, im JavaScript-Bereich reden wir eher von unterschiedlichen Typsystemen, die existieren.
wie Flow-Type ist zum Beispiel
eins, das sehr, sehr optisch sehr, sehr ähnlich
ist zu dem, was TypeScript
zur Verfügung stellt, aber halt
in den Nansen unterschiedlich ist.
Oder eben TypeScript
und das sind auch schon die populärsten.
Der Clojure-Compiler hat einmal ähnlich funktioniert.
Coffee-Script gab es früher.
Ja, Coffee-Script ist aber sogar
eine eigene Programmiersprache.
Ja, aber komplett, also ich meine.
Gleiche Historie.
Ähnlich, ähnlich. Da gibt es auch einen wichtigen Punkt, weil wie Typen definiert werden in JavaScript, das ist ja eigentlich nicht dem TypeScript-Team zu verdanken, sondern dem ECMAScript-4-Standard, der schon viel, viel älter ist, der nie umgesetzt wurde, an den sich aber alle Typsysteme jetzt irgendwie dranhalten bei der Definition des eigenen Typsystems.
Ich würde eher sogar sagen, dass Action-Skript, also die Flash-Programmiersprache noch eher ähnlicher oder verwandter mit TypeScript und Flow-Type ist. Aber das ist es dann auch. Also du hast entweder unterschiedliche Typsysteme, dann entscheidest du dich in den meisten Fällen heutzutage eh für TypeScript und dann bietet dir TypeScript eigentlich alles, was du dafür brauchst.
Also du laufst da gar nicht in Gefahr, dass du irgendwie ein anderes Werkzeug nimmst. Und TypeScript versteht halt auch komplett JavaScript. Das heißt, du kannst halt dort noch mit JavaScript-Code anfangen und dich nur einmal auf die Typ-Inferenz vom TypeScript-Type-Checker verlassen.
Dass du sagst, ich weiß jetzt, welche Typen du verwendest, rein in der Verwendung deines Codes. Dass du jetzt so eine retroaktive Typ-Annotation machst, macht man eher nicht. Es gibt ein paar Werkzeuge, ich könnte aber jetzt nicht den Namen dazu sagen, macht man aber aus dem Grund nicht, weil der TypeScript-Type-Checker eh gut genug ist, dass er schon sehr, sehr viel herausfindet, bevor du überhaupt irgendeine Annotation machen musst.
Was ein gutes Migrations-Solis ist, ist JS-Doc, das ist eine Typ-Annotation im Kommentar,
wo du einfach sagst, hey, du hast diese Funktion, die hat drei Parameter,
du definierst den Typen im Kommentar und nicht im Code und das machen viele Bibliotheken,
das machen sehr viele alte JavaScript-Bibliotheken, wie zum Beispiel Lodash oder Underscore schon
und TypeScript kann mit dem umgehen, also TypeScript kann auch Typ-Informationen aus diesen Kommentaren lesen
und hat halt so weit mehr Kompatibilität mit dem gesamten Ökosystem,
als wenn sie darauf bestehen würden, dass sie nur die Typen verwenden, die du annotierst.
Okay, aber so ein richtiges Äquivalent zu dem, was der Jochen gefragt oder gesagt hat,
gibt es nicht wirklich.
Zur Laufzeit hast du nicht wirklich mehr die Typinformation.
Also zur Laufzeit, es gibt Bibliotheken, die fügen Typinformation zur Laufzeit hinzu und leiten dadurch TypeScript-Typen ab, aber das ist es dann schon. Also es gibt auch ein paar so Reflection-Geschichten, das ist aber alles Mumpitz, also das möchte ich nicht einmal erwähnen, weil es einfach Schwachsinn ist.
Eine Sache, die aber gut ist zum Beispiel, das ist SOD.
Wenn du jetzt sagst, du brauchst jetzt Typinformationen zu Laufzeit auch,
dann kannst du über die SOD-Bibliothek dir deinen Typen in JavaScript definieren.
Das ist aber nicht TypeScript, das ist JavaScript.
Und kannst dann, wenn du diesen Typen weiter im TypeScript-Code verwenden willst,
sagen, hey, leite mir jetzt aus diesem JavaScript-Konstrukt, das ich gebaut habe,
das einen Typen darstellen soll, leite mir von diesem JavaScript-Konstrukt
doch einen TypeScript-Typen ab, den ich weiterverwende.
Und du bekommst dann zum einen einen klassischen TypeScript-Typ, den du in deinen Methodensignaturen verwenden kannst, den du annotieren kannst, wo du typechecken kannst, das funktioniert, das ist grandios gut.
Parallel dazu hast du aber immer noch dieses JavaScript-Konstrukt, mit dem du erst eine Validierung empfangen kannst. Das heißt, du kannst sagen, hey, du kriegst jetzt ein Chasen von einem Backend, steckst es in den Validator rein und kriegst entweder Ergebnisse, die es nachher dem Typen entspricht, super, oder Fehlermeldungen, mit denen du umgehen kannst.
und das ist eine
grandiose Bibliothek.
Erstens
ist sie so nah an TypeScript, dass du
wirklich sämtliche Dinge, die du in TypeScript schreiben kannst,
auch damit umsetzen kannst
und zweitens ist sie schnell,
sie macht robusteren Code,
ich bin total glücklich mit der, die kann ich sehr, sehr gut empfehlen.
Also unbedingt.
Aber prinzipiell gilt es.
Okay, cool. Also ein ähnliches
Verfahren. Sehr ähnlich.
In Salt ist es aber so, dass du
die Typen dann anfängst
zu schreiben in dieser JavaScript-Welt
mit den dort vorhandenen Methoden und Funktionen.
Und das ist halt umgekehrt zu dem,
wie es du normalerweise in TypeScript auch ist,
dass du sagst, du schreibst deine Typen
und die sind nach dem Kompilator einfach weg.
Also TypeScript ist so eine Erased-to-JavaScript-Sprache,
was auch bedeutet, wenn du es nicht zur Laufzeit haben willst,
musst du in JavaScript anfangen und musst halt dem anderen weggehen.
Ja, okay, aber da würde ja nicht prinzipiell was dagegen sprechen, oder?
dass du von TypeScript-Typen zu
JavaScript-Typen gehst. Das ist nur
das Tooling, das existiert nicht.
Aber das ist doch cool. Du hast auf jeden Fall
das gleiche. Unbedingt zu empfehlen.
Ja, unbedingt zu empfehlen.
Das ist richtig, richtig cool. Finde ich super spannend.
Könnte auch für mich nützlich sein.
Also gerade wenn du mit
Backends arbeiten musst, denen du nicht trauen kannst,
herrlich. Ja, oder
mit Inputs von Benutzern.
Ich meine, da musst du eh immer Validierung
machen, aber das
kann einem ja
in dem Sinne die Arbeit ein bisschen abnehmen.
Naja, quasi man definiert
halt, wie man gerne hätte, dass die eigene
Datenstruktur aussieht und benutzt
dann diese Information halt auch zur Validierung
dagegen. Das ist natürlich
also, ja, das ist genau eigentlich
der US-Case von Pydentic auch.
Ja, ja,
muss man das Pydentic noch genauer anschauen.
Also das hört sich zum
Zeitmehr, ich habe es heute gehört, wie wir
begonnen haben.
Und jetzt wieder. Erklär mal, Jochen,
zwischen FastAPI und Pydentic.
Ach, ja, FastAPI ist sozusagen ein ...
Ein Repeter-Face, fast.
Ja, genau.
Automatisierung bereitstellen.
Ja, und Pydentic.
Pydentic ist eine Bibliothek, die benutzt wird von FastAPI
und die halt sozusagen ermöglicht,
wenn man halt mit Typ-Annotationen sozusagen,
oder der Syntax, es gibt noch mehr,
weil man kann halt auch noch mehr machen
als nur die Sachen, die mit Annotationen möglich sind.
Man kann halt auch Validierungsfunktionen haben
und Upper Limits und
Lower Limits und weiß ich nicht, und ganz viel kompliziertes
Zeugs halt auch mit dazu schreiben. Das geht
mit den Typ-Annotationen natürlich nicht,
aber wenn man einfach nur die Typ-Annotationen hinschreibt,
dann passiert das halt auch, dass dann
sozusagen man
einen JSON nehmen kann und man hat halt
eine Objektstruktur definiert mit den Typen
und dann sagt man halt, hier ist das JSON,
parse das mal
und validiere das mal.
Und wenn es nicht, dann kriegst du 422 zurück, weil da fehlt irgendwas.
Wenn es nicht okay ist,
kriegt man halt schöne Fehlermeldungen auch zurück, wo dann
genau gesagt hat, so an der Stelle
hast du gesagt, das soll ein
Number sein, aber da ist eigentlich, da ist ein
String oder das ist halt irgendwie,
das passt sonst wie nicht, das soll eine Liste sein, aber das
ist halt nicht, ja, und
das ist natürlich nett. Okay, also es ist,
also es ist quasi
das, woraus FastAPI
gebaut wird. FastAPI ist
identisch via
HTTP. Ja,
plus es sind noch so ein paar Sachen
zusätzlich dabei. Starlet ist halt
irgendwie sozusagen das alles, was HTTP
angeht oder so, macht da drunter
die Bibliothek von Tom Christie.
Also Fast API ist schon so ein bisschen,
ist halt so irgendwie
drei sehr coole oder drei, vier
sehr coole Open-Source-Bibliotheken in einem French-Code
irgendwie quasi. Noch so Routing,
das hat man halt irgendwie von Flask
früher kannte, als Dekorator.
Ja, Flask war auch sehr alt.
Ja, genau, das ist natürlich auch sehr alt.
Also Stefan, wenn du Fast API schon kennst,
dann weißt du auch, wie Pedantic funktioniert.
Nur halt innerhalb.
Genau.
Also wie gesagt, ich habe den Namen in ein Architektur-Diagramm
geschrieben. Also das ist meine Erfahrung damit.
Reicht anscheinend.
Es ist schon mehr damit gemacht als viele.
Genau.
Ja.
Genau. Also ja, das ist
auf jeden Fall auch so noch ein ganz interessanter
Ding. Weil ich meine, das ist ja tatsächlich
so, wie viele Leute das benutzen. Viele Leute benutzen
einen TypeDict und denken, das würde passieren, dass es
validiert wird. Aber es passiert halt nicht.
Ja. Genau.
Ja, ansonsten, ich weiß es nicht. Haben wir noch
irgendwas Großes vergessen oder so, aber ich glaube
ansonsten
ich habe hier fast nichts mehr, was ich noch irgendwie
unbedingt gerne wissen wollte.
Ja, nach anderthalb
Stunden alles über
Typsysteme und Typen
gesagt. Das ging ja relativ
schnell jetzt.
Für meinen Typen hat der immer noch keine Erklärung gefunden,
aber sonst.
So Typen wie
dich, Dominik, ist schwer zu beschreiben.
Das ist so.
No space enough.
Ja, wirklich, ich finde es schön.
Stefan, hast du noch etwas, was du unbedingt loswerden wolltest?
Ich glaube, ich habe jetzt noch ein anschauliches Beispiel gefunden
zu Co-Varianz und Kontra-Varianz.
Nachdem ich mir die Grafik so lange angeschaut habe.
Ich hoffe, ich kann es erklären.
Co-Varianz ist in Wirklichkeit etwas, was wir als Subtyping verstehen.
Angenommen, du hast ein Lebewesen, dann hast du ein Subtyp davon,
das ist ein Pflanzenfresser, dann hast du ein Subtyp davon, das ist eine Kuh.
Das heißt, du wirst immer konkreter und konkreter und konkreter.
Was bedeutet, wenn du irgendwo ein Lebewesen erwartest,
kannst du dort einen Pflanzenfässer reinschmeißen,
kannst aber auch Kühe reinschmeißen oder Schafe reinschmeißen
oder Veganer, von mir aus.
Und das ist Covariance.
Das heißt, du kannst etwas sehr Breites akzeptieren
und kannst etwas sehr Konkretes reinstopfen,
wenn der Subtyp da ist.
Also das heißt, ich erwarte ein Lebewesen als Type Annotation quasi.
Genau, genau, genau.
Jetzt hast du aber zum Beispiel eine andere Covariance,
Nämlich du hast jetzt Pflanze und davon abgeleitet Gras und davon abgeleitet vielleicht Heu oder so.
Und jetzt willst du eine Funktion zur Verfügung stellen, die akzeptiert Grasesser,
dann kannst du dort bei den Grasessern Kühe, aber auch Pflanzenfresser reinschmeißen.
Wenn du jetzt aber sagst, du akzeptierst jetzt Pflanzen,
also alle die Pflanzen oder Funktionen von Entitäten,
die alle Pflanzen essen können, alle Pflanzen,
dann kannst du dort keine Kühe reingeben,
weil Kühe können nur Gras essen.
Und das ist Kontravariant.
Das heißt, du hast zwar auch einen Subtypen,
du hast einen sehr breiten Typen.
Ich akzeptiere ja Pflanzenfresser.
Allerdings kannst du keine Kühe reingeben,
weil Kühe nur Gras essen dürfen.
Okay, und Inverianz ist dann ganz festgesetzt,
dass halt nur den einen speziellen Typ.
Genau, Inverianz geht in beide Richtungen.
Ja, genau. Also ich hoffe,
dass das nochmal veranschaulicht.
Ich glaube, wir gucken uns lieber dein Bild nochmal an.
Ich hoffe, das Bild ist so anschaulich
für die Leute, die rausgestiegen sind.
Ja, aber
wir werden sicherlich ganz viele E-Mails
kriegen und das in den nächsten vier Folgen alles nochmal
genau erklären.
Ja, okay, wenn da eine Erklärung dabei ist.
Hallo bei peistenpodcast.de.
Wir haben aber noch gar nicht ganz fertig,
weil wir möchten ja noch unseren Pick der Woche, glaube ich, auswählen.
Ich fange mal an.
Stefan, weißt du denn, was ein Pick ist?
Ja, also müssen wir jetzt irgendeinen Link raussuchen,
den er total grandios findet.
Ja, genau.
Irgendwas Schönes zeigen.
Ja, meistens nennen wir Python-Module, aber das ...
Ich nehme tatsächlich, ja, auch nicht immer.
Ich nehme tatsächlich diesmal eins von
Simon Willison und zwar das LLM. Ich glaube, das haben wir
bei einer der Machine Learning Folgen
in Shownotes irgendwo
gehabt, aber es ist tatsächlich
bei mir ist vermehrt in Benutzung
im Monkey Patch schon immer das Default, aber sonst
ist es sehr, sehr schön, weil du halt
ganz viele Templates und Chains von
Templates direkt benutzen kannst in deiner
Kommandozeile, um halt mit den verschiedenen
Modellen zu sprechen direkt, die
du da haben willst.
Und es ist toll, wenn man
harte Instruktionen gibt, dann so die
Standard-Persönlichkeit des
antwortenden LLMs irgendwie
so ein bisschen gerade zu rücken
auf das, was man selber gerne als Antwort hätte.
Such irgendwie die Leute gut aus,
mit denen du sprichst, das wollte ich damit sagen.
Und dann leitest du uns ein, Dominik.
Weiterhin viel Spaß
bei den nächsten Pics, wollte ich noch sagen.
Ja.
Ja, was hast du denn gepickt, Jochen?
Was wollte ich? Ah, genau. Ich dachte mir
so, naja, vielleicht auch ein Buch mal.
Und zwar eins, das ich nicht gelesen
habe. Aber wo man
das alles nachlesen kann, kann man auch
die Antworten, wenn man
drauf gekommen ist, wie das sein muss, an uns schicken.
Und zwar The Little
Typer ist ein Buch, das
ich habe es versucht zu lesen. Es ist irgendwie, ich habe
dann zwischendurch aufgegeben.
Das muss ich sagen, wie Experiment mit Types
entbeißen.
Aber da steht
da steht das, glaube ich, alles ganz genau drin, wenn man das
wissen will. Und ah gut, vielleicht
nochmal was Praktisches, weil
ja,
das ist ja doch nicht irgendwie
was für alle wahrscheinlich.
Doku ist ganz nett, auch
nicht Python, sondern Go.
Geschichte,
Heroku hatte ja in letzter Zeit so ein bisschen Probleme
und
ist nicht mehr so richtig
irgendwie der Platz, wo man vielleicht so mal so,
also früher hat man das ja, wenn man irgendwas
mal eben deployen wollte,
hat man das oft dann bei Heroku oder so
getan, weil das halt sehr einfach war,
aber das geht
irgendwie nicht mehr.
Wo würdest du das jetzt machen, Jochen?
Also meine
Lösung dafür ist ja, dass ich das halt einfach,
ich habe da so meine Standard
Ansible-Dinger.
Ja, okay, gut. Also du
bist vom, dir ist Heroku
zu kompliziert geworden und deshalb hast du
jetzt deine eigene Hosting-Lösung gebaut.
Ja, leider, ja.
Ist natürlich keine Option, die jetzt viele
dazu hören. Genau, also das kann ich auch
nicht unbedingt empfehlen, das ist
unerwartet kompliziert,
aber bei mir geht's jetzt daher, hab ich das Problem
nicht mehr. Und ich mach ja auch
kein Docker oder so, sondern ich deploy da
dann direkt irgendwie.
Knallhart, bare metal.
Ja, genau. Und
bei
Doku hat man dann halt irgendwie sowas,
wo man dann so ähnlich wie mit Heroku einfach
man hat halt so ein POC-File und dann
kann man das einfach direkt und da auch
also wenn man einen Docker-Container bauen kann, kann man
Docker-Container dahin deployen und die laufen
dann unter Subdomänen direkt mit
HTTPS und so. Arbeitet das sogar mit Heroku?
Also Doku?
Nee, nee, das ist also, aber du musst
halt das Doku auf einem
von irgendwo auf einem
weiß ich nicht, auf einer virtuellen Maschine
irgendeinem Dings halt deployed haben.
Self-hosted Heroku. Genau, self-hosted
Heroku quasi.
Und genau, das ist glaube ich
manchmal ganz hilfreich, sowas zu haben.
Ah. Ja.
Okay, dann schließe ich mich da
direkt mal an, weil in dem Fall habe ich drei
Picks.
Der erste ist Vercel.
Das ist
wie Heroku, nur cooler.
Der zweite
wäre Fly.io. Das ist
quasi
Docker-Sachen auf Hosted-Infrastruktur
überall hin
machen und die machen krasses technisches Zeugs damit.
Also du schickst dir den Docker-Container,
aber die zerlegen den und
bauen sich da eigene
Sachen draus. Das ist auch technologisch
sehr interessant.
Das war jetzt aber der opportunistische Pick,
nur um da die
Alternativen zu Heroku
und Self-Hosted
einmal gesagt zu haben.
Jetzt sind wir ganz tief in den Pop-Bretchen.
Genau, mein eigentlicher Pick ist was ganz
anderes und zwar
das ZDF hat ja
eine Mediathek und auf dieser Mediathek
kann man Sachen ansehen und wenn man ein paar Sachen
angesehen hat, dann versucht das ZDF da
Recommendations draus
zu machen. Wow, das ist das
erste Mal seit Ewigkeiten,
dass ich von Fernsehen etwas höre.
Du meinst das ZDF, meinst du das tatsächliche
Fernsehen? Ja.
So analog.
Das zweite deutsche Fernsehen, meine ich.
Und die,
also nur die Mediathek.
Und weil das
ZDF ja in öffentlich-rechtlicher Hand
ist, haben die sich gesagt, eigentlich müssen wir das ja
den Leuten zurückgeben. Und das haben sie tatsächlich gemacht.
Die haben ihr Recommendation-System
auf GitHub gepackt.
Und man kann das jetzt ansehen.
GitHub ZDF minus Open Source
gibt es auch jetzt schon
ein Repository drunter, das heißt
Recommendations PA Base.
Und da sind,
da ist das Recommendations System
vom ZDF drin. Und fand ich einfach spannend,
das mal anzusehen.
Weil da ja doch auch einiges
an Arbeit drinsteckt. Und weil es da auch
viele Firmen gibt, die sowas gerne hätten.
Genau, das war's von mir. Stefan, hast du noch was für uns dabei?
Ich habe noch etwas herausgefunden. Das ist schon ein älterer Artikel von Bob Nystrom aus dem Jahre 2015. Heißt What Color is Your Function? Und Bob Nystrom ist einer der Sprachdesigner, der jetzt aktuell an Dart arbeitet.
Und das ist sehr spannend, weil er versucht zu erklären, anhand von Farben, wie sich normale Funktionen und asynchrone Funktionen im Sprachdesign unterscheiden. Also rein aus der Perspektive von, welche Herausforderungen kriegst du als Sprachdesigner, wenn du so ein Asian-Greed-Konstrukt gestalten musst.
Und wie gesagt, der ist schon ewig alt, aber er ist
vor kurzem wieder bei uns in der
Firma aufgepuppt. Kann ich sehr empfehlen.
Versuch das so zu erklären,
dass du das, die
Ergebnisse
oder die Erkenntnisse in Python
genauso anwenden kannst.
Und finde ich immer wieder sehr
interessant. Gehe sehr oft
wieder drauf zu.
Für die Programmiersprachen Interessierten.
Ja, sehr cool.
Also quasi diese Analogie
oder diese Metapher habe ich auch schon häufig gehört.
Ich wusste aber nicht, wo sie herkommt.
Und ja, das muss ich auch irgendwo mal lesen.
Nee, da gibt es tatsächlich noch was Älteres.
What Color Are Your Bits?
Das ist von 2004.
Da geht es um die Herkunft von Bits.
Also ob deine Bits urheberrechtlich geschützt sind oder nicht.
Okay.
Was du damit machen kannst, um die Farbe,
damit sie die Farbe ändern.
Aber das ist, ja.
Also ich musste da auch zuerst dran denken.
Also es scheint eine gute Metapher zu sein.
Wir können das ja beides verlinken.
Ja, sehr gerne.
Ja. Ja, vielen Dank.
Ich würde sagen, herzlichen Dank, dass ihr heute
alle wieder da wart. Herzlichen Dank, Stefan.
Herzlichen Dank, Johannes. Ja, danke für die Einladung.
Freut mich sehr. Ja, sehr gern.
Dann, ja, bleibt uns gewogen.
Schaltet uns wieder ein. Hört uns, wo immer ihr gerade seid.
Morgens, mittags, nachts, abends.
Zum Schlafen, zum Einschlafen.
Einen wunderschönen Tag.
Bis bald.
Tschüss. Ciao. Tschüss.