We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

SPy (Static Python) lang: fast as C, Pythonic as Python

00:00

Formal Metadata

Title
SPy (Static Python) lang: fast as C, Pythonic as Python
Title of Series
Number of Parts
131
Author
Contributors
License
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
SPy is a brand new statically typed variant of Python which aim to get performance comparable to system languages such as C and C++, while preserving the "Pythonic feeling" of the language. The main idea behind SPy is that "modern Python" is actually a subset of Python: - many of the most dynamic features of the language are considered bad practice and actively discouraged; - the alway-increasingly adoption of typing leads to codebases which are largerly statically typed. However, these rules are not enforced by the language, and there are cases in which "breaking the rules" is actually useful and make the code easier/better/faster. From the point of view of language implementors, the VM cannot easily take advantage of the "mostly static" nature of programs because it has always to be ready for the generic case. SPy tries to reconcile these two sides: - it uses a static type system which is designed specifically for safety and performance; - the vast majority of "dynamic" feature of Python (like decorators, metaclasses, `__special_methods__`, ...) can be used at zero cost, since they are resolved at compile time by using meta-programming and partial evaluation techniques. This talk will present in the details the ideas behind SPy and its current status.
Static random-access memoryCloud computingCompilerComputer animationLecture/Conference
OscillationDesign of experimentsView (database)Installation artCodeCompilerSubsetPhysical systemRule of inferenceJust-in-Time-CompilerMultiplication signSource codeNumerical analysisVirtual machineArray data structureCodeCompilerComputer programmingBefehlsprozessorSubsetInformationLevel (video gaming)Operator (mathematics)Rule of inferenceRandomizationPiMixed realityPhysical systemModule (mathematics)Graph (mathematics)Core dumpHigh-level programming languageMathematicsSystem callImplementationOrder (biology)ResultantPoint (geometry)HookingMathematical optimizationObservational studyType theoryNumberInterpreter (computing)Run time (program lifecycle phase)WebsiteGraph coloringLogicFormal languageSemantics (computer science)Extension (kinesiology)Set (mathematics)Line (geometry)Online helpNoise (electronics)Ideal (ethics)Social classLimit (category theory)Interior (topology)Field (computer science)Escape characterDampingProjective planeLoop (music)BitDynamical systemFundamental theorem of algebraPosition operatorProcess (computing)Functional (mathematics)Binary codeScaling (geometry)IntegerComplex (psychology)RewritingGoodness of fitLecture/ConferenceComputer animation
Shift operatorInformation securityDemo (music)FreezingMultiplication signRun time (program lifecycle phase)Phase transitionMachine codeComputer programmingSocial classSemantics (computer science)Point (geometry)Variable (mathematics)CASE <Informatik>Partial derivativeOrder (biology)Interpreter (computing)Formal languageMathematicsLogical constantWeb browserMeta elementNumeral (linguistics)AdditionOperator (mathematics)Statement (computer science)Formal grammarSoftware bugCompilerMereologyLevel (video gaming)NeuroinformatikCodeInternetworkingView (database)Physical systemComputer fileProcess (computing)SubsetGraph (mathematics)LogicBridging (networking)Functional (mathematics)Branch (computer science)Valuation (algebra)Abstract syntax treeEvoluteString (computer science)Electronic mailing listJava appletNetwork topologyTheory of relativityDeterminantIntegerUniform resource locatorKey (cryptography)Loop (music)Inheritance (object-oriented programming)Electric generatorResultantModule (mathematics)Patch (Unix)SpacetimeFreeware2 (number)Type theoryField (computer science)ExpressionDifferent (Kate Ryan album)Web 2.0Blu-ray DiscSoftware testingGraph coloringRule of inferenceOverhead (computing)Computer animation
Ordinary differential equationCodeGeneric programmingError messageMiniDiscParsingInterpreter (computing)Demo (music)View (database)Network-attached storageAlgebraic closureTypprüfungRemote Access ServiceSteady state (chemistry)Cross-site scriptingRun time (program lifecycle phase)Cloud computingThermische ZustandsgleichungIBM Systems Application ArchitectureDesign of experimentsFunction (mathematics)OvalRegulärer Ausdruck <Textverarbeitung>Object-oriented analysis and designMilitary operationEquivalence relationParameter (computer programming)Point (geometry)Formal languageBranch (computer science)Functional (mathematics)LogicImplementationCompilerModal logicExpressionType theoryError messageInterpreter (computing)Letterpress printingCompilation albumDivisorSoftware testingMultiplication signGeneric programmingRight anglePhase transitionRule of inferenceComputer configurationProcess (computing)Default (computer science)Computer programmingClassical physicsTypprüfungoutputNormal (geometry)Algebraic closureOperator (mathematics)Message passingPoisson-KlammerFunction (mathematics)Machine codeMathematical optimizationTemplate (C++)Special functionsSpacetimeModule (mathematics)Revision controlSocial classSet (mathematics)CodeDynamical systemEquivalence relationString (computer science)MathematicsCore dumpView (database)IntegerPartial derivativePerformance appraisalStatic random-access memoryObject (grammar)Code refactoringNamespaceShift operatorNatural languageComputer animation
Computer chessMilitary operationRow (database)Equivalence relationFinite element methodDemo (music)CodeError messageGeneric programmingAreaInstallation artView (database)AerodynamicsStatic random-access memorySymbolic dynamicsLetterpress printingString (computer science)Instance (computer science)Function (mathematics)Operator (mathematics)OvalSign (mathematics)Extension (kinesiology)Level (video gaming)Default (computer science)Computer networkVideo game consoleCondition numberSource codeElement (mathematics)LogicCASE <Informatik>Process (computing)Object (grammar)Type theoryRun time (program lifecycle phase)Operator (mathematics)Interpreter (computing)Semantics (computer science)Field (computer science)String (computer science)ImplementationCommunications protocolFormal languagePoint (geometry)System callMultiplication signIntegerEquivalence relationBuffer solutionMacro (computer science)Row (database)Web 2.0Interactive televisionNumberCompilerFunctional (mathematics)Interior (topology)Valuation (algebra)Dynamical systemNP-hardDemo (music)Rule of inferenceView (database)MereologyCodePoint cloudElectronic mailing listData dictionarySemiconductor memorySocial classPerformance appraisalValidity (statistics)Musical ensembleTypprüfungDivergenceDefault (computer science)Line (geometry)Inheritance (object-oriented programming)Arithmetic progressionLevel (video gaming)Right angleDirected setPartial derivativeCore dumpBefehlsprozessorObservational studySingle-precision floating-point formatBitComputer animation
Intrusion detection systemExtension (kinesiology)Default (computer science)Source codeElement (mathematics)Video game consoleDemo (music)Level (video gaming)Computer networkCondition numberRouter (computing)Remote Access ServiceExact sequenceView (database)CodeLatin squareWeb Ontology LanguagePhysical systemDisintegrationDirection (geometry)Arithmetic progressionCodeValuation (algebra)Overhead (computing)Terminal equipmentLevel (video gaming)Multiplication signJust-in-Time-CompilerInteractive televisionExtension (kinesiology)Inheritance (object-oriented programming)Translation (relic)AbstractionMeta elementRun time (program lifecycle phase)Element (mathematics)WindowINTEGRALDirection (geometry)Attribute grammarResultantWeb 2.0Type theoryScripting languageFunctional (mathematics)Social classWrapper (data mining)BitSet (mathematics)Performance appraisalComputer animation
Assembly languageStorage area networkMultiplication signBitProjective planeLecture/ConferenceMeeting/Interview
Intrusion detection systemData acquisitionRippingOpen sourceCodeSoftware repositoryBitFormal languageRepetitionBranch (computer science)Point (geometry)Demo (music)Code refactoringMeeting/InterviewLecture/Conference
Software testingCodeTemplate (C++)Projective planeMeeting/InterviewLecture/Conference
Formal languageType theoryGame controllerNatural languageOperator (mathematics)Process (computing)Run time (program lifecycle phase)Multiplication signWritingCodeArray data structurePoint (geometry)CASE <Informatik>Lecture/ConferenceMeeting/Interview
DataflowMathematical analysisType theoryImplementationFormal languageProgrammanalyseTheoryMultiplication signGoodness of fitTypinferenzPoint (geometry)Lecture/ConferenceMeeting/Interview
Roundness (object)Multiplication signPoint (geometry)Computer animation
Transcript: English(auto-generated)
Hello everybody, thank you, so okay like this talk is about spy What is spy? Well, it's hard to define we could it's a compiler We can say that it's a compiler for Python. Maybe you can say compiler for a variant of Python
We will see later what I mean exactly But before I start I would like to understand to show like My motivation behind this so how many of you like Python? Yes, that's what I expected. Hope that if I didn't see any hands, it would be how many of you would like Python to be faster
Okay, how many you know how to make Python faster? Okay, I want to talk to you later because I don't I mean I spent a lot of time doing pypi historically Which was Python sheet compiler. We try to make it faster. I Think there is a limit At which we can the performance you can reach with that approach
So the idea with spy is really let's make a thought experiment and let's try to imagine Something which is Still pythonic the fields like Python and we it has all the nice feature that we like about Python that when we raise
the hands before but We remove a bit of the dynamicity So to make it easier to compile and faster to execute. So this is kind of the Underline motivation behind my my work here. I Claim that a big problem the fundamental problem in Python performance is that
The compiler if you if you are a Python compiler and want to make Python fast Python fast executable out of a Python Source code you don't have much information. Like if you're a human and you look at this code, it's obvious what it does I mean, we are importing non pi. Thank you
And it's clearly a constant and the value is 10 and then we are functioning which takes an array of floats and the constant And then I mean if you read a code, you know what it does But if you're a compiler You cannot assume anything because no pie could not be known pie could be another package or I could
Made some magic which sees of the modules or I can add an import hook and then who I don't know What is this module and it could be changed elsewhere from another module in at any point in time later? The type annotation could just lie because Python doesn't check them So like there is this gap between what is good call like
This code really does what what what you what you imagine because it will never pass a code review like If you do too much strange stuff, well, it's bad code and should not write it But as a compiler, I cannot assume anything because I need to try to comply with all these strange semantics. I
Claim that in practice the vast majority of people already use a subset of Python and In which most of strange stuff don't actually happen in practice and in the latest years There was there is a lot of people using and liking study typing because of safety and robustness and blah blah
But the way it's done currently it doesn't help performance at all because it's just ignored and It's not safe because the interpreter actually doesn't check the types and My pie or pie right?
They are basically linters and there are a lot of escape edges in which you can have a program which actually fails at runtime Even if it's positive type check, so like it doesn't buy you much it baby something People find it useful, but I think that you can do better so One of the problem is that the type system that we use in Python was like kind of put on top of the existing language
So the idea is let's try to design something from scratch With this goes in mind be safe to be fast and to be Pythonic I'm fully aware that there are tons of other projects like this There is number there is our Python which is actually what I come from
From the pipeline site and we can consider it like something ideas pie torch as its own jit with its own set of Restrictions. So my spicy is another example. I mean there are many of them so I'm just adding a new one, so I've just I think we're like a lot of
Noise somehow I claim that the ideal spy Kind of fix the other end of the of the wire because all these languages Try to fix the inner loop program problem so you have numeric computation you have a while loop and you do stuff on arrays and you want them to be faster and
Usually we have a lot of solution for tears. We don't have really a good solution for a full-scale object-oriented Features Like you in which you can write the whole program and and and if it's fast Because I try to solve this kind of problem the
It's very important to explain to to underline a non goal is to be compatible with Python like you The goal is not to take a random Python package Compile it and a bit faster. I don't think it's possible. Actually. I'm pretty sure that's mark who I see Over there disagree with me because it's trying to make by C Python faster, but there is a limit of what you can do without
changing rules, of course The goal is to be compatible with Python in the sense that you will be able to mix spy and Python code Import modules and etc. But it's kind of obtained. I have a new extension which is dot spy
So like you write new core instead of rewriting everything in rust. Let's rewrite everything in spy which is easier basically But The goals is that I want something which is easy to understand which is filled by tonic Like if you don't know that you are writing spy instead of Python. Well, it doesn't feel more like Unless you know all the details of what happens when you do dander and then you return not implement
And then you do a look up on the other Operand and blah blah then if you don't know these rules then probably nothing change not much changes for you But I want something which is easy to implement Because there is a value in having an implementation which is easy to write and to maintain
And I want something which doesn't have what I call performance clips Like if your optimization become too smart then you arrive quickly at the point in which you have a program which is fast because the optimizer is able to Guess What are the assumption and how your program is behaving and then maybe it's it compiled it very fastly, but then
You change some line of code in a little module and then the JIT compiler Don't no longer the assumption of a gene compiler longer hold and then everything becomes two times lower ten times lower
There's something which I saw happening in pi pi like for real Exactly a good very good job because people then came to me and I had to consult them and to make the code fast But like I don't think it's callable So Like the goal is really to have something in which Performance is kind of built in and it's easy to achieve
We don't need it, you know You don't need a PhD in order to understand what's going on and to get the best result At a very very high level I mean now I'm briefly I will explain like kind of the rules of the language and
The way I want to reach this goal, but a very high level. I think that we can Think of languages and this to with these two colors. So on the on the left here I have what I call high high level language Which is usually implemented as an interpreter and all the operation are kind of slow because they are like
The any operation contains a lot of logic So again in Python if you have a plus B There is a lot of logic because you need to understand what exactly means depending on the types You do TSTs of that and if it's one of the two is a custom class You might want to call a method and if the other is another kind of custom class
Which is not a class or the first I mean there are a lot of rules like this so I represent it as a Operation like let's get complex operation in blue on the on the right side We have low level language Let's say C in which operation are really low level and very easy to compile if you have a plus B and C
Well, you know, they are integers. It's a one machine like one CPU instruction and And that's how you get the binary later The idea spy is to mix these two levels together. So You have something in which some of the operations are like low level and needs to compile but you still have
This high level logic, which is actually makes quite a nice I claim So you have this graph which contains both kind of operation, but once you have this kind of mental schema Then you can take this and transform This graph into something which is lower level and I call this process red shifting
Because we are removing the blues part and what's left is only there the red part and like Again, I'm going to talk more details what this means, but this is just like an idea of Where we are going?
so We want we start from Python and we tweak some of the semantics of the language in order to achieve that goal and The third the three biggest changes which I made are What I call like a formalization of a process which actually happens in practice which is
The distinction between logic which happens at import time and then what happens at runtime. I'll talk about it later Then the other tweak to the semantics is that if you have a type annotation it's actually enforced so if you have a Variable of a certain type and you assign a
Value of a different type. It's a it's a runtime error like the and this helps the compiler later to assume that this is true and then whenever I have an operation I I split the Semantic of the operation in two step. The first is well, let's understand what this operation means and this is kind of the blue
Code that I was showing earlier. It's all the Actually, what what makes Python better than Java for example from my point of view and then you have the execution phase in which well
Now that we found out that these are two integers and we want to just add them Well, this is very easy to do because but we if we split these two phases Existently then for the compiler. It's much easier to optimize So execution phases Inspire we have
Like formalized these free free stages when whenever you compile a program or execute a program Everything which happens at import time happens at the very specific beginning like it's kind of it's actually what happens already in Python like a lot
of stuff Opens when you import a module, but it could happen at any point in time I can import a module well after 30 seconds of execution in spite is not possible like all the modules are discovered ahead of time and and initialized and Then I have what I call the freeze phase and then well the actual execution of the program
At import time, it's very similar to what's happening like You can do all the crazy stuff that we like in Python you can do Meta classes you can do decorator. You can compute things that are needed later
You can monkey patch your code in case of pytest or something like this So like a lot of stuff which actually useful you can still do them, but then I have well The space which is free is and then I declare that Well, this is over like after a certain point in time
all the fields which are kind of global become frozen and constant and So it means that you can you can monkey patch of class early in the execution, but not at runtime and Now I think that this covers 99% of the use cases anyway
Of course sometimes you really want global mutable data, but you have to annotate it explicitly as variables basically and And then once I have initialized my system. I can just execute it as usual If you have this kind of
Schema then something interesting can happen because I have a lot of global Constants and they operate on them and all the operation which I do want is global constant well, they are kind of the you can optimize them away like If you have an if Uppercase debug statement somewhere and the bug is a constant. Well, you can you know, which bridge branch are you taking?
But it can go farther than this like if you do something which is very dynamic like Get out of a string on a class, but the string is constant. Well, you can do optimize is away if you have a list of URL, you're implementing fast API or something and
This list of URLs is Constant and frozen. Well, you can unroll the loop and and avoid the The hoverhead of the for loop at runtime, so there are a lot of possibilities
It's super important that this phase is kind of transparent to the user like they did the I'm designing the rules in such a way that You don't need to know about this like it naturally flows. Okay, it is constant Well, this operation will always get the same result and then of course when I'm the compiler well
I can optimize it away, but you don't need to notice in order to implement this I'm Developing two things at the same time. I'm developing the interpreter and the compiler, but a trick is that All the hard stuff can happen only at import time and this is kind of it's safe to be slow at that time
so in like the the import time and the partial relation time are run by interpreter which supports the full language and Then what's left after the partial relation time it's like a subset of the language which is actually compilable So the compiler knows only about this this small part. So that's why it's easier to implement and
and and faster and At this stage the interpreter is incredibly simple and incredibly slow like it's AST based It's written in part in Python But again, like it supports the full semantics and also the compiler is very simple
I'm trying to minimize time to market I didn't want to do any Fancier than it needs to be so the simplest thing to do to get executable code is generate C code and use a C compiler And actually TS opens a lot of possibilities right now I can emit the C code and target kind of for free. I kind of target WebAssembly
I can target I can target Emscripten, which is Emscripten WebAssembly in the browser. I can target native code Kind of for free, but the point is that again the compiler doesn't need to support the whole language because the hard part is taken care earlier and
The magic happens at this stage the partial valuation. So imagine to have an AST So you have your program represented as a graph of the tree and then I have a phase in which I go and color all the node and determine whether these nodes are blue which means that I can safely partial evaluate them away because they
They operate for example on constants or do this kind of operation which are guaranteed to be To be optimizable and then I have Reynolds which is what what operates on actual data which varies at runtime and
Redshift is what I was screaming earlier. I transformed this blue plus red graph into a red only graph. I Agree that So far, it's very muddy. It's very foggy. Like let's let's see what happens in practice. So this is the super simple example So I have a functional key which could
Do arbitrary computation in this case. It just does some numeric addition like numeric expression, but I Could download something from the internet here. I could do open a CSV file and do computation. I could do whatever I Annotate this as blue. So it is a blue function. It's guaranteed to be executed
at import time at partial evolution time and That it is this is not executed at It's not seen by the compiler and I can show you Where do I have it? I think it's here So it's blue phone blue funk dot spy
What I can show you is that for example, I I have this red shift phase In which basically I get spy programming input and I emit a spy program in output after this partial evaluation So it's blue from the spy and you see that what's remaining is just is just the function after
Evaluating after calling the blue and you could say okay, but any C compiler can do this that is not Particularly smart and I agree with you But the point is that this is guaranteed like it's not an optimization in the same said that how you hope the compiler will do
It it's guaranteed by the rule of language that this function is called earlier but once we have tears This process and the schema we can do interesting stuff so Imagine a closure like in this example. I have a function which makes another function make other
creates an other function which as One open and fixed so I can create add five and add seven and then call them This is I mean this perfectly normal Python code Like we we kind of that this probably works only surely works also in Python if you remove the blue annotation
But what happens if I So this is make under the spine so what happens if I redshift it and Let's also Try to highlight it
So as you can see they make other closure is gone because it was blue. So it's partially evaluated away What's left are the two concrete functions which contains the concrete values that I I?
Selected so I kind of create a dynamic like they navigate it aesthetically add five and seven and you can see that when I have an here it This is like a special syntax, which I invented to write to signal that I'm calling like a fully qualified Name and also like the lookup. It's another example of of this in Python whenever you look up a name
Well, it it needs to search the namespace the local and the globals and the module and and blah blah But in in spite this lookup can be optimized away So the way I represent in the in the AST is with this fully qualified strings in which I am calling not the add five
Function which is somewhere I'm calling the add five function which is in this module which is called make other and and this doesn't change and When again another thing which flows naturally from it is type checking So here we have something which contains an error. Maybe so I have a function which increments an integer and
I can call it on an integer and but if I call it on a string well That's obviously an error What do you think it happens if I call if I run this because of course I also have an interpreter, right? So I can just run this code. What do you think it happens?
Please someone answer what? Yes, so someone says print 42 I think that someone else will say well error because it's a type error. So it's actually both So if I what's this type error the spy if I try to run it Well, it it prints 42 because I'm not executing this branch
but what's happening is that The the red shifter know that in this branch. This is type error So what's happening is that It creates something like this so the the type check has been partially evaluated away and
It remains what array what was remaining is a race actually after is this this is not implemented yet It will but I actually I'm not I'm not from far from it But once you have this kind of modality you can choose like
We have branches in the code and we know that if you take these branches, then you have this you have a type error And then you can choose what to do. You can choose to have what I call lazy error Which is a behavior very very similar to what you have in Python now, or you can choose to have eager errors Which basically is every time I partial with something and I see there is a static
Like a type error I can well make it a Hard error and fail the compilation. That's actually what any static type language does that's what happens if you do a type error in C or a type error in Java and it's There are values on both if you are doing a refactoring and you are changing the name of the method and you want to run
The test you want to run them one by one and fix things incrementally But if you want to deploy you would like to know all your type errors in advance That's what you do with my PI or PI, right? So you will be able to choose both because there is values in both in both options
so from some point of view whenever Whenever this becomes a static race. Well by default is a warning somehow, but I can turn warnings into errors And I can show you like if I have this code which is type error
I mean what I showed before if I try to run its type error, but if I try to compile For example to native code Then I get well the classic a compiler error that you would expect I'm also spending a lot of time trying to make errors very nice to read and very useful to me because like I don't want
Oh type error like the compiler is trying hard to to make it easier to understand what's going on and Then let's go one step further. So we have type annotations. I mean we have a function which takes
Parameters and these parameters have types But the type well in Python is just an expression and in spy as well I can create Typed functions passing the type as a parameter. So in this
Example, I'm making a function as the function FN and the two parameter it takes well generic type T which is passed from up from From outside and well This is generic C
if I read shift is What I let's let's What I get is that I get to function
specialized on the type and again the specialization happens at partial version time at the redshift time, so basically Automatically from the rules of the language, which I explained before we automatically have genetics It's the equivalent of C++ templates But in a way, which is totally understandable without having to learn about this strange thing
Which are C++ templates, you can totally put a PDB when when I will have PDB Inside inside a function and see what are the values of T because it's a first-class object Currently this is the way you do in the future. I plan to experiment with some syntax sugar. So maybe I
You will be able to write something like this in which the type is actually like in square brackets But I mean this is something for the future. I haven't experimented with it yet But the core logic is there it is like a closure in which some parameters are fixed ahead of time
And you remember when I was talking about operation dispatch Like in Python, there is a lot of logic just fronting That you need to do at every step just to try to understand what to do with operation like a plus B Well, where is the implementation a lot of logic? In spy this is like two steps. The first is the implementation lookup and then I have the actual
I called implementation to do the actual operation and The lookup is based on static types. So if I if you have X plus B X plus Y what you do is to get the two static types of the expression and then I call
This special function which is in the operator module which is up dot uppercase add Which returns a function? Which you can call with the values to do the execution and if the the the the the the cool thing is that?
These three lines are blue So they are part of the semantics, but then they are optimized away. So I in the process of looking up the Operation I can do all the credit stuff that I'm used to do in Python. I can do have descriptors
I can you have all the dander method that I have I can do all the complicated logic I want but I don't pay the cost at runtime. What's what's left at runtime is just the fast execution I Think I have a demo also. Yes open dispatch time
So in this example, I want to show you what happens if I just call the odd Operator and I call it on free in three cases. So what happens if I ask for the implementation of the for I 32 I 32 and then what happens if I want to add two strings and what happens you want to add one string and
A number and you can see that basically in the first two cases It returns a function a built-in function which knows how to add integers and strings But in the last cases well it returns me a not implemented value and
Then the type checker knows that when you do an operation and the end you cannot find an implementation for the operation Well, it's a type error basically. So that's that's how we build up our semantics But it goes farther than this like a get out is just a specific case of this general logic So if I have X dot name
Then basically in spite is becomes equivalent of calling the done uppercase get out on Using name as a string and and with this again with that we can do all the crazy logic that we want we can implement Mmm. I don't take we'll validation we can do all like
SQL alchemy But we using this logic without paying the runtime cost of it Like if if you have been If you follow it my explanation you might have
The question that I'm changing the semantics again here because In Python, they load if you have a function which takes two arbitrary objects And you add any do any operation need? the The actual implementation depends on the dynamic type it depends on what is at runtime like if I do a plus B
well, I can pass both integers and strings and The interpreter knows how to do their core stuff But in spy the operation becomes depends on the static type and the study type Well, it's I don't know what will be at runtime because it might be different. Maybe I have a subclass
maybe I have Again a generic object which could be anything so the the other divergence from the semantics of Python is that if I have A variable of type objects by default it doesn't support much operation well
X plus Y where X and Y are objects it like it's a type error But sometimes it's still useful to have a super dynamic look up because I don't really know in that case Well you can opt in with what with the type which are called dynamic And then it will do the runtime look up of operation basically with dynamic you do the blue and red stuff at
Runtime, but it's it's a penalty that you pay only when you want you don't pay by default that's kind of the idea and We are almost at the end So like this is basically what I have so far something that I didn't say earlier like this super work in progress
So like what I have so far is what I showed so I have this interpreter a compiler Partial evaluation I claim it's kind of the hard part But I still have to build a lot of the language like I don't have lists and they don't have dictionaries So it's not really useful for now, but once you have
Like the basic rules in place like it should be easy to to all it is it's just an just engineering But what with what I have so far I can already See that things are working in the way. I intended so for example. I
I'm trying to write What they call like an FFI for C. So I want to access low-level Pieces of memory as as if it were a C struct so I know that I have 128 bytes and the first
64 are The x field of a point and the second 64 are the y field of a point and I can do it in Python, but if I do it then what you need descriptors And every time you do point dot X or point dot Y. Well you pay all this
Performance and in spy I I can have basically something it is this kind of syntax sugar because it doesn't really work right now but it's just because of syntax like they are like I have this actually running with a slightly different syntax and
Again guarantee it works, so I have this this class point Which has this X&Y which are fields and fields are well? objects with a dunder get which is basically the spy equivalent of the descriptor protocol and Whenever I do point dot X and point dot Y Then I do all this double lookup of blue plus red the blue is optimized away
And what's left is a call of this like in the primitive which I have which is row buffer So row buffer get of int knows how to read from from the machine like from a CPU point of view
64 bits into the register is something that the C compiler can can compile to the single instruction So No, I think it's here. I Told you that like the syntax right now. It's a bit different
This is what I would like eventually, but I don't have so it is it so far I have to write the class it is because I don't support the class the class keyword yet, but If I and you see you have like your function foo which instantiate the point and then does
well set the values and then get the values of X and if I do redshift and Let's also highlight it and then
All the infrastructure for the class and and the code which is kind of low Went away, and what's left is this very low level function, and you see instead of P dot X equals something well
I'm calling By the partial elevator and this just calls row buffer set I 32 using the offset 0 and this is offset for so This is stuff that normally I would have to compute the offset at runtime Which is costly for such an easy operation, but all the expensive stuff was done earlier, and I can also
write it to see and then if I construct dot C This is the what what's generated, but you can see that also you see basically instead of having P
X well, I'm calling basically this function, but this function calls this one again with the offset Which is a constant and this is a macro basically C So it will it eventually it will become like a direct set
So this is the first demo and the second which I still have a few minutes is basically interaction with JavaScript Because I also targeting WebAssembly So for interaction with JavaScript, I would like something like this. I would like
Maybe to be able to do window the document of at element by ID or something and then call And Set attributes, but all this stuff needs to happen on the JavaScript side and I would like to basically translate tears
High-level code automatically into low-level code, which is what I need to do to talk with Justin I don't want to write this code by hand because it's horrible. I want a nice API on top of this low-level code, but I don't want to pay penalties basically In Python what you do is this like III can wrap all JavaScript values into a JS ref
Class and then every time I do a get out then I I call tears JS get out function and then and then drop the result But again in Python all tears is every every layer of abstraction in Python adds runtime penalty
In spy I can do basically tears It's very similar, but I am using this uppercase get out so that the wrapper and unwrapping is basically Done and optimize our way by the partial evaluation so I can
I Can show you that? This code I don't I don't have time to show actually show you but this code automatically becomes tears Which is also going to see so the overhead of this translation is Goes away and well since I am out there here. I can show you that. It's actually working and
I think that's it Where we can go in the future? either say everything super work in progress what
We can use spy for generating web assembly modules we can use pi for generating standalone scripts But in the future I plan to go in the direction of integration with C Python You can use spy for instead of sitem. Let's say to build extensions. I can imagine using spy
with a cinder back and cinder is a Python JIT compiler developed by meta which uses kind of it can use static types to generate better code So I can use spy to remove all the high level of red and and then with cinder Have a fast code, but that's
Stuff which I still need to explore so I think I'm done Okay, a microphone the microphone see a little bit Thank you very much for this very informative talk We have time for a little bit of Q&A we put up two microphones here on the side
So if anybody still has a question after this You can get up to the microphone and ask your question And I also looked at the discord channel where you can follow all these talks at home and the discord channel I have not seen a question yet So, let's see, but we have a
Brave person at the microphone. So please ask your question Hello, the project looks very promising and it's interesting, but I haven't found a reference There we can try it. Oh, I Just
Tried to google it or go it or find it of pi pi and didn't succeed so yeah, so Unfortunate because like the rip I mean the code is open source. The repo is on the top get up commas pi language pi The documentation let's say it's a bit lacking
What happened is that I work in the first lead to arrive at point to have a demo and I did the talk Python a few weeks ago in the US and so I all the code for the demo was kind of by maybe on a spike and now what I'm doing is to
Refactor code from this branch and put it into reasonable code and then I will well document But yes, basically You can try to clone this repo and look at the test, but that's the best I can or you can find me
Around and I can show you basically. Yep. Thank you very much for the question at the other microphone. Please ask your question Really interesting project. I just had one question that I see that with spy you kind of regenerate some code and I'm worried. Would you not run into the same problems that you run into with templates in C++ where there's
Too much generated code and then it's yeah, it's quite a lot of stuff And also like how would you debug it? How do you how would you debug, you know, and you have an issue here? How would you debug the generated code or how would it go? So yes
Every every language with the genetics as this problem So if you are not careful, you cannot can end up with code blood rust does a good job at merging back Code which which Which is like generic but then it can be shared so I I hope to be able to do something like that
But then it really depends at some point. It depends on you. Like if you If you know what you are writing and you want maximum performance But you have to specialize I imagine that you are numpy and you want you want you want to write
Operation on arrays you want to specialize them on your type so you you must dust is Like on specialization, but in other cases, you you know that this is not On a path which is super important for preference So can just you can use the dynamic type then you don't specialize and you pay the penalty at runtime
But it's fine. So what you will have control on it Thank you very much. We have time for one final very brief question. I Kind of like oh, I don't know pi pi used to I
Supposing you're it's possible. I don't think it's a good idea so I Lot of the idea from spy come from our Python which was like the implementation language for pi pi our Python was Didn't use type annotation and it used like full program analysis to do type inference
Which in theory seems seems like a good idea, but in practice it was not because That's okay we were running out of time so at this point I would just like to thank the speaker and Tonya Kuno again Let's have another round of applause. Thank you