Transcript: Typescript und Typisierung
Full episode transcript. Timestamps refer to the audio playback.
Ja, hallo liebe Hörerinnen und Hörer, willkommen beim Python-Podcast, heute Episode 54.
Wir reden heute über Types, Type-Ins und Type-Script.
Hallo.
Hallo, 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
stand irgendwie dabei, so 400 Bugfixes
und so, also ja, 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
Okay, sehr gut. Also 3.12.1
ist draufgekommen und jetzt in meinem
Systeminterpreter zum Beispiel, ist der auf 3.12.
Hervorragend.
Ja, aber ich glaube,
da war nichts, also außer Bugs
ist da nichts irgendwie passiert.
Mein Hauptproblem im Moment ist halt PyTorch oder so was,
wo es auch im Dezember einen Release gab,
dass es jetzt endlich mit 3.11 funktioniert.
Ah, ja, ja.
Ja, aber...
Ja, ansonsten genau neue Releases.
Es gab einen neuen
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 Dustin-Time-Compiler
und verwendet jetzt einen ähnlichen Ansatz für den Parser,
wie Python halt auch.
Python ist ja jetzt mit irgendwie 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 Parser-Generator, auf einen 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.
Das wäre meine News gewesen, Jochen.
Ach so, 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's auch angeblich eine wundervolle Diskussion
auf Reddit zu...
Ja, also
es gibt einmal die, ich kann empfehlen,
es gibt Core-PY, das ist so ein Podcast,
wo zwei der Core-Entwickler
irgendwie drüber reden. Da gibt es eine Episode
zum Just-In-Time-Compiler.
Wer sind dabei?
Shannon und Sean? Oder wie ist das?
Ne, das sind
Pablo Galindo Salgado,
der Release-Manager
auch für 3.13
und
Luca Schlanger.
Ah ja. Genau.
Die haben da einmal drüber geredet und
daher weiß ich auch, dass das
basiert hauptsächlich,
also warum man das jetzt nochmal in Angriff nimmt,
auf Geschichten, die in Lua
passiert sind. Da gab es jetzt auch irgendwelche
– ich habe jetzt wieder die
Details vergessen – aber so Papers,
die sehr, sehr interessant aussahen und
die halt vermuten lassen, dass man es relativ leicht
irgendwie auch für Python verwenden kann.
Und ja, das ist halt ein
InPython in Ruby.
Da werden überall diese Dinger jetzt gerade eingebaut.
Und hier der
wegen dem PyPy auch hier war schon
der meinte auch so,
oh, er muss jetzt mal sein
Commit-Bit
wieder hochfahren.
Wieder quasi aus...
Ja, es gab ja immer, dass 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.
Ah, cool. Das wird auf jeden Fall spannend.
Schnelles Python.
Ja, genau.
Es gab dann ein Issue zu, wo dann einer
von Netflix oder so in relativ freundlichem Ton zun schrieb irgendwie so ja also das macht bei uns sehr viel Arbeit und irgendwie das war jetzt alles irgendwie nicht so g und ich hab 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
und
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.
Und das ging alles nicht.
Und das 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 Pydentic-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 so was wie if Pydentic V2.
Bäh.
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 es halt aus.
Dieses Update war nicht
wirklich reibungslos,
sondern da haben viele Leute irgendwie eine Menge
Schweiß gelassen.
Also nicht nur ich.
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 kann man 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.
Ich glaube, das muss der Stefan mal so ein bisschen erzählen.
Ist das jetzt mein Intro oder was?
Ja, das war die Software-Überleitung.
Ja, genau.
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 Bibliothekennamen oder irgendein neues JavaScript-Framework, das irgendeinen abstrusen Namen hat, mit dem sich 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 fast API,
weil tatsächlich, das ist spannend, ich bin
jetzt mit, 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 Longchain, 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 fast immer noch langen, langen
Gesprächen mit unseren Python-Devs
in unser Architektur-Diagramm eingetragen
habe für irgendeinen Server, den wir
gemacht haben. Genau, also das war eben das
Erste, wo ich mir gedacht habe, so, da kenne ich mich
jetzt aus, bei FastAPI, da kann ich mitreden.
Funktioniert
Multithreaded, aber
nicht Async. Ist das richtig?
Nee, 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
LibUV, also das ist halt
eine Adaption von LinnUV, 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.
Cool. Das war die
zweite, war dann, dass ich
versucht habe,
über Pyro 3
eine Brücke zwischen
zwischen Async Rust und Async Python
einmal zu schreiben. Das war spannend.
Das war richtig cool. Also was mich da
beeindruckt hat, und mit dem habe ich
nicht gerechnet, ist, dass
das Foreign-Francish-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.
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.
PS3, 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 ergeben 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, 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, stimmt nicht, ich habe es zwischen dem ersten und dem zweiten Lockdown tatsächlich das meiste geschrieben.
Das ist auch tatsächlich ein schickes Buch. Das sieht auch super aus, also von außen.
Wir wissen das, weil wir dieses Buch auch alle haben.
Ja, tatsächlich.
Zwar als Python-Entwickler, was natürlich auch schon was heißt.
Alles ohne die Kamera gehalten. 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, das sauber zu lesen ist
und verzetteln sie 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 bzw. Schuhe designt hat.
und der mich gefragt hat, hey, so,
E-Mail geschrieben, hey, der war aber das 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.
Er hat tatsächlich dann
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
oder irgendwas Cooles draus zu machen,
da kriege ich heute noch Gänsehaut.
Das ist ja für mich so,
ich weiß, es ist mein Buch,
aber es ist nicht nur mein Buch.
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.
und es hat eine Freude für mich gemacht,
wie er ein Interview
für sein Startup gemacht hat,
auf einmal sehe ich, hey, da ist mein Buch im Hintergrund,
herrlich, also macht
Riesenspaß.
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
zu diesen 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 wenn du sie so reil probierst oder mal kurz ein Inhaltsverzeichnis unterschreibst wie du dir ein zweites Buch vorstellen kannst Und gerade habe ich 100 weitere Eintr gehabt innerhalb von drei Stunden
Also ich bin mir am Nachmittag hingesetzt und habe gedacht,
ups, wow, da ist ein Buch da.
Und 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 Typ-System funktioniert,
lernst du im TypeScript-Book alle Dinge,
die schief gehen können.
Dinge, die, wenn du wirklich Programme damit schreibst,
wo du merkst, hey, 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 entgegenzukommen.
Im Moment, ich dachte, so Typen hast du damit,
nichts mehr schiefgehen kann. Und 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.
Ich bin eine super Überleitung
tatsächlich auf das Thema, was wir heute machen wollen, oder?
Ja.
Ganz herzlichen Dank, dass du heute da bist, Stefan.
Das freut uns sehr.
In Paisen haben wir 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.
Weil es halt so ein großes Thema ist.
Es gibt auch eine ganz große Anti-Fan-Gemeinde
in Paisen für Types.
irgendwie. Ja, 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.
Ja, das ist ein gefährliches Spiel.
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,
als das halt wirklich Nutzen hatte.
Ich habe tatsächlich in den Projekten bei mir jetzt Enforced MyPy
Pre-Commit-Hook, das ist auch
schon, da gehe ich ziemlich vielen Leuten auf die Nerven.
Aber...
Da kannst du überall Objekt hinschreiben, oder? Das zählt doch auch.
Ja, okay. Also da sind die
meisten nicht draufgekommen.
Oh, da habe ich jetzt ein Geheimnis verraten.
Hups.
Annie oder Anna.
Also ich bin
beeindruckt von der 100% Test Courage.
Also ich bin
leider Gottes der faulste Tester.
Dieseits der Donau.
Also das ist...
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, 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 und da,
also das ist, glaube ich,
also auch schärfenhaupt, das ist, glaube ich,
meine größte Schwäche.
Ja, 100% Courage ist auch schon sehr
ich finde es beeindruckend, wirklich.
Ja, das haben wir in dem Projekt, in dem ich bin, auch 100%
Branch Coverage sogar.
Und TypeScript.
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
typisierte 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 sie auf
und keiner beschwert sie und es funktioniert halt einfach.
Oder du kannst verschiedene Typen mischen.
Du kannst ein String mit einer Zahl kombinieren.
Nein, das geht in Pandas.
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.
Ja, dynamic versus static, 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
ist eine sehr
schwache Bezeichnung
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. Also 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 bisschen andere
Herangehensweise ans
Programmieren
voraussetzt. Du machst dir
einfach mehr Gedanken über
die mögliche Wertemenge
einer Variable, bevor
du einen Wert 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 doch 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 dich fragst, was war denn diese Variable X nochmal? Also was habe ich mir da eigentlich gedacht? Und dann hast du irgendeine fette Wurst an Code und musst herauslesen, was du eigentlich damit machst.
und also das ist was, was
mich immer komplett
verwirrt hat, wie
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
weil, also gut österreichisch, sorry, Graut und Ruben einfach zusammenschmeißen
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 Funktionen und je mehr Bibliotheken, die du hast. Wie gesagt, ich wäre schon gesagt, ich bin jetzt in diesem Long-Gen und LLM-Wahnsinn irgendwie gefangen. Da hast du sehr, sehr komplexe Objekte, die du 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
und haben 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...
Das ist ein gutes Argument.
Die IDE, ja, okay.
Das ist eigentlich alles gesagt.
Ästhetisch ist immer das Argument.
IDE kann damit was anfangen oder so,
aber wenn man das jetzt anguckt,
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 peinlich.
Aber ich muss,
diesen Argument höre ich auch häufig, wenn man jetzt so bei den
alten, zum Beispiel
übernächste Woche wieder, oder
Das nächste, ich weiß nicht.
Das nächste, ja.
Auch hier aufs Python-User.
Und das nächste, nächste Mittwoch.
Das nächste Woche, ja.
Ja, ja.
Genau, gehen.
Da gibt es dann die alteingesessenen,
die sagen auch immer so, ah.
Immer nur AXE-Quarks, Sternchen, Sternchen.
Nein, das nicht, aber.
Ja, ja, aber das ist schon so ein Punkt,
mit dem viele Probleme haben, ja.
Ich kenne genug Python,
dass ich den Witz mit AXE-Quarks verstanden habe.
Dann gehörst du schon zu den Oberen.
Ja, also gut.
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
Programmiersprache vertragen? Und Rust sagt ja.
Also, her damit.
Aber dafür ist mir halt in Rust
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
und
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
aber 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 es 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.
Ja. Ist ein Typ.
Ja, ob man den jetzt braucht oder nicht.
Auf der anderen Seite
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 Arc1.
Das dritte ist ein Object, das heißt Arc2.
Und so geht es weiter bis Arc30.
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
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ß
und
Du hast mich gerade an etwas Wunderbares erinnert.
Ich bin ja
in einer Java-Welt groß geworden.
und habe gelitten.
Ich auch.
Ich komme aus der Nähe von Linz
und direkt 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 Try
to Sneak in Some Generic or Parameterize
Type Pattern Matching Stuff Anywhere Visitor.
Und das ist
fantastisch. Also bei uns
in der Firma, ohne Java-Developer,
bei uns in der Firma, ohne 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.
Ja, das ist ein Dankzeug.
Und um das geht es eigentlich Und gerade in TypeScript also gerade auch in meinem Buch gibt es ein paar Beispiele drinnen da kommen sie schon richtig richtig vorausgekommen Da gibt es irrsinnig m Werkzeuge wie String Literal Types oder Tappel Variadic 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
Currying versuchen, auf drei
sehr, sehr komplexe Orten umzusetzen und 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 herauszufinden.
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 das 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 müssen wir uns ja das Akkord nicht verändern und einfach Type-Driven-Development, eine neue Instanz starten.
mir.
Und
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.
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 in Rust drin,
ich habe das jetzt schon erwähnt, und sorry, das ist der
klassische Rust-Nutzer, nicht ständig
sagen, 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 mehr schaust,
hey, was, wo
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 vor Hause 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,
auseinander ü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 es ist,
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.
Ich finde es 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 mal 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 Software schreibt dann kann es halt sein dass es sehr viel bringt auch irgendwie m viele H 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 ...
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 Reployment-Release-Zyklus so
alle sechs Monate.
Ja, genau, in den sechs Monaten passiert halt auch
nichts, aber ja, 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.
Und 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
als, 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 Unit-Tests.
Und da sind wir auch bei einem Ding, wo die Sachen
so ein bisschen ähnlich sind. Also ich dachte auch lange Zeit
irgendwie,
Unit-Tests sind was ganz anderes und
Typisierung
ist ein anderes Ende
von einem Spektrum und ich bin eher so Team-Test.
Aber inzwischen denke ich so, naja, das ist schon
relativ ähnlich auch. Ich meine, auch Unit-Testing
ist halt so eine Sache, die man sich erst irgendwie
erschließen muss und für manche Leute macht
es einfach, wenn man halt irgendwie so
in einem Jupyter-Notebook Sachen macht,
Und 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 im Team entwickelt, dann klar hat man Tests und eine CI-Pipeline und weiß ich nicht, diesen ganzen Kram halt.
Ja, das Stichwort da ist doch Programming by Contract, oder? Und das ist halt eine Möglichkeit, so einen Contract zu schreiben. Aber ich bin da in so einem Zwiespalt. Einerseits bin ich total genervt von solchen Typsystemen, die dann sehr präzise sind. 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
drankommst 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 Typsystem reingießen, wenn du das möchtest.
Ja, das ist quasi keine Sprache.
auch tatsächlich irgendwelche Bytes liegen,
die von einer CPU ausgelesen werden.
Also das,
wenn dir das
Typsystem das erlaubt, dass du dort
irgendwas zwischen minus 1 und plus 1 zum Beispiel
definierst oder mein Gott,
eine ganze Zeit zwischen 25, was auch immer,
dann schiebst du die
Validierungen nur an eine andere Stelle.
Ja gut, aber das
macht man mit dem Typsystem generell, oder?
Also ich meine, sobald der TypeScript-Compiler durch ist,
ist er weg. Das ist
sehr richtig, genau. Das ist sehr richtig.
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 ja auch viele Leute.
Ja, das ist ganz, 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. Das ignoriert
die Annotationen einfach. Ich lasse dann
MyPyte rü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 denkt man sich, warum hat man
sich ü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 Tideshaper
Extension richtig konfiguriert hast.
Ja, und ob dann auch
MyPy die Stubs halt
lesen kann, die halt da notwendig sind
oder halt auch nicht.
Aber viele IDEs behandelt es doch auch selber schon.
Ja, ja, genau. Da gibt es ja auch
dann, ich weiß gar nicht jetzt,
bei VS Code
dann normalerweise verwendet wird.
MyPy 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 MyPy,
klar, und es gibt halt
noch PyWrite und
der Language Server für Python.
Kann es sein, dass der selber
von Microsoft in TypeScript
geschrieben ist? Ich glaube schon.
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 macht,
sondern du brauchst eh nur einen extra Typchecker
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 Typsystem, cool, also wie werden
Typen geschrieben, definiert, wie
sind sie im Zusammenhang. Es ist auch ein
Typchecker dabei,
also der TypeScript-Compiler
TSC macht in erster Linie mal
Typechecking, 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 ein 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 validen 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 noch 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 das läuft im Hintergrund schon der TypeScript-Compiler
und checkt meinen JavaScript-Call
und versucht zu inferieren und zu verstehen,
was ich schon geschrieben habe, ohne
eine 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.
Da kann Python sich, glaube ich,
auch noch eine Scheibe abschneiden.
Da gibt es noch so ein paar Löcher.
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,
du brauchst nicht mehr die Typernotation schreiben,
aber die Idee hat irgendeinen
Typechecker schon per Default drinnen.
Wahrscheinlich schreiben sie ihn selbst, weil
Chatprints schreiben sie irgendwie selbst.
Haben sie.
Dann werde ich schon.
Der von Jetbrains ist aber der ist super gut Das ist einer der Gr warum man PyCharm verwendet weil die halt da die beste Typ haben Man merkt schon dass es unter Java ist
Aber das können sie.
Das sind sie richtig, richtig gut.
Schon wieder Rust.
Für Rust haben sie auch einen eigenen geschrieben.
Die ganze Welt verwendet Rust Analyzer.
Außer du nimmst Rust Rover von JetBrains,
dann ist da ein eigener drinnen.
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.
halt dann, und das ist bei Python
nicht so, weil die
statischen Type-Checker vor allen Dingen von den großen
Gebäuden gebaut werden, halt nicht
MyPy, Dropbox, ich weiß nicht, ob die
immer noch da so hauptsächlich dran sind, aber dann gibt's noch
einen von Google, es gibt noch Pyright,
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 MyPy 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 dich auch noch darauf einigen,
welches Subset des Typsystems du jetzt
verwendest.
Ja, genau.
Da kann ja gar nichts schief gehen.
Ja,
das ist ja keine Tester.
Das TypeScript-Own-Management
ist ja stark in der Kritik,
sehr keine Frage.
Also das ist einfach ein schwieriges Problem.
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 ja auch sagen, dass 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, Historie.
Ja, ein kleines bisschen Programmiersprachen-Historie mitgeliefert.
Ja.
Ich wollte gerade nochmal auf Java ein,
wo wir das gerade hatten.
Das ist leider schon ein bisschen drüber,
aber davon wieder weg.
Da hatte ich nämlich auch noch so eine schöne,
da habe ich letztens was 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
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 such grad, 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
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 Laufzeituobjekte 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 Du hast 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 Innamen sein kann, weiß ich sowieso nicht.
Ich habe das gesehen bei unseren Kollegen
und das ist kein Innamen.
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 Fluglevel
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,
jetzt kriegen sie es halt mal gesagt.
Ja.
Im IFCenis gibt es auch Generics
in Python.
Ja, genau.
Wovon geht das?
Ja, also das ist ja,
also 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
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 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. Dann zeige ich hier so,
jetzt kannst du da, du kannst noch eine Liste auch reintun
oder 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 List von Object.
Das heißt, alles, was du da reintun 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,
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?
Ist cool.
Super, genau das.
Gott, Experte.
Ich sage ja nicht, ich bin nie Experte, ich bin einfach nur
aufgehoben und schreibe den ganzen Mist auf.
Ja gut, aber das macht dich zum Experten.
Aber nein, das beschreibst du ziemlich gut.
Also du kannst mit Typ-Parametern
dir die Entscheidung auf den tatsächlichen Typen
für später aufheben.
Das ist das, was dort passiert.
Und eben so sagst du,
dann wird das halt eine Array-List von String
oder eine Array-List von Integer
und du substituierst diesen Typ-Parameter
mit einem konkreten Typen
und kriegst nachher auch solche konkreten Typen
wieder retour.
In manchen 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 in Python? Protokolle?
Doch, das ist in Python, das ist halt
drei Achtung Gründer 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
Protocols
geht das auch.
Ja, genau, und dann...
Habt ihr das schon mal irgendwo gesehen Ja ich verwende das Bevor es jetzt Ja ja Also ich finde das eine gro 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 genau
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
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 false positive heißt,
eine Annotation hat gesagt, nee,
du kommst hier nicht rein, das ist irgendwie,
du bist nicht der richtige Typ.
Dein Typ ist hier nicht gefragt.
Sozusagen, obwohl es
eigentlich doch okay gewesen wäre.
Und also offenbar
es ist 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
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 voll snaggert.
Ja, genau.
Und ja,
der hat das
also 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
und aber
Das Problem ist, wenn es zu Nominal arbeitet,
dass du auf dem Schlag eine Hierarchie aufbaust,
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ückgabewerte, Propertytypen etc.
Und ich sage mal, ein 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 wie 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 arbitrer
geschaffenen Hierarchiekonstrukt sagen, das passt oder passt nicht.
und ich glaube,
es kann man gut vorstellen, dass das Python auch
stark hilft.
Definitiv.
Ja, das ist jetzt also seitdem,
ich meine, ist das auch, glaube ich,
in Go ist das ja auch so,
die 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.
Ja, und
ich verwende das tatsächlich.
Ich glaube auch, 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,
du hast ganz recht, Johannes.
Ich glaube, es war Johannes.
Ja, genau, das ist das, was natürlich passiert.
Du hast Klassen und dann hast du Hierarchien davon
und dann benutzt du die und fertig.
Das ist dem Konstrukt zu schulden.
Und der Konstrukt hat 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.
Ja.
Ja, ja. 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.
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 freigiebig, der ist vielleicht
ein Integer-String 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...
die ähnlich sind, durcheinander kriegst.
Weil strukturelle Typsysteme funktionieren halt immer bis zu dem Grad,
wo 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.
Das ist, genau, das benutze ich genau für diesen Use Case,
dass man halt
oft quasi sowas
zum Beispiel Integer möchte man
einschränken von 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 NewTypeYear,
der halt eigentlich ein Int ist,
kann mir der TypeChecker sagen,
wenn ich irgendwie mal ein anderes Int da
reingesteckt habe, was ich nicht mal als Ja
irgendwo anders deklariert habe,
und kriege dann sozusagen den Effekt, dass wenn da irgendjemand
irgendwas reinsteckt, was kein Ja ist, dann
gibt es halt auch, sagt der
TypeChecker 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?
Ja.
Also gerade mit dem, also
in TypeScript kannst du das ein bisschen. Du kannst
teilweise Werte
oder geringere Wertbereiche
definieren. Also in TypeScript ist 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, nicht dieser einzige oder einzelne konkrete Wert,
die Zahl 1, der String Stefan, was auch immer, kann auch als Typ gelten.
Das heißt, du kannst einen Wert haben, wo 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.
Eins oder zwei oder drei oder vier oder fünf oder sechs.
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. Solche Strings 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.
Und dann bin ich mir sicher,
dass ich den richtigen
HTTP-Status-Code 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 das hast du gerade sehr sch erkl Vielen Dank Stefan 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 habe ich die Matura geschafft
mit dem Mathematikbuch unter dem Kopfkissen.
Funktioniert.
Ja, 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
alles gehabt, als ich versucht,
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, Kontra-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 was bedeutet das eigentlich?
Und was macht dann Bound und so?
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 Petit fragen.
Nein, es ist
irrsinnig schwierig zu erklären. Lass mich kurz
mein zweites Buch aufmachen, weil da wäre Zeichnung.
Ja.
Also bevor ich jetzt allgemeine Beschreibungen erkläre, sage ich es lieber einmal so.
In einer Kovariantenbeziehung 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 keinen Effekt drauf, kannst du weiterhin darauf zuweisen.
Der Kontravariant 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 eine 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 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 Kontrovarianz.
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 rein.
Weil das sind die Sachen, die merke ich mir selber nie genau.
Das ist was man einmal nachlesen muss.
Also in welche Richtung kann man was irgendwie doch
voneinander erben, wenn ich das richtig verstehe?
Und das allgemeiner annotieren?
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,
das bezieht sich direkt auf Python
hier und
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 das andersrum?
Das wäre dann Co-Variant oder Kontra-Variant?
Genau, und das eine ist Co-Variant und das andere ist Contra-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
annotiert, ja.
Und In-Variant 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 Schuhe
und dann schauen wir mal.
Schauen wir mal, ob das hilft.
Ja aber genau Ich dachte auch so 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?
Steht zumindest in der Types,
Pricing, Typing. Tatsächlich ist
in dem PEP 484 eine sehr schöne Erklärung
drin.
Mit Employees und Managers.
Wenn du
eine Funktion hast, die eine Liste von Employee
nimmst, 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
Angestellten aufsetzt,
die
Manager-File.
Genau.
Nee, 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. Eine Q-Variante
oder eine Contra-Variante. Und der Bound ist dann
quasi tatsächlich die,
wenn dann erst die Manager-Revival, 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
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 für verwenden, dass das damit
gemeint ist, in dem einen Namen geht. 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 Typen,
dann geht es halt nicht mehr so richtig.
Und dann macht,
also Type-Alias macht das dann halt explizit,
dass das halt sozusagen...
Und die Type war,
das hatten wir eben, TVK, TKV,
warum TKV jetzt da
im besonderen Sinne, weil ich diese kurzen Dinge,
einer der Gründe, warum ich Go nicht leiten kann, sind diese
einen Charakter
Variablen haben, aber ja.
Ja, das sind halt die Generics, oder, die wir vorhin hatten.
Stefan, du hast angesetzt.
Erklär uns, was Type war.
Also ich habe jetzt ganz kurz diesen
Pep4 aufgemacht und der ist
wunderschön.
Der ist super, oder?
Also 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 jetzt sagen,
du hast diese Typvariable in diesem Beispiel
von pep484 ist das 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 dir
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 du jetzt seist als Bound
definiert, was bedeutet, dass du
eine Länge definieren
können musst oder Länge lesen
können musst.
In Python hast du 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
Konstrant 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, da gibt es eine Size,
das hat eine gewisse L was auch immer Spannend w es ob ich dort einen String reingeben kann weil man kann ja die L von einem String definieren Ja kannst du Alles was Lend von irgendwas hat
ist size. Also ich kenne kein
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.
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 und 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
erst mal 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-Ware 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 eine List, ist eine 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
cool. 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
werden ja durch Knight umgesetzt.
Das ist bei Python
auch nicht anders. Viele Sachen sind einfach
aus Knight durch andere Sprachen entstanden.
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?
Ah, in Python musst du dich da anstrengen dafür.
Oder sind das 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 Hypes
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 das?
Warum macht man denn das? Du hast noch 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 das, 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 int adden.
Du 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
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 Compilerns
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.
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 ist
so Führungslieder.
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 mit zwei Variablen
oder mit Argumenten, die diese 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 den
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 Implementation 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.
Achso, okay. Da gibt's
zwei, also es gibt da, dann hab ich, also es gibt
mehrere Overload-Dinge,
denke ich. Genau, also das
das ist blöd, ja.
Es ist blöd, dass diese Sachen in
unterschiedlichen Sprachen unterschiedliche Dinge bedeuten.
Es ist, 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 musst du
jedes Mal einen neuen
Namen haben dafür oder einen neuen Scope
oder so. Dafür gibt es
Single Dispatch.
Ja, das hat
damit zu tun, dass
in Java überhaupt möglich ist, dass du
den gleichen Namen mehrmals vergeben kannst.
Ja, weil die beim
Kompilieren die Namen, weil die Namen weg sind
beim Kompilieren.
Nein, weil die
Funktionssignaltypen haben.
Nein, weil die Funktionssignaltypen 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 ein 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.
Äh.
Okay.
Ich hab's jetzt hier aus From Typing.
Also, so wie ich das
gesehen hab, es gibt auch ein sehr schönes Beispiel
dafür, das ist auch aus dem Fluent Python
Buch, habe 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 halt so hat beschreiben n dass man dass halt die Typ 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 ist halt,
liegt halt daran, dass man das
in dieser neuen Annotationssprache
halt nicht so gut hinschreiben 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
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
Also irgendjemand hat dann halt...
Sie haben ja oft mal lange genug was gemacht,
was sie keinen gefunden hat.
Es kann ja sein, du rufst das halt auf,
lässt es auf eine bestimmte Art
und dann läuft dein Type-Checker 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 ist 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 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 die Annotation 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.
Nee, das sieht nicht schön aus.
Ausgedehnt.
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 denn 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. Ja, also in JavaScript gibt es es, weil
also in TypeScript gibt es es,
weil du halt in JavaScript
Parameter weglassen kannst
oder
oder
Parameter an unterschiedlichen Positionen
auch was anderes heißen.
Und da der TypeScript irgendeine Methode
braucht, um das darzustellen.
Und deswegen haben wir es.
Ja, gut, wenn man Sternchen, Komma, Quark
schreibt oder sowas. Also gerade dieses
Ad-Beispiel von Johannes, das würde ich
eigentlich jetzt den TypeScript mit
Generics umsetzen.
Ja, gut.
Wenn du jetzt
die Methode Add
für Integer und die Methode Add für String 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 kann ich das dann netto überschreiben.
Ja, ja.
Ja.
Was mir noch
fehlt, wir haben schon relativ viel gesagt,
aber es ist sowas wie, ich glaube es ist eben schon
einmal gefallen, sowas wie rekursive Types oder sowas,
Wenn ich zum Beispiel einen JSON-Type definiere.
Oh, sag doch nicht sowas.
Kapitel 7.
Du bist ja noch weit entfernt von Kapitel 7.
Ja, also rekursive Types ist schon nötig.
Wenn du jetzt zum Beispiel irgendwie eine Liste definieren willst,
eine einfach verkettete Liste,
dann hast du dort nur einen Knoten
und du verweist auf den nächsten Knoten.
Aber das ist eigentlich nur ein Typsystem
für 100. Also du musst halt irgendwie
die Möglichkeit haben, dass du Typen
definieren kannst die sich selbst referenzieren k wenn n Also wie JSON oder sowas zum Beispiel tats 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 Toys haben oder so.
Ja, genau. Oder in Array von Arrays.
Ja.
Wenn du dabei bist, ne.
Ich habe mal mit jemandem
vom TypeScript-Team gesprochen, bezüglich
rekursiven Typen.
das ist meistens ein Implementierungsdatei,
wie tief der Compiler dort
gehen kann. Also was sind die,
wie ist
der Compiler entwickelt,
dass er bald genug sagen kann,
hey, da stopp ich jetzt und passe nicht mehr weiter. Also wie
geht der Compiler mit der Regression?
Typsysteme können das eigentlich.
Hat er auch in der IDE irgendwie, ich weiß nicht,
bei JSON-Type oder sowas, bis wie viel Level
tief darf der denn gucken,
ob das noch stimmt?
Genau.
Und da werden sie auch immer besser.
der Mathematik egal.
Das ist der Mathematik egal, die guckt.
Ja, genau.
Ja, das kommt dann wieder
darauf an, welche Art von Mathematik, wenn man
den konstruktiven Zweig
anhängt. Das gibt es gar nicht.
Jason, das ist so schwierig.
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.
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, 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.
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 dann tun.
Das ist ja
ein weitverbreiteter, ich glaube,
dass Deno direkt TypeScript interpretiert.
Deno hat nur einen TypeScript-Compiler
inkludiert, also kompiliert TypeScript
bevor er das JavaScript ausführt.
Also tatsächlich,
wie, also ich sage mal, im JavaScript-Bereich
reden wir eher von unterschiedlichen
Typsystemen, die existieren.
Wie Flowtype 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.
Wie Typs definiert werden.
Ja, CoffeeScript gab es früher.
Ja, CoffeeScript ist aber sogar eine eigene Programmiersprache.
Also wie Typs definiert werden,
das meinen.
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 dir 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, hey, 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 TypeScape TypeChecker eh gut genug ist, dass er schon sehr, sehr viel herausfindet, bevor du überhaupt irgendeine Annotation machen musst.
was
ein gutes Migrations-Solid ist
ist JS das ist halt ein Typ 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 Lodesh 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. Es gibt auch ein paar Reflection-Geschichten.
Also okay, dass du so rumgehst.
Das ist aber alles Mumpitz. Das möchte ich nicht einmal erwähnen, weil es einfach Schwachsinn ist. Eine Sache, die aber gut ist, zum Beispiel dieses 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 Typ,
klassischer TypeScript-Typ,
den du in deinen Methodensignaturen verwenden kannst,
den du annotieren kannst,
wo du Typechecken hast,
das funktioniert, das ist grandios gut.
Parallel dazu hast du immer noch dieses JavaScript-Konstrukt
mit der ersten 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 SORT 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,
was du normalerweise in TypeScript hast,
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 die zur Laufzeit haben willst,
musst du in JavaScript anfangen
und musst halt dem anderen weggehen.
Ja, okay, aber da steht ja nicht,
würde ja nicht prinzipiell was dagegen sprechen, oder?
Dass du von TypeScript-Typen zu JavaScript-Typen gehst.
ist nur jetzt halt das Tooling, das
existiert nicht. Ja, okay, aber das war cool.
Also du hast auf jeden Fall das Gleiche. Unbedingt zu empfehlen.
Ja, unbedingt
zu empfehlen. Also 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, also 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 Use Case von Pydentic auch.
Ja, ja.
Muss man das Pydentic noch genau 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,
erzähl mal den Unterschied zwischen FastAPI und Pydentic.
Ach ja, FastAPI ist sozusagen ein ...
Ein Repetaface fast.
Ja, genau.
Automatisierung bereitgestellt.
Und Pidentic?
Pidentic ist eine Bibliothek, die benutzt wird von FastAPI.
Und die halt sozusagen ermöglicht, wenn man halt mit Typannotationen 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, ganz viel kompliziertes Zeugs halt auch mit dazu schreiben. Das geht mit den Typannotationen natürlich nicht, aber wenn man einfach nur die Typannotationen hinschreibt, dann passiert das halt auch, dass dann sozusagen man JSON nehmen kann und man hat halt eine Objektstruktur definiert mit den Typen und dann sagt man halt, hier ist das JSON, passt das mal und validiert das mal.
Genau, und wenn es nicht, dann kriegst du 4-2-2 zurück,
weil da fehlt irgendwas.
Wenn es nicht okay ist, kriegt man halt schöne Fehlermeldungen
auch zurück, wo dann genau gesagt wird,
so an der Stelle hast du gesagt,
das soll ein Number sein, aber
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.
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
darunter, die Bibliothek von Tom Christie.
Also FastAPI 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
Flass früher kannte, als Dekorator oben
an der Route dran.
Ja genau, das ist natürlich auch sehr alt.
Also Stefan, wenn du
FastAP schon kennst, dann weißt du auch
wie Pedantic funktioniert, nur halt innerhalb.
Okay.
Also wie gesagt, ich habe den Namen in
Architektur-Diagramm geschrieben, also das ist
meine Erfahrung damit, aber
reicht anscheinend.
Ist schon mehr damit gemacht als viele andere.
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 dann 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.
Ja.
Für meinen Typen habt ihr immer noch keine Erklärung gefunden, aber sonst.
Ja.
So Typen wie dich, Dominik,
ist schwer zu beschreiben.
Das ist so.
Ja.
So, ja.
Wirklich, ich finde es schön.
Stefan, hast du noch was, 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, 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 Pflanzenfresser reinschmeißen, kannst aber auch Kühe
reinschmeißen oder Schafe reinschmeißen oder
Veganer.
Von mir aus, ne?
Und das ist Co-Varianz.
Das heißt, du kannst
etwas sehr Breites akzeptieren
und kannst was sehr Konkretes reinstopfen,
wenn der Subtyp...
Das heißt, ich erwarte ein Lebewesen als Type Annotation quasi.
Genau, genau, genau.
Jetzt hast du aber zum Beispiel
eine andere Co-Varianz,
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 stellen die akzeptiert Grasesser dann kannst du dort bei den Grasessern K aber auch Pflanzenfresser reinschmei
Wenn du jetzt aber sagst, du akzeptierst jetzt Pflanzen, also alle die Pflanzen oder Funktionen von Entitäten, die alle Pflanzen essen können, dann kannst du dort keine Kühe reingeben, weil Kühe können nur Gras essen.
Und das ist Kontrovarianz.
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.
Und Invarianz ist dann ganz festgesetzt, dass
nur den einen speziellen Typ. Genau, Invarianz ist
die beiden Richtungen.
Also ich hoffe, dass das nochmal
veranschaulicht. Ich glaube, wir gucken
lieber dein Bild nochmal an. Ich hoffe, das Bild ist so
anschaulich für die Leute,
die ausgestiegen sind.
Ja, super.
Da wir sicherlich ganz viele E-Mails kriegen und das in den
nächsten vier Folgen alles nochmal
präsentieren.
Ist ja auch okay, wenn da eine Erklärung dabei ist.
Hallo, jetzt peistenpodcast.de
Wir haben aber noch
gar nicht ganz fertig, weil wir möchten
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.
Meistens haben wir Python-Module, aber
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
das Kommandozeilentool.
Das war schon in Shownotes irgendwo gehabt, aber es ist tatsächlich
bei mir ist es 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 dir die Leute genug gut
aus, mit denen du sprichst, das wollte ich damit sagen
und deswegen
viel Spaß. Und dann lädst du uns ein, Dominik.
Weiterhin viel Spaß
bei den nächsten Picks, wollte ich noch sagen.
Ja.
Ja, was hast du denn geblickt, 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 Ja Aber da steht da steht das glaube ich alles ganz genau drin wenn man das wissen will Und vielleicht nochmal was Praktisches weil ja
das ist ja doch nicht
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 der Platz, wo man vielleicht
so mal so, wenn man, also früher hat man das ja
irgendwie mal 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.
Und das kann man auch im Selbstmodus...
Wo würdest du das jetzt machen, Jochen?
Also meine Lösung dafür ist ja, dass ich
das halt einfach, ich hab da so meine Standard
Ansible...
Ja, okay, gut. Also du
bist vom, dir ist
Heroku zu kompliziert geworden und
deshalb hast du jetzt deine eigene Hosting-Lösung
gebaut, aber das ist
natürlich keine Option, die jetzt viele
dazu haben. Genau, also das kann ich auch nicht unbedingt
empfehlen, das ist das 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 deploye dann direkt
irgendwie
Knallerhart, 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 direkt Docker-Container
dahin deployen und die laufen dann unter
Subdomain direkt mit HTTPS und so.
Arbeitet das sogar mit Heroku, also Doku?
Äh, nee, nee, das ist
also, aber du musst halt das Doku
auf einem von, von, von
irgendwo auf einem, weiß ich nicht, auf einer
virtuellen Maschine, irgendeinem
Dings halt deployed haben. Achso, ein self-hosted
Heroku. Genau, self-hosted Heroku
quasi. Genau.
und genau, das ist glaube ich manchmal ganz
hilfreich, sowas zu haben.
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.
Hier 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 Du meinst das ZDF meinst du das tats Fernsehen Ja
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 drin steckt. 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 aufgeprobt.
kann ich sehr empfehlen.
Versuch das so zu erklären, dass du
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.
Ne, 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.
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, cool. Ich würde
sagen, herzlichen Dank, dass ihr heute alle wieder da
Aber herzlichen Dank, Stefan.
Herzlichen Dank, Johannes.
Ja, danke für die Einladung.
Freut mich sehr.
Sehr gerne.
Dann, ja, bleibt uns gewogen.
Schaltet uns wieder ein.
Hört uns, wo immer ihr gerade seid.
Morgens, mittags, nachts, abends.
Tagsüber zum Schlafen, zum Einschlafen.
Einen wunderschönen Tag.
Bis bald.
Tschüss.
Ciao.
Tschüss.