Transkript: Typescript und Typisierung
Vollständiges Transkript der Episode. Zeitstempel beziehen sich auf die Audiowiedergabe.
Ja, hallo liebe Hörerinnen und Hörer.
Willkommen beim Python Podcast, heute Episode 54.
Wir reden heute über Types, Type ins und TypeScript.
Hallo Johan.
Hallo, hallo, willkommen Dominik und Hallo Johannes.
Hallo Johannes.
Hallo zusammen.
Und hallo Stefan.
Genau.
Ja, hallo Thomas.
Auch ein Gast heute, genau.
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.
Das war's ja Schönes.
Wer möchte anfangen soll ich?
Ja, fangen wir mal an.
Na gut.
Ja, also ehrlich gesagt, das letzte Mal war er nicht so lange her, daher habe ich ja nicht so viel gesammelt.
Heißen 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 da unten auch.
Ja, also noch nicht mit allen Sachen, aber mit vier Sachen.
Okay.
Also 3.12 bei 1 ist drauf gekommen und jetzt in meinem Systeminterpreter zum Beispiel ist es jetzt auf 3.12.
Hervorragend.
Tja, aber ich glaube, da war nichts, also außer Bugs ist da nichts irgendwie passiert, was ist.
Mein Hauptproblem im Moment ist halt so PyTorch oder sowas, wo es auch im Dezember einen Release gab, das letztendlich mit 3.L funktioniert.
Ah, ja, ja.
Ja, aber ansonsten genau, neue Releases gab eine neue Ruby und 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 ein paar neuen auf dem Pack-Parser umgestiegen.
Und das ist, äh, Ruby verwendet ja jetzt was ganz ähnliches.
Ist auch so ein rekursives Dings da, Parsen, ich weiß, ich habe wieder vergessen, wie das genau heißt.
So ähnlich und sie sind auch umgestiegen von Bison, also dem Parser-Generator auf den anderen.
Ich habe den schon ganz oft Loop 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, äh, Shopify, ja, genau.
Also die basieren, also es gibt ja viele, viele große Unternehmen, die halt 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 ist ja meine News gewesen, Jochen.
Achso, sorry.
Dann schieb's mal durch.
Ja, im 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.
Ein Copy-and-Patch-JIT-Compiler, was auch immer das bedeuten mag.
Da gab es auch angeblich eine tolle Diskussion auf Reddit zu.
Ja, also es gibt einmal die, ich kann nur empfehlen, es gibt Core PY, das ist ein Podcast, wo zwei der Core-Entwickler irgendwie drüber reden.
Da gibt es eine Episode zum Just-in-Time-Compiler und dann.
Wer sind dabei?
Shannon und Sean oder wie ist das?
Nee, das sind Pablo Galindo Salgado, der Release Manager auch für die, äh, für 313 und Lukas Schlanger.
Ah ja.
Genau.
Und 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 InPyte, ein Ruby, da werden überall diese Dinger jetzt gerade eingebaut.
Und hier der, ähm, der wegen dem PyPy auch hier war schon, der meinte auch so, oh, er muss jetzt mal sein Commit-Bit wieder quasi ausgehen.
Ja, dass es halt die neuen Versionen deutlich einfacher zu implementieren sind bei PyPy, wenn das drin ist, was da in CX Engines irgendwie dazukommen sollte, wollte, wenn ich das richtig verstanden hatte damals.
Ja, also jedenfalls der macht er jetzt auch mit und das wird auf jeden Fall spannend.
Schnelles Python.
Ja, genau.
Ja, ansonsten hätte ich jetzt noch das, äh, ich habe mich ja jetzt auch hier an dieser Stelle schon irgendwie ein paar Mal beschwert über irgendwie sehr holprige Updates um Python.
Entschuldigung, ja, gut.
Über Pythonic 2, über den Umstieg von Pythonic 1 auf 2.
Und jetzt haben das andere Leute auch gemacht.
Irgendwie Simon Willison hat da in letzter Zeit relativ viel zu gepostet, dass er das irgendwie ungünstig fand.
Und da habe ich dann auch so Sachen gesehen wie, es gab da eine Issue zu, wo dann einer von Netflix oder so in relativ freundlichem Ton zunächst schrieb, irgendwie so, ja, also das macht bei uns sehr viel Arbeit und irgendwie, hm, das war jetzt alles irgendwie nicht so günstig.
Und ich habe dann geguckt, der hat dann auch irgendwann beschrieben, welche Issues hier reingelaufen sind.
Und das war halt zum Beispiel auch einer von den Dingern, in die ich, 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 es war relativ furchtbar.
Also gerade wenn man ein Library ist, hat man damit halt ein großes Problem, weil man nicht kontrollieren kann, was in einer Applikation, die einen benutzt, halt irgendwie für eine Piedentic-Version ist.
Und zum Beispiel Fast API hatte man auch ein Riesenproblem gehabt.
Und wie die das dann letztendlich gemacht haben, ist, sie haben halt so einen Flag eingeführt, Pydentic V2, und machen dann jetzt gerade sowas wie if Pydentic V2 500 Zeilen eingerückt, irgendwie kompatibilitätslayer und dann else und dann sonst.
Und das machen sie an mehreren Stellen.
Das ist wirklich nicht so schrecklich.
Naja, aber so sieht es halt aus.
Also das war, dieses Update war nicht wirklich reibungslos, sondern da haben viele Leute irgendwie eine Menge Schweiß gelassen.
Also nicht durch.
Okay.
Also gut, wenn man es nicht zu sehr drin hat.
Ich habe tatsächlich auch zwischendurch noch auf 1 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.
Achso, das kann man so über TypeScript-Version unterhalten.
Apropos, ich habe gerade das neues Buch erschienen in der TypeScript-Welt.
Echt, was?
Das ist mir ganz neu.
Ja, ich glaube, das muss der Stefan mal so ein bisschen erzählen.
Ist das jetzt mein Intro oder was?
Ja, aber die Software-Überlaufleife.
Ja, genau.
Ich habe das jetzt total spannend gefunden, weil es würde ja immer so gemunkert, dass im Webbereich gibt es ja quasi alle drei Minuten irgendeinen neuen Fachbegriff oder irgendein neuen Bibliothek-Namen oder irgendein neues JavaScript-Framework, das irgendeinen abstrusen Namen hat, mit dem sie alle noch irgendwie auseinandersetzen müssen.
Und das ist jetzt das zweite Mal, dass ich so in diese Python-Ecke reinschaue and, hey, come on, this is it again, all this gleich.
The ersten Namen, denial, was FastAPI.
While tatsächlich, this is spanned, I've been just with five or five months by us in the firm with a group of Python developers on the world, Data Scientists, ganz classic, those two data scientists and this tool that was Python, the bibliotheken, with Langchain, Piper Pro for these LLM sages.
And this was my earless intro in this Python Welt, and I've been massives that I have a package manager.
There gives you an Anaconda or Pep oder sind das ganz andere?
Keine Ahnung.
Also wie gesagt, this is ja schon wieder vorbei.
But I wish that I have Fast API in language Gesprächen mit unseren Python-Devs in unser Architekturdiagramm eingetragen habe for irgendeinen Server, den we, den wir gemacht haben.
Genau.
Also das war eben das erste, wo man gedacht habe, so, da kenne ich mich jetzt aus, bei FastAPI, da kann ich mitreden.
Funktioniert Multi-Threaded, 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 man das, wie es gedacht ist, halt Stalette bzw.
UV-Corn und das ist halt sozusagen die LibUV-Implement, also das ist halt eine Adaption von LibUV, was halt auch unter der Eventual bei Node.js liegt, halt für Python.
Ja, und also ist halt quasi genauso schnell dann auch und ist Async, ja.
Cool.
Naja, das war die zweite, war dann, dass ich versucht habe, über Pio 3 eine Brücke 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-Function-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 auslesen.
Also das war, also das Kompilieren vom RAS-Code war auf jeden Fall anspruchsvoller, als wir nachher die Symbole in Python zu loaden und zu verwenden.
Das war richtig, richtig beeindruckend.
Also coole Sache möchte ich mir auf jeden Fall mehr anschauen.
Aber das ist es.
Also das sind meine Python-Kenntnisse.
Ja, weil also immer das Benutzen von Python ist halt das, was so Spaß macht, ne?
Also High-Level-Interface, ich glaube, ist sehr gut geeignet.
PyS3 auch ein cooles Beispiel irgendwas.
Da gibt es die meisten Sachen, die ich es irgendwie kann.
Ich glaube, was nicht kann, ist irgendwie Iteratoren ausspucken, richtig oder so.
Oder Generatorergebnisse.
Ja, das wird wahrscheinlich schwierig sein.
Das kann man mir kurz vorstellen.
Keine Ahnung.
Da ist dieses Typsystem von Rusty doch sehr, sehr eigen und sehr schwierig, in andere Spruchen zu integrieren.
Nehme ich mir an.
Ja, aber ich hatte ja als News ja auch quasi noch ein bisschen Werbung gemacht für dein Buch.
Vielleicht würdest du dazu noch irgendwie kurz was sagen.
Ja, danke schö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 heißt, das Zielpublikum waren Entwicklerinnen und Entwickler, die JavaScript schon kennen, sich dort auch schon wohlfühlen und jetzt merken, hey, 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 es stimmt nicht.
Ich habe es zwischen dem ersten und dem zweiten Lockdown tatsächlich das meiste geschrieben dazwischen.
Das sieht auch super aus, also von außen, wenn sie an den Schrank stellen.
Wir wissen das, weil wir dieses Buch auch alle haben.
Ja, zwar als Python-Entwickler, was natürlich auch schon was heißt.
Alles schon in die Kamera gehalten.
Das macht mich irrsinnig happy, ihr Kind sich das nicht vorstellen.
Das sind diese unglaublich schönen Momente, weil man sieht, dass das Buch tatsächlich auch an Leute kommt und Leute das verwenden.
Also die Lesebändchen gesehen, herrlich, spitze.
Und die Optik ist wirklich ganz, ganz besonders, weil das war eigentlich auch ein Grund, warum ich mit Smashing Magazine zusammenarbeiten wollte.
Die haben einfach irrsinnig viel Liebe zum Detail und versuchen wirklich sehr individuelle Bücher zu machen, haben eine wunderschöne Typografie, die sauber zu lesen ist, und verzetteln sie dann in kleinen Finesten 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 mir gefragt hat, hey so, E-Mail geschrieben, hey, der war wohl das cool, mögst du mal ein Buch design?
Und der ja passt, ich war doch, hey, wow, cool, nicht.
Ich hoffe, er kostet jetzt nicht eine Million oder so.
Er hat tatsächlich dann unser Buch, also das Buch gestaltet war versucht, da mit diesem Kapitelinlays ein bisschen das Ganze zugänglich zu machen, freundlich zu machen.
Das war uns ganz, ganz wichtig.
Und die Person, die nachher, also die Airy, die nachher das Ganze gesetzt hat und versucht hat, ein Produkt rauszumachen, 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 dort irgendwas Cooles auszumachen.
Also 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.
Also da sind so viele Leute daran beteiligt gewesen.
Es war ein irrsinnig cooler Effort von so vielen Menschen und das macht mich einfach jedes Mal wieder glücklich, wenn ich dann sehe, dass die Leute auch so sehen, sie das in die Bücherregale stellen.
Oder das Beste, was du machen kannst, hast einen Zoom-Call, stellst du in den Hintergrund und schick mal ein Foto von dem Zoom-Call.
Das ist das allerbeste.
Das macht mir die größte, größte Freude.
Und es hat ein Freund für mich gemacht, wie er ein Interview für sein Startup gemacht hat.
Auf mir sehe ich, hey, da ist mein Buch im Hintergrund.
Herrlich.
Also macht Riesenspaß.
Das ist aber das erste TypeScript-Buch.
Ich habe dann noch ein zweites TypeScript-Buch geschrieben.
Das ist erst im September rausgekommen, also ist noch ganz, ganz frisch.
Das ist das TypeScript-Cookbook, das jetzt mit O'Reilly veröffentlicht worden ist.
Das war praktisch eine Auftragsarbeit.
Also O'Reilly hat so diese Acquisition-Editors, die suchen halt nach potentiellen Autoren, schlagen 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, gewisse Stimme, eine gewisse Idee zu dem Ganzen.
Ich habe aber gedacht, naja, wenn es ist so reile, probierst du, da mir kurz ein Inhaltsverzeichnis unterschreibst, wie du dir ein zweites Buch vorstellen kannst.
Und gerade habe ich 100 weitere Einträge gehabt innerhalb von drei Stunden.
Also ich bin mir am Nachmittag hingesetzt und dacht, ups, wow, da ist ein Buch.
Und bin mit denen in einem Vertrag gegangen und habe halt dann versucht, den Nachfolger vom TypeScript im 50 Lessons Buch zu schreiben.
Wenn du in TypeScript im 50 Lessons lernst, wie das Typ-System funktioniert, lernst du im TypeScript Cookbook alle Dinge, die schief gehen können.
Dinge, die, wenn du wirklich Programme damit schreibst, wo du merkst, hey, da passt gerade was nicht, du 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 zu machen.
Im Moment,
ich dachte, so Typen hast du, damit nichts mehr schief gehen kann.
Und mit Typen, mit sicheren statischen Typen sind die Sprachnummer ganz besonders gut.
Genau, da beschreibt man nur mehr Programme, die nur mehr funktionieren und man hat keine Bugs mehr und es ist super heppig.
Ja, ja, genau.
Ja, also ich bin also eine
Ü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.
Und in Python haben wir von Typen auch schon das eine andere Mal so am Rande gehört.
Ja, wir haben diese Episode immer lange vor uns hergeschoben, weil wir uns nie ausreichend vorbereitet gefühlt haben dafür, weil das halt so ein großes Thema ist.
Es gibt auch eine ganz große Gemeindeheisen 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 nur 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.
Ja, das ist ein ganz ehrliches Spiel.
Ja, also ich verwende sie auch schon und ich habe halt einen Projektmarker 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 in dem Ding halt auch schon 100% Test Coverage.
Insofern war da einfach wahrscheinlich nicht mehr so viel zu viel.
Ja, auch das habe ich ja gemacht, um es mal gemacht zu haben, als das ist halt mit der Schule.
Ich habe tatsächlich in den Projekten bei mir jetzt Enforced MyPi Pre-Commit-Hook.
Das ist auch schon, da geht ziemlich vielen Leuten auf die Nerven.
Aber da kannst du
überall Object hinschreiben, oder?
Das zählt doch auch.
Ja, okay.
Also da sind die meisten Jungs noch nicht drauf gekommen.
Oh, da habe ich jetzt ein Geheimnis verraten.
Ups, Entschuldigung.
Any oder anyone?
Zack.
Also ich bin beeindruckt vor der 100% Test Coverage.
Also ich bin leider Gottes der faulste Tester.
Diese der Donau.
Also das ist, ich sage immer, also ich habe diesen Spruch gehabt, wie ich noch in einer Agentur gearbeitet habe, dass gesagt, ja, getestet wird beim Kunden, nicht wenn es in Production ist, es soll reichen.
Aber 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 Test-Suite schreibt.
Also Arschaufenhaupt, das ist, glaube ich, meine größte Schwäche.
100% Coverage ist auch schon sehr.
Aber ich finde es beeindruckend wirklich.
Ja, das haben wir in dem Projekt genehmigt.
Ich bin auch 100%, also 100% Branch Coverage sogar.
Und TypeScript.
Also es ist ja oft so, dass man das so ein bisschen als gegensätzliche Pole ansieht, sage 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 Typenparadebeispiel.
Das Ding ist das, 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 Wert 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 einen String und keiner regt sie auf und keiner beschwert sie und das funktioniert halt einfach.
Oder du kannst verschiedene Typen mischen, du kannst einen String mit einer Zahl kombinieren.
Nein, das geht im Putten.
Das geht nicht.
Okay, cool.
Wow, dann setzt sich schon mal einen Riesenschritt weiter in JavaScript.
Ich glaube, das ist ja das große Problem an JavaScript, oder?
Dass du solche implizite Konversionen drin hast.
Ja, also gibt es ja, das heißt halt immer weak getyped versus strong getyped, aber ich meine, ich weiß nicht, ob das irgendwie
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 sehr schwache Bezeichnungen, meiner Meinung nach.
C zum Beispiel hat ein statisches Typsystem, aber ein sehr, sehr schwaches, obst du jetzt einen Charakter hast oder ein Integer oder irgendwas anderes, es ist einfach komplett wurscht.
Also du kannst alles damit machen.
Du kannst auch hin und her wechseln und kannst auch Bitfiddling mit allem möglichen Scheiß machen.
Genau, genau, genau.
Wundervolle Bundes.
Und von dem ist das Statische eigentlich das Wichtige, weil es ein 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, du bekommst einen Typen durch Typ Inferenz, das mache ich sehr, sehr gerne, weil ich sage, okay, diese Variable x ist 3 und dann weißt du, dass das ein Numbo oder Integer oder was auch immer ist.
Das geht natürlich auch.
Das machen auch moderne Programmiersprachen sehr, sehr, sehr gerne.
Grundlegen, dass du halt mit wenig Annotation machen kannst.
Nichtsdestotrotz definierst du Verträge zwischen Bausteinen deines Codes, zwischen den Functions, zwischen Methoden in deinen Klassen, etc., in denen du sagst, du erwartest aber jetzt diesen Wertebereich und nichts anderes und du lässt auch nichts anderes zu.
Und TypeScript ist meiner Meinung nach da sehr, sehr spannend, weil TypeScript hat 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 a komplett neue Programmiersprache to definieren oder zu entwickeln, sondern auf Basis einer Regelwerk zu finden, damit all beteiligten Programmierinnen und Programmierer irgendwas to diskutieren anders, was da eigentlich for sich geht.
Nichts ist schlimmer when you a half year after that program geschrieben hast, wieder anders, hey, was war denn diese Variable X?
Also, what habe ich mir da eigentlich gedacht?
And then hast du irgendwo eine fette Wurst an Code and musst rauslesen, was du eigentlich damit machst.
Also das ist was, was mich immer komplett verwirrt hat, wie, also ich habe dann irgendein funktionales Programmierparadigma mal ausprobiert, viel mit asynchronen Promises gearbeitet in Node, irgendwelche dynamischen Objekte gehabt, wo ich ständig neue Keys hinzugefügt habe und wieder entfernt habe.
Und das war kurz anders.
And drei Monate später habe ich nicht mehr gewusst, was ich da mache, weil ich das Programm heute lese, ich kenne mich nicht aus und ich würde es auch heute nicht mehr so machen.
Einfach weil, also gut Österreich is, sorry, Kraut und Röben einfach zusammenschmeißen und hoffe, dass am Ende alles funktioniert.
And this is good for kleine Scripture.
This is good when duel geschwind was runterhackst.
Aber wenn ihr wirklich mit einem Team versucht, reale Software zu machen, dann ist das 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 dir wissen, was erwartet jetzt deine Funktion.
Und je mehr Bibliotheken, das du hast, wie gesagt, ich habe schon gesagt, ich bin jetzt in diesem Lunchen und LLM-Wahnsinn irgendwie gefangen, da hast du da sehr, sehr komplexe Objekte, die du hin und her schickst.
Woher sollst denn du wissen, oder woher soll ich wissen, der kein Python schreibt, sondern nur lest, was da jetzt eigentlich erwartet wird und was ich doch rauskriege?
Das finde ich auch.
Also das tatsächlich so als Dokumentationstyp für Python ist das 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 Riesenklar 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 gut.
Aber deshalb heute hier.
Also ich finde 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-Onnotations unterhalten und der meinte so, ja, schön, gut, und ich sehe die Vorteile und so.
Ich find's einfach irgendwie hässlich, weil irgendwie das Argument.
Die Idee, ja, okay, das ist eigentlich alles gesagt.
Ästhetik ist immer das Argument.
Idee kann damit was anfangen oder so, wenn man das jetzt anguckt, der meinte so, ja, dann hat man bei den ganzen modernen Libraries heutzutage, dann hast du da irgendwie Funktionen und da hast du pro Zeile einen Parameter, weil da kommt immer der Name des Parameters, dann kommt halt die Typ-Annotation, die einem nicht viel sagt und dann kommt nochmal ein Kommentar, der erklärt, was die Typ-Annotation einem eigentlich sagen will.
Und das dann so untereinander.
Und dann meint er so, das erinnert mich total an C-Code aus den 80ern.
Ich weiß nicht.
Ich mag das nicht.
Das ist nicht Python.
Ja.
Aber ich muss, also dieses Argument höre ich auch häufig, wenn man jetzt über den alten, also wenn man zum Beispiel übernächste Woche wieder, oder ist das nächste, ich weiß nicht.
Hier aufs Python.
Nächste Mittwoch.
Das ist nächste Woche, ja.
Genau, gehen.
Da gibt es dann die Alte eingesessenen, die sagen auch immer so, ah.
Immer nur Arx Quarks.
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 Argus Quarks verstanden habe.
Dann wirst du schon schon zu den Roboter zu erhalten.
Ja, nein, also gut, also ich bin immer sehr kritisch, wenn es darum geht, dass man die Ästhetik bewertet, weil ich schreibe sehr viel in Rust.
Rast ist eine sehr unästhetische Sprache.
Du hast quasi, hey, wie viel Syntax kann Programmiersprache vertragen?
Und Rast sagt ja, also her damit.
Aber dafür ist mir halt in Rast 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 ein paar Annotationen, die ich da habe, einfach hin.
Und irgendwas hat das da geblinkt, sorry, ich bin kurz rausgekommen.
Und verstehe zumindest, was passiert.
Und ich muss ganz ehrlich sagen, was ich rein jetzt sehe von dem, was Python-Typings umsetzt, ist das eh sehr minimalistisch.
Also da kann man sich noch weit, weit mehr vorauskommen.
Also ich finde das gar nicht einmal so hässlich.
Ja, ich finde, das Problem ist halt, dass diese Typsysteme oft zu weit getrieben werden.
Und das treibt dann Blüten.
Ja, also für alles und jedes und nochmal die letzte.
Genau, für alles geht es.
Und das muss dann alles ein benannter Typ sein und das geht dann, also ich habe hier ein Beispiel aus der Apple-Dokumentation, da gibt es einen Typen, der heißt CN Label Contact Relation, Younger Cousin, Mother, Siblings Daughter or Father, Sister's Daughter.
Ist ein Typ.
Ja, ob man den jetzt braucht oder nicht.
Auf der anderen Seite hier ein Beispiel aus der .NET-Bibliothek, die Links sind dann alle in den Shownotes.
Da gibt es eine Methode, die heißt Run.
Ihr habt 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.
Da bringen mir die Typen nichts.
Da sagen mir die Typen nicht, was das macht.
Und zwar in beide Richtungen nicht.
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 es
geht mir genauso auf den Senkel wie die alten Herren, die dann sagen, nein, Typannotationen ist ekelhaft und hässlich und wie in den 80ern.
Irgendwo in der Mitte ist dieses Maß und
du hast mich gerade an was Wunderbares erinnert, ich bin ja in einer Java-Welt groß geworden und habe
geliebt worden.
Ich auch.
Aber direkt.
Ich komme aus der Nähe von Linz und direkt auf dem anderen Bergel 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 Generalic or Parameterize Type Pattern Matching Stuff Anywhere Visitor.
Und es ist fantastisch.
Also bei uns in der Firma Java Developer diese Firma haben die Java Developer wohnen diese Whitescreen-Monitore, aber nicht, dass sie irgendwie dort mehrere Fenster nebeneinander hinkriegen, sondern ich sage immer, das ist damit die Klassennamen ohne Zeilenhumbruch darstellen können.
Und das ist natürlich, das ist Mumpitz, das ist ganz klar.
Also ich denke, man muss die ganzen Sachen immer ein bisschen pragmatischer sehen und halt auch einen richtigen Nutzen oder wissen, welchen Nutzen man da rauszieht.
Das gilt für alles in der Softwareentwicklung, meiner Meinung nach.
Also was ich am liebsten, genau.
Was ich am liebsten habe zum Beispiel, also ich schreibe immer noch sehr, sehr viel Note und wenn ich starte damit, dann habe ich einmal keine Typen zu Beginn, weil ja selbst noch nicht weiß, wie meine Software am Ende ausschaut.
Aber wenn ich dann fertig bin, wenn ich dann ein paar Funktionen extrahiert habe, dann lasse ich mir ein paar Typen einführen, einfach nur, dass ich festgelegt habe, was ich hier an dieser Stelle erwarte, damit wenn ich zurückgehe oder wer von meinen Kolleginnen und Kollegen zurückgeht, auch weiß, was dort zu erwarten war.
Und um das geht es eigentlich.
Und gerade in TypeScript, also gerade auch in meinem Buch gibt es ein paar Beispiele drinnen, da kann man sich schon richtig, richtig vorauskommen.
Da gibt es irrsinnig mächtige Werkzeuge wie String Template Literal Types oder Taple Types, Variatic Touple-Types.
Das sind Dinge, wo ich mir denke, Wahnsinn, dass das überhaupt geht, also beeindruckend technisch, dass das geht.
Aber die Use Cases dafür sind halt stark limitiert und man muss wirklich überlegen, ob das dafür steht.
Und ich habe dort drei Lektionen, wo wir ein funktionales Programmiertool wie Currying versuchen, auf drei sehr, sehr komplexe Arten umzusetzen und sagen, aber überleg, 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 auskriegst.
Und die stelle 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, dass das tatsächlich gar nicht so einfach rauszufinden.
Ja, und ich glaube aber, dass da noch ein anderes Problem dahinter ist.
Und ich bin sehr froh, Stefan, dass du da gesagt hast, dass du gegen Tests bist und 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, du hast 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 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.
Das 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 mathematisch herangehen, ja, und die sagen, okay, ich habe ja 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 aussieht.
Oder ich kann gleich die richtigen Typen reinschreiben.
Ja, da müssen wir nicht mehr das Akonym ändern.
Einfach Type-Driven Development kann man neu genau anstarten hier.
Und da, ja, das sind, glaube ich, einfach zwei verschiedene Arten zu programmieren, die eben verschiedene Dinge eher bevorzugen.
Es ist tatsächlich, glaube ich, auch ein bisschen von der Sprache abhängig, weil ich glaube, Python und JavaScript unterstützen ja diese Art des explorativen Programmierens sehr, sehr stark.
Einfach eben, indem sie die Typen auch entfernen.
Also du kannst sie wirklich einfach einmal 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 noch sehr, sehr stark in Rust drin.
Ich habe das jetzt schon erwähnt und sorry, der klassische Rastnutzer nicht, muss ich ständig sagen, dass er Rust verwendet, aber es ist halt wirklich so.
Die Sprache macht einiges sehr, sehr richtig.
Du hast in Rust das her sehr stark typisierte Programmiersprache mit einem fantastischen Typsystem.
Das ist grandios, dass das so funktioniert, wie es funktioniert.
Das heißt, du kannst dir gar nicht leisten, dass du einfach nur mal schaust, wo kommst du mit deinen Wertebereichen überhaupt am Ende hin.
Aber trotzdem schafft es Rust, dass du explorativ arbeiten kannst, weil einfach die Mittel, die zur Verfügung gestellt werden, so zugänglich sein können, weil die Typen, die vor Hause schon drinnen sind, so entgegenkommen sind.
Das heißt, du kommst mit ein paar Basitypen aus der Standardbibliothek und den üblichen Wertebereichen schon sehr, sehr weit, bevor du dir selbst deine eigenen Strukturen und Interfaces nenne ich jetzt einmal heiße anders überlegen musst.
Und das ist sehr, sehr spannend.
Es ist aber trotzdem eine andere Art des Programmierens.
Also das Endro-Resultat schaut auch dann anders aus.
Also ich mag das aber auch gerne, so Models oder so Data Classes zu bauen und dann zu gucken, hey, was sind das denn überhaupt für Objekte und die halt dann direkt zur Annotation zu verwenden, das so strukturell sehr klar.
Ne, es schließt sich auch nicht auch aus, nicht.
Ich bedenke mir, die Gefahr liegt wahrscheinlich, dass man sich auf eines komplett verschreibt.
Macht das, was der Johannes wieder gesagt hat, ganz richtig ist, es ist im Ende des Tages ein Werkzeug nicht.
Und es muss irgendein 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 nicht.
Also ich finde die gerade so angenehm.
Wichtig ist, dass die Sprache, mit der Story das unterstützt.
Ja, ich glaube auch eben, aber ich meine, das hat natürlich mal einen Preis, weil es halt zusätzlich Komplexität unter Umständen halt auch einführt und es dann halt vielleicht auch unzugänglicher macht.
Also ich, worauf ich eigentlich hinaus will, ist, naja, je nach Use Case kann es halt kann es halt unterschiedlich nützlich sein.
Also wenn man halt zum Beispiel eben in einem Team einer großen Software schreibt, dann kann es halt sein, dass es sehr viel bringt.
Auch irgendwie möglichst viele Hürden zu errichten, bevor irgendwie Code.
Du willst quasi gar nicht, dass die Entwickler irgendwas machen.
Ja, das ist leider halt eine Strategie, das ist schwer zu unterscheiden von irgendwie, man versucht Fehler zu vermeiden, bevor sie dann produktiv gehen, zu bloß nicht deployen, was dann halt auch viele Leute machen, was halt irgendwie auch blöde Konsequenzen hat unter Umständen dann.
Weil also viele Sachen, also man hat dann zum Beispiel nicht nur ein Staging-System, sondern noch so drei andere oder vier andere und führt immer mehr hinzu, dass man bloß nicht nach Produktionen deployen.
Ich habe zwei Abteilungen bei uns kennen.
Wir haben Deployment-Release-Zyklus so alle sechs Monate.
Ja, genau.
Und dann in den sechs Monaten passiert halt auch nichts, aber ja, ist halt vielleicht auch irgendwie Konflikt mit anderen Zielen.
Hast du ja diesen Artikel über Move Fast and Break Things gelesen, der kürzlich rauskommt.
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 vor den Leuten zu verlangen, dass sie sich erst Gedanken machen und dass es 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 Analyst oder sowas oder halt irgendwie jemand, der irgendwie, keine Ahnung, Roboter irgendwie dazu bringt, irgendwie lustige Dinge zu machen oder sowas.
Und ich will mich jetzt eigentlich.
Oder Teilchenbeschleuniger, also solche Sachen, genau.
Und ich will gar nicht jetzt irgendwie Typ-Theorie verstehen oder irgendwie, keine Ahnung, auch Unitests.
Und da sind wir auch bei einem Ding, wo die Sachen so ein bisschen ähnlich sind.
Also ich dachte auch lange Zeit irgendwie Unitests sind was ganz anderes und Typisierung ist eine, 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 Unitesting 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, 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, ja, CI-Pipeline und weiß ich nicht, diesen ganzen Kram halt, ne?
Das Stichwort da ist doch Programming by Contract, oder?
Und das ist halt eine Möglichkeit, so einen Contract zu schreiben.
Aber also ich bin da in so einem Zwiespalt.
Einerseits bin ich total genervt von solchen Typsystemen, die dann sehr präzise sind und die dann, ich habe auch, ich bin auch mit Java aufgewachsen, Stefan, also ich zähle deinen Schmerz.
Und dann wirkt man sich ab und macht einen Pair aus Int und String und dann weißt aber nicht, wie da an dem zweiten dran kommst.
Und 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 dann 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, ja, 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.
Hast du in einer Sprache, das kannst du, also ich glaube, ich habe eine mal gesehen, was ist das?
Also grundsätzlich im funktionalen Programmierbereich.
Aber ich würde einmal annehmen, nicht in den populären oder weit verbreiteten Programmieren.
Nicht in denen, die man benutzt irgendwo.
Oder die man schon mal gehört hat.
Aus einem ganz einfachen Grund, weil du halt unter den Wertebereichen von einer Zahl halt 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 im Typsystem generell, oder?
Also ich meine, der, also bei dem TypeScript-Compiler durch ist, ist ja weg.
Das ist ja richtig, genau.
Das ist ja richtig.
Ich glaube in Python genauso, ne?
Wenn ich mich nicht täisch.
Ja, generell.
Also die Annotation erstmal gar nichts.
Genau, das ist, also 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 MyFi drüberlaufen.
Und die Leute verwenden alle Type-Dickt und sowas und denken halt, ja, das überprüft jetzt, ob meine ganzen Werte da so, also meine ganzen Werte in dem Dikt halt so den richtigen Typ haben und so.
Und Python selber macht da gar nichts.
Das überprüft überhaupt nichts.
Es ignoriert die Annotation einfach.
Ich lasse an MyFi rüberlaufen und dann kriege dann so 400 Fehler.
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.
Also es stimmt überhaupt gar nicht.
Und ja, da ist dann, denkt man sich, warum hat man sich denn überhaupt die Mühe gemacht?
Also es ist halt irgendwie.
Ja, wie ist denn der Zustand der Entwicklungsumgebungen in Python?
Kommt drauf an.
Also auch die hängen halt daran, ob du MyPy zum Beispiel als Static Type-Shaper Extension richtig konfiguriert hast.
Ja, und ob dann auch MyPy die Stubs halt leasen kann, die halt da notwendig sind oder halt auch nicht.
Die müssen halt alle dann auch nicht mehr.
Aber viele Idees
machen das doch auch selber schon.
Ja, ja, genau.
Da gibt es ja auch dann, ich weiß gar nicht jetzt, was bei VS Code dann normalerweise verwendet wird.
MyPi ist eine Extension.
Ja, aber ich meine, wenn jetzt zum Beispiel einfach nur das.
Also IntelliJ macht das selber.
Ja, die machen das, die haben einen Proprietären, dann gibt es irgendwie MyPy, klar.
Und es gibt halt noch PyRite und der Language Server für Python, kann es sein, dass er selber in Type von Microsoft in TypeScript geschrieben hat, 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 du, dass die Sprache dir zu einem Typsystem anbietet, cool, aber eigentlich nichts damit machst, sondern du brauchst eh nur einen extra Typ-Checker und anscheinend wie bei den Package Managern gibt es dort auch mehrere, wo du dann raussuchen kannst, welcher gefällt dir jetzt und welcher passt zu dir und so weiter.
Und ich finde es grandios, dass es auswählt gibt, keine Frage nicht, 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 Typ-Checker dabei.
Also der TypeScript-Compiler TSC macht in erster Linie mal Type-Checking, aber kompiliert dann auch tatsächlich JavaScript-Code, den du ausführen kannst.
Also es gibt so jetzt Proposals, dass du auch Typ-Annotation irgendwann einmal in JavaScript schreiben können solltest, so ähnlich wie in Python-Version 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 Typsystem, Typchecker, 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 Typsystem anzubieten, sondern auch Werkzeuge anzubieten, dass du noch ein zu validen JavaScript-Code kommst und du deine Fehler siehst und die Fehler auch sofort in deinem Editor und deiner Idee dargestellt werden, das sind meiner Meinung nach genau die Punkte, die noch auch den, unter Anführungszeichen, den 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-Code und versucht zu informieren und zu verstehen, was ich schon geschrieben habe ohne einzige Typ-Annotation.
Und ich kriege aus dem raus schon Autocomplete und die ersten Warnings, dass vielleicht irgendwas nicht ganz rundlauft und schief geht, das ist so viel wert, ohne dass ich eine Zeile TypeScript schreibe, wo wir denken, ja, das ist eigentlich eine richtig gute Idee gewesen.
Ja, naja, absolut.
Da kann Python sich, glaube ich, auch noch eine Scheibe abschneiden, weil da gibt es noch so ein paar Löcher.
Also wenn ich jetzt sage, ich installiere Py-Scham oder wie auch immer, welche Idee und die kommt schon mit einem Typ-Interpreter oder einem Type-Checker mit, das wäre natürlich göttlich, nicht, dass du einfach sagst, hey, du brauchst immer die Typ-Annotation schreiben, aber die Idee haut irgendeinen Type-Checker schon per Default drinnen.
Wahrscheinlich schreiben sie ihn selbst, weil ChatPraints schreiben es
irgendwie selbst.
Haben Sie.
Der von JetPraints ist behaupten.
Aber die.
Der ist super gut.
Das ist einer der Gründe, warum er Pyjar verwendet, weil die halt da die beste Typ-Inferenz haben und die besten.
Ich meine, man merkt, dass es der Java ist, ja, aber.
Aber das können sie, also da sind sie richtig, richtig gut.
Sie haben auch für schon wieder Rust, für Rust haben sie auch einen eigenen geschrieben.
Also die ganze Welt verwendet Rust Analyzer.
Außer du nimmst Rust-Rover von JetBrains, dann ist der Eigner drinnen und sie haben auch recht damit.
Also das ist halt 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, das, 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 Wänden gebaut werden, halt nicht MyPy, Dropbox, ich weiß nicht, ob die immer noch da so hauptsächlich dran sind, aber dann gibt es noch einen von Google, es gibt noch PyRite.
Die hängen sowieso immer so ein bisschen in den Versionen hinterher, weil sie ihre Codebasis 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 ja auch noch darauf eingehen, welches Subset des Typsystems du jetzt verwendest.
Ja.
Genau.
Da kann ja gar nichts schief gehen.
Ja, das ist eine TypeScript-Version gibt es ja jetzt auch.
Ja, und Type-Script-Personenmanagement ist ja stark in der Kritik.
Sehr keine Frage.
Also das jedes Release ist ja bei Legion.
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 diesen, 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 wir das TypeScript schon historisch gewachsen.
Also du merkst, du merkst schon die dunklen Flecken der Vergangenheit und versuchst sie zu ignorieren.
Das ist ja 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,
auch da kriegst du Historie.
Das ist ein kleines
bisschen Programmiersprachenhistorie mitgeliefert.
Ja, ja.
Ja.
Ja, aber ich wollte gerade nochmal auf Java ein, wo wir das gerade hatten, es ging leider schon ein bisschen drüber davon wieder weg, aber da hatte ich nämlich auch noch so eine schöne, da hatte ich letztens sehr, sehr schönes gelesen, das halt in der, der einer der Autoren von der Sprachspezifikation von Java hat halt irgendwann mal so geschrieben zu den Generics, also dass sie die Generics eingeführt haben.
Also ja, das war irgendwie ein Fehler.
Und dann hat er irgendwie noch in dem Buch selber findet man auch irgendwo so eine sehr schöne Fußnote, ja, wo halt quasi die Annotation von Inam Inam ist auch ein Python ein Problem, aber in Java halt auch.
Und Inam ist halt irgendwie definiert als, ich versuche gerade, ob ich das hier finde, ah ja, genau.
Ist eine generische Klasse definiert als Enam, Spitze, Klammer T, Extens Inam, Spitze, Klammer T, Klammer zu, Klammer zu.
Also diese rekursive Definition ist halt so ein bisschen schwierig zu verstehen.
Wir haben inzwischen aufgegeben, es zu versuchen, Leuten zu erklären.
Es gibt irgendwie Spezialisten, die uns versichert haben, über Typtheorie, die uns versichert haben, dass das schon alles okay ist und kein Problem.
Und wir sollen uns einfach nicht so viel Gedanken drüber machen, was wir sehr gerne annehmen.
Das Spannende ist ja bei den Java Generics, dass die als einziges Element im Typsystem von Java keine Auswirkungen auf die Gestaltung der Laufzeitobjekte haben.
Also das sind auch so nach dem Compile-Schritt wird das einfach entfernt und nie wieder angesehen.
Und das ist halt das Beeindruckende dran.
Also das war halt auch so, oh shit, das brauchen wir jetzt, wir müssen das jetzt machen im Release 1.5, glaube ich, war das.
Und das war die einfachste und unproblematischste Art, wie wir dazu kommen.
Und alle Implikationen, die das hat, die werden bis heute mitgezogen.
Du kannst quasi generische Klassen nie wirklich optimieren.
Geht einfach nicht.
Was halt spannend ist, weil die hast du halt überall, du hast überall Genericks drin.
Deswegen werden auch oft nur in der Standardbibliothek das generische Object verwendet, anstatt dass du einen generischen Typparameter hast.
Und was ihnen mit Inam sein findet ist, was ich sowieso nicht.
Also ich habe das gesehen bei unseren Kollegen und das ist kein Inam, das ist ein Ernst.
Eigentlich jetzt ein guter Zeitpunkt, um nochmal so ein bisschen zu erklären, worum es überhaupt geht und was 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 wissen wollen.
Jetzt kriegen sie es hat mal gesagt, ja.
Im GF10, es gibt auch Generics in Python.
Ja, mit, ja genau.
Hui abuma, wovon getan.
Also das ist ja, das ist, also diese Generics in den Typ-Annotationen, das ist ja wirklich nur sehr instruktiv.
Es ist nur sehr so vage gesagt.
Das ist keine, da ist die Arras ja noch viel größer.
Johannes, hättest du denn neue?
Was ist denn bitte ein Generic, bitte?
Ein Generic ist eine Spezialisierung eines Typen anhand eines anderen Typen.
Und das klassische Beispiel ist da die Java-Liste.
In Python hast du ja eine Liste, die, sag ich mal, dynamisch typisiert ist.
Das heißt, wenn du eine Liste hast, kannst du da eine Zahl reintun und einen String und einen komplexe Zahl und ein Objekt und noch eine Liste.
Das ist immer sehr unterhaltsam, wenn man das in den, wenn ich das in den Seminaren mache, wenn ich den Leuten Programmieren beibringe, die vielleicht schon mal eine Programmiersprache gesehen haben oder die schon mal was davon gehört haben und dann sage 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 Objekt zurück, sondern du kriegst dann tatsächlich einen String zurück.
Das ist der große Vorteil, den du in Java davon hast, dass du diese Accessormethoden hast, die dir die spezifischen Sachen rausgeben.
War das korrekt erklärt, Stefan?
Genau das.
Also gut, Experte.
Ich sage, ich bin nie Experte, ich bin einfach nur Laufgebung und schreib den ganzen List 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 dann passiert.
Und eben, wie du sagst, dann wird es halt eine Array List von String oder eine Array List von Integer.
Und du substituierst diesen Typ-Parameter mit einem konkreten Typen und kriegst du konkreten Typen wie der Retour.
In manchmal Programmiersprachen kannst du dann auch noch so things 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 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 dich schon hin.
Und dann kriegst halt zum einen die Sicherheit, dass du nicht irgendwelche Typen reingibst, die nicht damit funktionieren.
Wie macht man?
Und zum anderen kriegst du halt noch mehr Informationen über deinen Typ noch heraus, wenn du ihn dann verwendest.
Wie macht man das denn in Python-Protokolle?
Doch, das ist in Python ist das seit drei achtem Grunde auch so oder kann man das so machen.
Man kann auch nominal typisiert das Ganze machen, aber da geht das jetzt auch, genau.
Mit Typing Protocols geht das auch.
Ja, genau.
Hat er
das schon mal irgendwo gesehen?
Ja, wirklich.
Ich verwende das.
Also ich finde das eine großartige Idee, aber ich habe es noch nie irgendwo verwendet gesehen.
Ja, ja, doch.
Also ich kenne es auch vor allen Dingen aus dem Fluid Python-Buch von Luciano Ramalou.
Und der hat sich auch mit diesem Typisierungsthema stark beschäftigt und hat dann diverse Fehler in der Typeschat, im Type-Chat-Repository, wo halt die ganzen, wo auch die Standardbibliothek von Python annotiert ist, hat er da gefunden und viele davon konnte er fixen mit diesem Structural Typing-Ansatz.
Und also Fehler im Sinne von halt die Annotationen waren halt irgendwie, da waren halt False-Positives oder halt False Negatives möglich.
Auch sehr interessant, wenn man sich halt anguckt, welche Fehler sind häufiger.
False Positives sind viel, viel häufiger bei Typ-Annotationen als False Negatives.
Also in der Python-Standard-Bibliothek waren es irgendwie achtmal so häufig.
Was halt auch ein Hinweis darauf ist, dass es halt für Leute wichtiger ist, dass halt die, also false Positiv heißt, eine Annotation hat gesagt, nee, das ist, du kommst hier nicht rein, das ist irgendwie, du bist nicht der richtige Typ.
Dein Typ ist hier nicht dich gefragt.
Sozusagen, obwohl es eigentlich doch okay gewesen wäre.
Und also offenbar ist es halt irgendwie so mehr opportun, irgendwie auf der Seite von strikter zu sein, zu irren, als umgekehrt.
Was ja auch so ein bisschen vielleicht damit zusammenhängt, welche Leute das, für welche Leute das halt vor allen Dingen gut ist, nämlich die, die halt versuchen wollen, möglichst viel da draußen zu halten.
Und wenn sie ein bisschen zu viel draußen halten, ist es besser, als was durchzulassen, was halt dann irgendwie knallt zur Laufzeit.
Das wäre dann vollstegativ.
Ja, genau.
Und ja, der hat der hat da 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 Type-Script mit diesen Intersection und Union-Types.
Was ja auch irgendwie so, das ist halt so sehr cool eigentlich, dass das geht.
Und das geht halt, wenn man jetzt so mit Abstract-Base Classes das Ganze macht und nominal geht das halt nicht so richtig.
Das Problem ist, wenn du Nominal arbeitest, du baust du auf den Schlocker Hierarchie auf.
Wenn die implizit ist durch die Basitypen, die du definierst.
Und das kannst du sehr, 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, Property-Typen etc.
Und ich sage mal, eine Programmiersprache wie JavaScript wäre gar nicht anders zu typisieren gewesen, oder es wäre gar nicht möglich gewesen, die anders zu typisieren ist wie mit einem strukturellen Typsystem, weil sonst praktisch kein Code mehr funktioniert hätte, den du irgendwie geschrieben hast.
Und das war immer 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 arbitr geschaffenen Hierarchiekonstrukt sagen, das passt oder passt nicht.
Und ich glaube, es kann mir gut vorstellen, dass das Python auch stark hilft.
Ja.
Definitiv.
Ja, das ist jetzt also seitdem, also ich meine, es ist auch ein, glaube ich, in Go ist das ja auch so.
Mit den Interfaces in Go verhalten sich im Grunde auch so.
Genau, du implementierst implizit Interfaces, wenn die Methodensignatur gleich ist.
Dann bist du kompatibel zum Interface.
Ja.
Ja, und also nö, ich verwende das tatsächlich.
Ich glaube auch, dass es halt, das ist eigentlich sozusagen das, wo es dann anfängt, Spaß zu machen.
Weil ehrlich gesagt, mit den Hierarchien, Klassenhierarchien und so, das ist nicht so meine Vorstellung von Spaß.
Ja, also kann man ja gemeckert.
Ja, du hast ganz recht, Johannes.
Das ist das, was, oder 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 da kann das Konstrukt doch nichts dafür.
Das ist halt einfach so.
Nee, und es liegt
halt nahe, ja.
Du hast schon diese Hierarchie und dann benutzt du sie halt auch weiter.
Du hast schon die Struktur, also nehmen wir sie.
Aber das ist dann eben das Problem, worauf du dann triffst.
Du kommst an der Stelle, wo du weißt, hier muss ich jetzt eigentlich nur addieren, aber der Typ, den du verlangen musst, ist halt irgendein ganz wilder oder ein ganz abgefahrener oder irgendeiner, der wo ganz anders in der Hierarchie drin ist.
Und das, genau.
Was mir sehr gut gefällt am Python-Typ-System, was ich gesehen habe, nur durchs Drüber drüber fliegen, ist dieses New-Type-Konstrukt, wo du sagen kannst, hey, es gibt schon einen bestehenden Typen und das vielleicht sehr, sehr freigiebig.
Das ist vielleicht der Integer da ist drin oder was auch immer.
Aber du kannst eben noch dieses eine Label verschaffen, damit du jetzt nicht irgendwelche unterschiedlichen Integer-Werte durcheinander kriegst oder irgendwelche Objektwerte, die ähnlich sind, durcheinander kriegst.
Weil strukturelle Typsysteme funktionieren halt immer bis zu dem Grad, wo du sagen hast, hey, aber dieses eine Ding will ich da jetzt nicht herinnen haben, weil ich erwarte doch etwas anderes und kann dies durch das Typsystem nicht so ausdrücken.
Mach das New Type, dann wird es explizit und dann kannst du genau sagen, hey, an dieser Stelle erwartest du etwas, was so ausschaut, always 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 New Type 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, dass ich dadurch, dass ich sage, ich definiere den New Type hier, der halt eigentlich ein Int ist, kann mir der Type-Checker sagen, wenn ich irgendwie mal ein anderes Int da reingesteckt habe, was ich nicht mal als Ja irgendwo anders deklariert habe.
Und kriegt dann sozusagen den Effekt, dass wenn da irgendjemand irgendwas reinsteckt, was kein Ja ist, dann gibt es halt auch einen, sagt der Typechecker halt schon, okay, nee, das sieht nicht gut aus.
Und so kann man sich halt das sozusagen so ein bisschen herbei emulieren, dass man irgendwie damit auch überprüft, ob das inhaltlich Sinn macht.
Entschuldigung.
Also gerade mit dem, also in TypeScript kannst du das ein bisschen.
Du kannst teilweise Werte oder geringere Wertbereiche definieren.
Also in TypeScript ist es das spannende, wie in jedem Typsystem, du hast Wertemengen und du definierst ja nur, ob dieser eine Wert, den du hast, jetzt in diese Menge passt oder nicht.
Das sind sehr große Mengen zum Teil, String, Number oder alle Objects.
Zum Teil sind sie halt auf deine Objekttypen heruntergebrochen, wo du sagst, diese Kombination an Properties, die gewisse Typen haben, erlaubst du dort oder nicht.
Du kannst aber auch sagen, hey, dieser einzige oder einzelne konkrete Wert, die Zahl 1, das Dring 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 das schenken.
Aber du kannst noch diese Literal-Types oder Value-Types, dass 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, 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 ein Event-System implementierst und du hast halt on-Click, on Keydown, on Keypress, was auch immer.
Das heißt, es muss mit On anfangen und nachher muss der erste Buchstabe unbedingt 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 auch 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 put post-delete, was auch immer, oder HTTP-Error-Codes, da gibt es 70 um den Dreh.
Ich weiß jetzt nicht, ob es 201 gibt, 217 noch gibt, weiß ich nicht.
Das kann man dieser Union-Typ sehr, sehr schön sagen.
Und dann bin ich mir sicher, dass ich den richtigen HTTP-Statuscode in meiner Response schicke und brauche nicht großartig überlegen, ob ich noch im richtigen Wertebereich bin oder nicht.
Ich muss mich einmal korrigieren, ich habe eben nachgelesen, Value-Types ist nicht das richtige Wort.
Es bezieht sich auf was 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ön erklärt.
Vielen Dank, Steffen.
Das ist auch in Kapitel 4 beschrieben von meinem Buch und da bist du ja noch nicht, ne?
Naja, 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 unters Kopfkissen und werde das per Diffusion.
Kurz, es ist so wie die Matura geschafft hat, mit dem Mathematikbuch und den Kopfkisten funktioniert.
Ich finde, wir müssen noch ein bisschen darüber reden, wie man das so in Python dann machen kann noch und wie man das Typing-Modul vielleicht noch so ein bisschen benutzt.
Alter, wir hatten jetzt so ein New Type, was irgendwie ganz cool ist.
Wir hatten die Generics.
Ja, die Generics, achso, genau, wo wir dann schon mal, da habe ich nämlich jetzt heute Angst gehabt, als ich versuche, versucht das, da dachte ich mir so, oh mein Gott, wenn hoffentlich fragt das keiner, deswegen frage ich das jetzt mal.
Kann mir dann vielleicht erklären, was der Unterschied zwischen Kovariant, Kontravariant und Invariant und so ist.
Ja, genau.
Weil das kann man nämlich auch mit angeben und ich dachte mir so, okay, ich kann es ja angeben, aber oh Gott, was bedeutet das eigentlich?
Und was macht dann Bound und so?
Ich kann es aus einer Typtheorie sagen, was kontravariant ist.
Ich weiß aber nicht, ob das so auf Python auch zutrifft.
Aber ich versuche es jetzt einmal so zu erklären.
Kovariant ist, wenn du schnell die Petit fragen.
Nein, es ist irrsinnig schwierig zum erklären.
Lass mich kurz mein zweites Buch aufmachen, weil da wäre Zeichnung.
Aber bevor ich jetzt allgemeine Beschreibungen erkläre, sage ich es lieber einmal so.
In einer kovarianten Beziehung hast du zum Beispiel einen Typ, der ist String oder Number.
Was bedeutet das, dass wenn du einen Wert hast, der Number ist, dann kannst du den auf jeden Fall auf diesen einen Typen zuweisen, der Strand oder Number sein kann.
Das heißt, je enger dieser Wertebereich wird, hat keinen Effekt drauf, kannst du weiterhin darauf zuweisen.
Kontravariant ist genug umgekehrt.
Du kannst zum Beispiel jetzt nicht eine Funktion, die als ersten Parameter String oder Number oder einen Typen, einen Funktionstypen, der als ersten Parameter String oder Number erwartet, kannst 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 ist der Typ zwar auch ein Subtyp, der Parametertyp ist ein Subtyp vom anderen.
Aber nachdem der in einer Funktion steht, sind die nicht zueinander kompatibel, sondern nur umgekehrt.
Das heißt, du kannst eine Funktion, einen Funktionstypen definieren, der als ersten Parameter eine Number angibt.
Was bedeutet, dass du auch Funktionen zuweisen kannst, die String oder Number erwarten, weil eben dieser eine Fall abgedeckt ist.
Und das ist der Unterschied zwischen Kovarianz und Kontrovarianz.
Brauchst du eigentlich nie, macht dir 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, ihr 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 da.
Weil das sind die Sachen, die merken wir selber nie genau.
Das ist, was man immer nachlesen muss.
Also in welche Richtung kann man was irgendwie doch voneinander erben, wenn ich das richtig verstehe.
Und das eine allgemeine Analyse.
Generisieren.
Generisieren.
Also ich habe es jetzt hier auch gerade, wenn jemand anders spricht, kann ich ja googlen.
Also, so wie ich das jetzt hier verstehe, ist es, das bezieht sich direkt auf Python hier und Qualitätsquelle, Stack Overflow, kann man 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 irgendeinen generischen Typenliste mit irgendeinem Typen drin.
Und jetzt ist die Frage, wenn du eine Liste hast, die den Typen B hat, also den Basistypen, kannst du die dann da verwenden, wo du eine Liste vom Typen D erwartest, also eine abgeleitete Klasse.
Oder ist es andersrum?
Das wäre dann Kovariant oder Kontravariant.
Genau, und das eine ist Kovariant und das andere ist Kontravariant, 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 Kovariant ist, wenn man quasi annotiert mit der Implementierung und Kontravariant ist, wenn man mit der Basis annotiert, ja.
Und Invariant wäre dann, wenn man nicht beides verwenden darf, weil der sagt ja halt, nö, denn das ist nicht genau das, was ich erwarte.
Ja, irgendwie so.
Für genauere Sachen muss man PEP 484 lesen.
Das haben wir ja sicherlich alle schon gemacht.
Da muss man gar nicht genauer drauf eingehen.
Ich packe die Grafik in die Show Notes und dann schauen wir mal, genau.
Schauen wir mal, was das hilft.
Ja, aber genau, ich dachte auch so, also man kann das ja angeben und dann dachte ich so, ich habe das noch nie verwendet.
Ist das irgendwie, hab ich was, passe ich was?
Und was macht dann Bound?
Also, weil das macht man ja irgendwie auch bei den Conta-Variants oder was sagst du das?
I don't know.
Steht zumindest in der Typ, Pising, Typing.
Tatsächlich ist in dem PEP 484 eine sehr schöne Erklärung drin.
Mit Employees und Managers.
Wenn du eine Liste, wenn du eine Funktion hast, die eine Liste von Employees nimmst, solltest du da, kannst du da eine Liste von Managers reingeben.
Und für manche Funktionen kann das Ja sein, wenn du halt sagst, okay, wir müssen Gehalt auszahlen, das müssen Angestellte kriegen und wenn die angestellten Manager sind, dann ist es halt so.
Kann aber auch nein sein, dass du, dass du zum Beispiel, keine Ahnung, alle, die
alle Angestellten feiern, Manager feuern.
Genau.
Zum Beispiel, dass du die, 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 rein reintun.
Wenn du aber eine Liste von Managern reingegeben hast, dann geht das nicht.
Und das ist jetzt eben genau so eine Frage, wo du beide Optionen haben kannst, also so eine Situation, wo du beide haben kannst und das tatsächlich auch eigentlich beantworten können musst, ob du da eine abgeleitete oder eine Basisklasse reingeben darfst.
Das ist eine Co-Variante, eine Kontrollvariante.
Und der Bound ist dann quasi tatsächlich die, wenn dann erst die Manager gefallen, weil das die spezialisiertere Variante ist.
Ja.
Ja, wir haben noch mehr von 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-Alias und die Type-War.
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.
Na, ich meine, weil bei Type-Alias, das kannst du auch einfach so hinschreiben.
Das 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 zyklische Imports zu vermeiden und so.
Und dann ist halt unklar, was gemeint ist, wenn man nicht Type-Alias davor schaut.
Also beispielsweise, wenn ich jetzt irgendwie eine Union habe, das könnte jetzt mehrere Sachen sein, dann kann ich dann Tabi Alias für verwenden, dass es das damit gemeint ist, ihm einen Namen gibt.
Ja, aber du könntest ja auch einfach hinschreiben, MyUnion gleich und dann irgendwie der Typ oben, Pipe-Symbol, der andere.
Aber wenn du.
Du hast dann ein Type-Alias schon.
Das heißt, das selber kann ich annotieren mit Nein, ist es nicht.
Ja, also du könntest damit dann wieder adortieren.
Aber wenn du jetzt zum Beispiel da Strings verwenden wollen würdest für die Typ-Typen, dann geht es halt nicht mehr so richtig.
Und dann macht, also Type-Alias macht das dann halt explizit, dass das halt sozusagen.
Der Alias ist, okay.
Und die Type war, das hatten wir eben.
TVK TKV, was warum TKV?
Ein besonderer Sinter, weil ich diese kurzen Dinge, also einer der Grunde, warum ich Go nicht leiden kann, sind diese Ein-Charakter-Variablen-Namen.
Ja, das sind halt die Generics, oder?
Die wir vorhin hatten.
Genau, genau.
Stefan, du hast angesetzt.
Erklär uns, was Type ist.
Ja, ja, also ich habe jetzt ganz kurz diesen PEP484 aufgemacht und der ist wunderschön.
Also Type-Variable, also immer Type-Parameter dazu, aber das ist im Grunde genau das gleiche.
Das ist eben ein Typ, der später durch einen konkreten Typ ersetzt wird.
Das heißt, du kannst jetzt sagen, diese Typ-Variable in diesem Beispiel von PEP484 ist das ST.
Seized-Type wird das heißend worden, weil da geht es um Siist.
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 Dorten, der zweite Parameter, einschränken.
Also ein Bound sagt hier, also der generellische Typarameter sagt hier, alle möglichen Werte, aber später nur ein konkreter.
Und der Bound sagt hier, 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 wird Seized 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 Bounce.
Andererseits könntest du ja sagen, du hast irgendeine Subklasse oder so.
Aber Bound ist auch etwas, das kennen wir in anderen Programmiersprachen auch.
In TypeScript wird das als Constraint bezeichnet.
Aber im Grund geht es darum, dass du einfach vordefinierst, du hast ein paar Eigenschaften, die du sicherstellen willst.
In dem Fall, was dort dann beim PEP 484 ist, mit diesem Upperbound sagst du einfach, du willst die Möglichkeit haben, eine Länge zu berechnen.
Du willst einfach wissen, hey, da gibt es eine Size, das hat eine gewisse Länge, Größe, was auch immer.
Spannend wäre so, ob ich dort einen String reingeben kann, weil man kann auch die Länge von einem String definieren.
Ja, kannst du.
Genau.
Alles klar.
Cool, dass die Lennen von irgendwas hat.
Ja.
Also ich kenne keinen Python, aber ich habe diesen Codes gelesen und weiß sofort, was ich dazu erwarten habe, weil 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, 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, ja, 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 XY, ist ja erstmal sehr lose und jetzt durch diese Typvariablen und durch den Bound ist es doch relativ genau spezifiziert und auch sehr exakt, würde ich sagen.
Was ich sehr spannend finde an dem Beispiel, und das ist wahrscheinlich jetzt so eine Python-Eigenwart, aber im ersten Aufruf wird dort dieser generische Typ-Parameter oder diese Type war ersetzt durch eine List.
Das ist, glaube ich, die eckigen Kammern nicht.
Im zweiten Aufruf, da hast du geschwungene Klammern, wird durch ein Set ersetzt, also der Typ wird durch ein Set ersetzt.
Aber im dritten, da ist im ersten Aufruf eckige Klammern, im zweiten Parameter sind geschwungene Klammern.
Da wird der Parent-Type davon, eine Collection, verwendet, wo du sagst, hey, okay, ist nicht List, ist nicht Set.
Also es könnte beides sein, du nimmst einfach was, was beide beschreibt.
Finde ich cool, dass das das Typsystem so macht.
Normalerweise würde TypeScript dir da vielleicht einen Fehler werfen.
TypeScript würde da sagen, hey, wenn du das einmal durch einen Typ ersetzt, dann musst du auch im zweiten Parameter den gleichen Typ verwenden.
Und so findest du aber in der Hierarchie tatsächlich einen Parent-Type, den du nutzen kannst.
Das ist ziemlich geil.
Also richtig cool.
Ja, das ist ziemlich schön.
Es ist nämlich ja so, dass ich das jetzt verwenden möchte, muss ich ganz ehrlich sagen.
Ich glaube, ich habe das so weit.
Sehr gut.
Viele Programmiersprachen-Features kommen ja durch Knight umgesetzt, das ist bei Python und auch nicht anders.
Viele Sachen sind einfach aus Knight durch andere Sprachen entstanden.
Nein, also den größten Knight habe ich ja durch die Imput-Signatur.
Das macht einfach so viel einfacher.
In JavaScript ist 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 drin stehen.
Das ist ja auch so eine Sache, dass die man nur bei den Type-Annotations findet oder auch woanders, wo halt derselbe Methodenname mehrfach hintereinander definiert wird.
Was macht denn das genau?
Schreibst du in Python dort dann beide Methoden aus?
Also implementierst du da beide Methoden oder sind es nur die Signaturen?
In Python musst du dich da anstrengen dafür.
Das hat ja nicht mal viel mit, ja, es hat vielleicht schon was mit 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, aber was macht denn das?
Und warum macht man 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 Funktionsobjekt enthält.
Und diese Variable hat einen Namen und diesen Namen, der ist eindeutig, den kann es nur einmal geben.
Und zu diesem Namen kann es 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, ja, 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 Dur 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 addden.
Du kannst keine Integer addieren, weil der Compiler dir sagt, ja, 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 Compilens die richtige Zuweisung bekommen, die sind dann im JavaScript-Kompilat heißen, die dann unterschiedlich, weil die eben da unterschiedlich sind.
Das ist genau der Unterschied.
Heißt das nicht?
Ein Overload in TypeScript ist im Grund nur eine andere Funktionssignatur auf Basis über der tatsächlichen.
Du musst mindestens zwei angeben, eine, die dem Typs-System mitgeteilt wird als Nutzungssignatur und eine, die du verwenden kannst, noch 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 wird für und wieder, ne?
Okay.
In Python ist 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 dieser Signatur entsprechen, dann rufe bitte diese Subsignatur auf.
Also du fügst da quasi eine weitere Funktion hinzu, die nur in bestimmten Fällen aufgerufen wird.
Aber das ist was, was zur Laufzeit passiert.
Also zur Laufzeit wird dann entschieden, welche Submethode aufgerufen wird.
Das ist im Wesentlichen ein Matchcase, der da vorsteht.
Naja, aber ich weiß nicht, ob das im Typing-Zusammenhang nicht was anderes ist.
Also ich meine, es gibt diese Overload-Geschichten vielleicht in Klassen, weil ich aber hier auch bei den 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 es zwei, also es gibt halt, dann habe ich, also es gibt mehrere Overload-Dinge, denke ich.
Genau, also
das ist blöd, ja.
Es ist blöd, dass es die, dass diese Sachen in unterschiedlichen Sprachen unterschiedliche Dinge bedeuten.
Und es ist, also wenn ich der Kaiser wäre, dann wäre das anders.
Also das ist tatsächlich was, was ich vermisst habe, ja, 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, ja, Listen.
Und die machen sehr unterschiedliche Dinge, aber im Endeffekt das gleiche Semantische.
Die fügen die aneinander.
Und die heißen gleich, weil die das gleiche machen.
Und sowas gibt es in Python nicht, weil in Python musste jedes Mal einen neuen Namen haben dafür oder einen neuen Scope oder so.
Ja, das hat.
Also weißt du, warum das 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, nein, weil die
Funktionssignatur ein Typen.
Nein, weil die Funktionssignatur die Typen haben, weil Java-Typen erfordert und dadurch ist einfach genug unverbunden, um das zu identifizieren können.
Genau, es sind unterschiedliche Funktionen.
Also die Funktion add int int ist eine andere Funktion als die Funktion addFloatFloat.
Und darum ist es natürlich in JavaScript.
Genau, darum ist sie in JavaScript, TypeScript 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, eh eigentlich wurscht.
Die sind dann weg.
Ja, zur Laufzeit aufhin.
Aber diesen Mechanismus, den kriegst du hin, der heißt Single Dispatch.
From Funct Tools Import Single Dispatch, PEP 443.
Das, was ihr beschrieben habt, das heißt Overload, das ist ja was ganz anderes.
Python Langutil.
Äh.
Okay.
Ich habe es jetzt hier aus From Typing, also so wie ich das gesehen habe, es gibt auch so ein sehr schönes Beispiel dafür.
Das ist auch aus dem Flow-Python-Buch, habe ich das da.
Also das ist halt so ein Beispiel für Methoden, die halt eigentlich in, also die halt auch so ein Problem, das man mit Type-Annot-Annotationen halt so hat, beschreiben, nämlich dass man, dass halt die Typ-Annotationen nicht so express, 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 Type 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, 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, äh, 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, musst du halt zehn Dinger übereinander häufen, um das halt irgendwie abgebildet zu kriegen.
Und ja, und auch in diesen Dingern sind dann halt, waren halt lange Fehler drin und die sind halt auch echt schwer zu finden.
Also ja.
Und die machen ja auch überhaupt gar nichts, diese Fehler, jetzt mal ganz ehrlich.
Ja, na gut, also irgendjemand hat dann halt offenbar lange genug.
Irgendjemand, also es kann ja sein, du rufst das halt auf, lässt 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 es verdufft 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, ja, gut.
Zugegeben, ja.
Aber was war jetzt die Lösung Jochen?
Weil 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, also sozusagen, wenn du eine Funktion annotieren möchtest, aber das halt die Annotation nicht einfach so hinschreiben kannst, dann kannst du die möglichen Arten, wie das halt, also die, wenn es halt mehrere, wenn du mehrere Annotationen hinschreiben musst für die Funktion, kannst du das per Overload hinschreiben.
Hast dann halt der Methodenbody oder Funktionsbody ist dann halt 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 es aber auch nicht aus.
Nee, das sieht nicht schön aus.
Ich würde es zum Beispiel in TypeScript auch nicht immer verwenden.
Meistens ist das ein Codes, weil 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, ne?
Warum macht man das dann nicht?
Vielleicht, wenn man so ein Public-AP-Interface hat, was unbedingt benutzbar bleiben muss, aus irgendwelchen Gründen.
Vielleicht für Legacy oder.
In JavaScript gibt es es, weil, also in TypeScript gibt es es, weil du halt in JavaScript Parameter weglassen kannst oder Parameter in 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 ein Sternchen, Quark schreibt oder sowas.
Also gerade dieses Add-Beispiel vom Johannes, das würde ich eigentlich jetzt den TypeScript mit Generics umsetzen.
Ja gut, wenn du jetzt eine Methode add für Integer und eine Methode add für String hast, musst du ja schon zwei unterschiedliche Implementierungen haben auch.
Also an irgendeiner Stelle musst du ja dann die Implementierung verzweigen.
Nicht in JavaScript.
Ja, wenn du Plus verwendest, okay, aber dann muss das Plus irgendwo hin verzweigen, weil das macht ja sehr unterschiedliche Dinge.
Der müsst ihr dann da nicht überschreiben.
Ja, ja.
Ja.
Was mir noch fehlt, wir haben schon relativ viel gesagt, was ist sowas wie, ich glaube, es ist eben schon einmal gefallen, so etwas wie rekursive Types oder sowas, wenn ich zum Beispiel einen JSON-Type definiere oder sowas.
Oh, sag doch nicht sowas.
Kapitel 7.
Da bin ich ja noch weit entfernt von Kapitel 7.
Rekursive Types ist schon nötig, wenn du jetzt zum Beispiel irgendwie eine Liste definieren willst, einfach verkettete Liste, dann hast du dort nur einen Knoten und der verweist auf den nächsten Knoten.
Aber das ist eigentlich nur Typsystemfu, nicht.
Also du musst nicht irgendwie die Möglichkeit haben, dass du Typen definieren kannst, die sich selbst referenzieren können, wenn nötig.
Also wie JSON-Objekte oder sowas zum Beispiel tatsächlich.
Zum Beispiel, ja, genau.
Also in JSON kann es ja auch sein, dass du naja schwierig.
Ja, eine Liste von Objekten habe, in denen andere das entschecken, die wieder irgendwie Teugs haben oder so.
Ja, genau.
Oder ein Array von Arrays, wenn du schon dabei bist.
Aber ich habe einmal mit jemandem vom TypeScript-Team gesprochen bezüglich rekursiven Typen.
Das ist meistens ein Implementierungsdatei, wie tief der Compiler da dann gehen kann.
Also was sind die, wie ist der Compiler entwickelt, dass er bald genug sagen kann, hey, da stoppe jetzt und pass nicht mehr weiter.
Also wie geht der Compiler mit der Rekursion?
Ja, da 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 und
so geht es nicht kaputt, ja.
Und da wären es auch immer besser, der Mathe-Scripte-Compiler ist schon recht.
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.
Aber das gibt es gar nicht.
Jason, hast du schon
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.
Es geht schon weit rein mit der Rekursion und die geht auch weit genug in der Mathematik.
Ja, ja, ja.
Ja, ich weiß nicht, haben wir noch.
Ah, oh, was mir noch einfällt, genau.
Das schließt so ein bisschen an das Piedentic-Thema von eben an.
Ich meine, das ist ja jetzt etwas, was man, also die Typen werden ja zur Laufzeit ignoriert in Python, aber nicht immer und man müsste es auch nicht, weil im Grunde kann man rausfinden, wie die Annotationen sind.
Und es gibt halt auch Software, die das macht, wie zum Beispiel Pydentic.
Ja, oder MyPy.
Oder FastAPI oder FastAP.
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 Unternehmen.
Das ist ja ein weit verbreiteter Ihr glaube ich, dass Deno direkt TypeScript interpretiert.
Ach so.
Deno hat nur einen TypeScript-Compiler inkludiert.
Also kompiliert TypeScript, bevor er es JavaScript ausführt.
Also tatsächlich, ich sage mal, im JavaScript-Bereich reden wir eher von unterschiedlichen Typsystemen, die existieren.
Wie Flow-Type ist zum Beispiel eins, das sehr, sehr optisch sehr, sehr ähnlich ist zu dem, was TypeScript zur Verfügung stellt, aber halt in den Noncen unterschiedlich ist.
Oder eben TypeScript, und das sind auch schon die populärsten.
Der Closure-Compiler hat aber ähnlich funktioniert.
Wie Typen definiert werden.
Ja, CoffeeScript ist aber sogar eine eigene Programmiersprache.
Also wie Typen
definiert werden.
Gleiche Historik.
Ähnlich, ähnlich.
Da gibt es 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 ActionScript, also die Flash-Programmiersprache, noch eher ähnlicher oder verwandter mit TypeScript and Flow Type ist.
Aber das ist es dann auch.
Also du hast entweder unterschiedliche Typ-Systeme, dann entscheidest du in the meisten Fällen heutzutage eh für TypeScript und dann bietet die TypeScript eigentlich alles, was du dafür brauchst.
Also du laufst gar nicht in Gefahr, dass du irgendwie an others werkzeug nimmst.
Und TypeScript versteht halt auch komplett JavaScript.
Das heißt, du kannst halt dort with JavaScript-Code anfangen und dich nur mal auf die Typen-Inferenz vom TypeScript-Type-Checker verlossen.
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 dir aber jetzt nicht diesen Namen dazu sagen.
Macht man aber aus dem Grund nicht, weil der TypeScript-Type-Checker eh gut genug ist, dass er schon sehr, sehr viel rausfindet, bevor du überhaupt irgendeine Annotation machen musst.
Was ein gutes Migrationssool ist, ist JSDoc, das sind halt ein Typ Annotationen im Kommentar, wo du einfach sagst, hey, du hast diese Funktion, die auch 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 Anderscore, schon.
Und TypeScript kann mit dem umgehen.
Also TypeScript kann auch Typinformationen aus diesen Kommentaren lesen und hat halt so weit mehr Kompatibilität mit dem gesamten Ökosystem, als wie 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 Typinformationen zur Laufzeit hinzu und leiten dadurch TypeScript-Typen ab.
Aber das ist es dann schon.
Also es gibt auch aber so Reflection-Geschichten.
Achso, okay, dass du so rumgehst.
Das ist aber alles Moonpitz.
Also das würde ich alles nicht.
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, hey, du brauchst jetzt Typinformation zur Laufzeit auch, dann kannst du über die SOD-Bibliothek dir deinen Typen in JavaScript definieren.
This is 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 Typen, classischer TypeScript-Typ, den du in deinen Methodensignaturen verwenden kannst, den du annottieren kannst, wo du Type-Checken hast, das funktioniert, das ist grandios gut.
Parallel dazu hast du aber immer noch dieses JavaScript-Konstrukt, mit dem du Validierungen anfangen hast.
Das heißt, du kannst sagen, hey, du kriegst jetzt so JSON from the backend, steckst it in the validator rein und kriegst entweder Ergebnis, das nachher dem Typen entspricht, super, oder Fehlermeldung, mit der du umgehen kannst.
Und das ist eine grandiose Bibliothek.
Also 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 als man.
Okay, cool.
Also ähnliches.
Also in der Verfahren.
Sehr ähnlich.
In SOT ist es aber so, dass du halt 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, wie du normalerweise in TypeScript hast, dass du sagst, du schreibst dir einen Typen und die sind nach dem Kompilator einfach weg.
Also TypeScript ist so eine Erase-to-JavaScript-Sprache, was auch bedeutet, wenn du es dir zur Laufzeit haben willst, musst du in JavaScript anfangen und musst dir den anderen weggehen.
Ja, okay, aber da steht ja nicht, würde ja nicht prinzipiell was dagegen sprechen, oder?
Dass du von TypeScript zu JavaScript beziehungsweise.
Es ist nur ein Teil des Tooling, es existiert.
Ja, okay, aber das ist auch gut.
Also du hast auf jeden Fall das Leistung.
Unbedingt zu empfehlen.
Ja, unbedingt zu empfehlen.
Also das ist richtig richtig.
Finde ich super spannend.
Könnte auch für mich nützlich sein.
Also gerade wenn du mit Backends arbeiten musst, denen du nicht trauen kannst, herrlich.
Ja, oder mit Inputs von Benutzern.
Ich meine, da musst du eh immer Validierung machen, aber das kann einem ja in dem Sinne die Arbeit ein bisschen abnehmen.
Naja, quasi man definiert halt, wie man gerne hätte, dass die eigene Datenstruktur aussieht und benutzt dann diese Information halt auch zur Validierung dagegen.
Das ist natürlich, also ja, das ist genau eigentlich der Use Case von Piedentic ja auch.
Muss man das Patentik nur genau anschauen?
Also das ist ja jetzt um Satmail, ob es heute gehört, wie wir begonnen haben.
Erklär mal Jochen, wie er denn zwischen Fast API und Padantic.
Ach, ja, FastAPI ist sozusagen ein
Interface, was Advent-Server.
Ja, genau, oder?
Padentic ist eine Bibliothek, die benutzt wird von Fast API.
Und die halt sozusagen ermöglicht, wenn man halt mit Typ-Annotationen sozusagen oder der Syntax, man.
Es gibt noch mehr, weil man kann halt auch noch mehr machen, als nur die Sachen, die mit Annotationen möglich sind.
Man kann halt auch Validierungsfunktionen haben und Upper Limits und Lower Limits und weiß ich nicht.
Und ganz viel komplizierte Socks halt auch mit dazu schreiben.
Das gehen alle mit den Typ-Annotationen natürlich nicht, aber wenn man einfach nur die Typ-Annotationen hinschreibt, dann passiert das halt auch, dass dann sozusagen man ein JSON nehmen kann und man hat halt eine Objektstruktur definiert mit den Typen und dann sagt man halt hier, hier ist das JSON, parst das mal und validier das mal.
Ja, und
wenn es nicht, dann kriegst du 4, 2, 2, weil da fehlt irgendwie ein bisschen.
Und 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 eine Number sein, aber da ist eigentlich, da ist ein String oder das ist halt irgendwie, das passt sonst wie nicht, das soll eine Liste sein, aber es ist halt nicht.
Ja, und das natürlich nicht.
Okay, also es ist, also es ist quasi das, woraus Fast API gebaut hat.
Fast API ist verdäntig 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, ne, die Bibliothek von Tom Chrissie.
Also Fast API ist schon so ein bisschen, ist halt so irgendwie drei sehr coole oder drei, vier sehr coole Open Source Bibliotheken in einem French Code irgendwie quasi.
Noch so Routing-Kann, das haben wir halt irgendwie von Flasper kannte, ne, als Dekorator oder Flaskbar auch.
Ja, genau.
Das ist natürlich auch der Auto.
Also Stefan, wenn du Fast AP schon kennst, dann weißt du auch, wie Pedantic funktioniert.
Nur halt innerhalb der.
Okay.
Also wie gesagt, ihr habt den Namen in den Architektur-Diagramm geschrieben.
Also das ist mehr Erfahrung damit auf.
Reicht anscheinend.
Es ist schon mehr damit gemacht, dass es nicht mehr so ist.
Genau.
Ja.
Aber genau, also ja, das ist auf jeden Fall auch so noch ein ganz interessanter Ding, dass man, weil ich meine, das ist ja tatsächlich so, wie viele Leute das benutzen.
Viele Leute benutzen dann Type-Dikt und denken, das würde passieren, dass es validiert wird, aber es passiert halt nicht.
Ja.
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 Tagen, nach anderthalb Stunden alles über
Tage sein können, kein Problem.
Typsysteme und Typen gesagt.
Das ging ja relativ schnell jetzt.
Für meinen Typ hat er immer noch keine Erklärung von mehr, sonst.
So Typen wie dich, Dominik, schwer zu beschreiben.
Das ist 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 Kovarianz und Kontravarianz.
Oh, nachdem ich mir die Grafik so lange angeschaut habe.
Ich hoffe, ich kann es erklären.
Kovarianz ist in Wirklichkeit, was wir als Subtyping verstehen.
Angenommen, du hast ein Lebewesen, dann hast du einen Subtyp davon, das ist ein Pflanzenfresser, dann hast du einen 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 du aber auch Kühe reinschmeißen oder Schafe reinschmeißen oder veganer.
Vermehrt.
Und das ist Kovarianz.
Das heißt, du kannst etwas sehr Breites akzeptieren und kannst was sehr konkretes reinstopfen, wenn der Subtyp.
Also das heißt, ich erwarte ein Lebewesen als Type Annotation quasi.
Genau, genau, genau.
Jetzt hast du aber zum Beispiel eine andere Kovarianz, nämlich du hast jetzt Pflanze und davon abgeleitet Gras und davon abgeleitet vielleicht teuer oder so.
Und jetzt willst du eine Funktion zur Verfügung stellen, die akzeptiert Grasesser, dann kannst du dort bei den Grasessern Kühe, aber auch Pflanzenfresser reinschmeißen.
Wenn du jetzt aber sagst, du akzeptierst jetzt Pflanzen, also alle die Pflanzen oder Funktion von Entitäten, die alle Pflanzen essen können.
Alle Pflanzen.
Dann kannst du dort keine Kühe reingeben, weil Kühe können nur Gras essen.
Und das ist Kontravarianz.
Das heißt, du hast zwar auch einen Subtypen, du hast ja breiten Typen.
Ich akzeptiere ja Pflanzenfresser, allerdings kannst du keine Kühe reingeben, weil Kühe nur Gras essen dürfen.
Okay, und Invarianz ist dann ganz festgesetzt, dass halt nur den einen speziellen Typ.
Genau, Invarianz ist, geht in beide Richtungen.
Ja.
Genau.
Also ich hoffe, dass das nochmal veranschaulicht.
Ich glaube, wir gucken uns lieber dein Bild nochmal an.
Ich hoffe, das Bild ist so anschaulich für die Leute, die da ausgestiegen sind.
Ja, super.
Und das in den nächsten vier Folgen alles nochmal erklären.
Das ist ja auch okay, wenn da eine, wenn da eine Erklärung dabei ist, die.
Hallo bei python-podcast.de.
Wir haben aber noch gar nicht ganz fertig, weil wir möchten gerne 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 ihr total grandios findet.
Ja, genau.
Irgendwas Schönes zeigt.
Ja, meistens nehmen wir Python-Module, aber das ich nehme tatsächlich, ja, auch nicht immer.
Ich nehme tatsächlich diesmal eins von Simon Willison und zwar das LLM.
Ich glaube, das haben wir ja bei einer der Machine Learning-Folgen.
Ach, das Kommandozeilent.
Zwar schon
in den Shownotes irgendwo gehabt, aber es ist tatsächlich, bei mir ist vermehrt in Benutzung, ich 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 Intuition gibt, dann so die Standardpersönlichkeit des antwortenden LLMs irgendwie so ein bisschen gerade zu rücken auf das, was man selber gerne als Antwort hätte.
Such die Leute gut aus, mit denen du sprichst, das wollte ich damit sagen.
Und dann lädst du uns ein, Dominik.
Weiterhin viel Spaß bei den nächsten Picks, wollte ich noch sagen, ja.
Ja.
Ja, was hast du denn gibt mich doch?
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, da kann man auch die Antworten, wenn man dann drauf gekommen ist, wie das sein muss, an uns schicken.
Und zwar The Little Little Typer ist ein Buch, das ich habe es versucht zu lesen, es ist irgendwie, ich habe dann zwischendurch aufgegeben.
Das wird sich sagen, wie Experiment mit Types und Beisen.
Ja.
Aber 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 irgendwie was für alle wahrscheinlich.
Doku ist ganz nett, auch nicht Python, sondern Go-Geschichte.
Heroku hatte ja in letzter Zeit so ein bisschen Probleme.
Und es ist nicht mehr so richtig irgendwie der Platz, wo man vielleicht so mal so, wenn man, also früher hat man das ja, wenn man irgendwas mal eben deployen wollte, hat man das oft dann bei Heroku oder so getan, weil das halt sehr einfach war, aber das geht irgendwie nicht mehr.
Und das kann man auch in Selbstbox.
Also meine Lösung dafür ist ja, dass ich das halt einfach, ich habe da so meine Standard Ensible Dinger.
Also du
bist vom Dir ist Heroku zu kompliziert geworden und deshalb hast du jetzt deine eigene Hosting-Lösung gebaut.
Ja, leider, ja.
Das ist natürlich keine Option, die jetzt viele.
Genau, also das kann ich auch nicht unbedingt empfehlen.
Das ist das unerwartet kompliziert.
Aber bei mir geht es jetzt daher, habe ich das Problem nicht mehr.
Und ich mache ja auch keinen Docker oder so, sondern ich deploy 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 Pog-File und dann kann man das einfach direkt und da auch, also wenn man Docker-Container bauen kann, kann man direkt Docker-Container dahin deployen und die laufen dann unter Subdomainen direkt mit HTTS und so.
Warte das sogar mit Heroku, also Doku?
Nee, nee, das ist also, aber du musst halt das Doku auf einem von irgendwo auf einem, weiß ich nicht, auf einer virtuellen Maschine irgendein Dings halt deployed haben.
Self-hosted.
Genau, Self-Hosted Heroku quasi.
Und genau, das ist, glaube ich, manchmal ganz hilfreich, sowas zu haben.
Oh.
Okay, dann schließe ich mich da direkt mal an, weil dann in dem Fall habe ich drei Picks.
Ah, okay.
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 technische Zeugs damit.
Also du schickst den in 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 dir die Alternativen zu Heroku und self-hosted einmal gesagt.
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 ein bisschen.
Ewigkeiten, dass ich von Fernsehen etwas höre.
Du meinst das ZDF meinst du das tatsächliche Fernsehen, was
das zweite deutsche Fernsehen meine ich.
Und 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.
Ach, okay, so ansehen.
Und GitHub ZDF-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 er ja doch auch einiges an Arbeit drinsteckt.
Und weil es da auch viele Firmen gibt, die sowas gerne hätten.
Genau, das war's von mir.
Stefan, hast du noch was für uns dabei?
Ich habe nur was rausgefunden, 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 Asynchrate-Konstrukt gestalten hast.
Und wie gesagt, der ist schon ewig gehört, aber er ist vor kurzem wieder bei uns in der Firma aufgeproppt, kann ich dir empfehlen, versuch das so zu erklären, dass du die Ergebnisse oder die Erkenntnisse in Python genauso anwenden kannst.
Und ich finde die 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 auf jeden Fall mal lesen.
Nee, da gibt es tatsächlich noch was älteres.
What color are your bits?
Das ist von 2004.
Da geht es um die Herkunft von Bits.
Also ob deine Bits urheberechtlich 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, cool.
Ich würde sagen, herzlichen Dank, dass ihr heute alle wieder da wart.
Herzlichen Dank, Stefan, herzlichen Dank Johannes.
Ja, danke für die Einladung.
Freut mich sehr auch.
Dann, ja, bleibt uns gewogen, schaltet uns wieder ein, hört uns, wo ihr gerade seid, morgens, mittags, nachts, abends, tagsüber zum Schlafen, zum Einschlafen.
Einen wunderschönen Tag.
Bis bald.
Tschüss.
Ciao.
Tschüss.