ajb 20 hours ago

It's weird, but the pain of moving to a whole new language seems less than the pain of using one of these language subsets. I guess it might be because of "loss aversion": we dislike losing something we have more the value we put on gaining it. In a new language each newly added feature is a gain, but in a language subset you're always encountering things you would have in the full language. So no matter how good the rational case is, there is a bias against them. I can't think of a successful one actually - anyone?

  • getnormality 20 hours ago

    The author seems to speak to that here:

    > SPy does something different: on one hand, it removes the dynamic features which make Python "slow", but on the other hand it introduces new features which make it possible to implement and use the same pythonic patterns which we like.

    The author seems unusually focused on explaining his new way, which may help it feel more like a new language with a coherent philosophy and unique benefits in its own right.

    • jhbadger 14 hours ago

      Not unlike how Crystal isn't really "compiled Ruby" but rather its own language that just looks and feels similar to Ruby.

  • pansa2 20 hours ago

    > in a language subset you're always encountering things you would have in the full language

    Exactly. I once pitched the idea of a Python subset (with a different focus, not performance like SPy), and almost every reaction was "will it support <favourite Python feature / favourite library>".

    For example, a new language can build its own solution for array math, or maybe that's not something its users need. OTOH many consider a Python subset to be unacceptable if it doesn't specifically support NumPy.

    In the end I came to agree with https://pointersgonewild.com/2024/04/20/the-alternative-impl...:

    > positioning your project as an alternative implementation of something is a losing proposition

    > don't go trying to create a subset of Python [...] Do your own thing. That way, you can evolve your system at your own pace and in your own direction, without being chained by expectations that your language should have to match the performance, feature set, or library ecosystem of another implementation.

    • semi-extrinsic 3 hours ago

      I think Python is a bit special in this case, as many people tend to use it more like duct tape for connecting different libraries (which often contain compiled and optimized code) rather than a language for doing stuff bottom-up.

    • HanClinto 16 hours ago

      I can see the wisdom in this.

      As a counter-example, it feels as though Typescript has managed to (largely?) succeed as a subset of Javascript, so maybe the "do your own thing" isn't entirely a lost-cause -- maybe it's just really really difficult?

      • dec0dedab0de 16 hours ago

        Typescript is a superset of javascript

        • HanClinto 15 hours ago

          Aaah, you are correct -- I had that backwards. All Javascript is indeed valid Typescript, but not all Typescript is valid Javascript.

          Appreciated

  • PaulHoule 17 hours ago

    One of the standard architectures for complex applications is to put together a scripting language and an systems programming language. You can either look at the scripting language as primary with the systems language used for performance or hardware interfacing or you can look at the systems language being primary and the scripting being used around the edges.

    The model of having a closely related scripting and systems language would be an optimization of this and SPy seems like an answer.

    [1] AAA games that have a scripting engine on top of C/C++, a finite element solver that lets you set up a problem with Lua and solve it with FORTRAN, etc.

    • thomasmg 15 hours ago

      Yes, there are quite many real-world cases of this architecure. But, wouldn't it be better it the same language (more or less) can be used for both? I don't think such a language exists currently, but I think it would be a nice goal.

      • sophrosyne42 15 hours ago

        Oxcaml, of course.

        • thomasmg 14 hours ago

          Interesting, I was not aware of OxCaml. (If this is what you mean.) It does seem to tick a few boxes actually. For my taste, the syntax is not as concise / clean as Python, and for me, it is "too functional". It shares with Python (and many high-level languages) the tracing garbage collection, but maybe that is the price to pay for an easy-to-use memory safe language.

          In my view, a "better" language would be a simple language as concise as Python, but fully typed (via type inference); memory safe, but without the need of tracing GC. I think memory management should be a mix of Swift and Rust (that is, a mix of reference counting and single ownership with borrowing, where need for speed).

  • dec0dedab0de 18 hours ago

    I would say that Rpython is successful. However, it's primary goal is to be whatever the PyPy developers need to write PyPy.

    I totally agree about subsets though, I would much rather have a superset like Cython, but that has it's own challenges for compatibility if you wanted to have a "pure python" version of the same library. Which is why I really like that Cython is using typehints now.

    • ajb 17 hours ago

      Yeah Rpython escapes this as most people don't write it directly.

      Micropython is another example. No-one expects micropython to support numpy. They're just happy to get away from C. But where you can use the full python, you wouldn't use micropython.

  • netbioserror 19 hours ago

    Throwing my hands up and moving to Nim was downright easy next to the excessive effort I put into trying out Nuitka, Numba, and PyInstaller for my use case. If you want static compilation, use a language and libraries built with that assumption as a ground rule. The herculean effort of building a half-compatible compiler for a dynamic language seems like a fool's errand, and would be a fun curiosity if so many people hadn't already tried it, especially with Python.

    • rangerelf 16 hours ago

      I was looking for someone else that had done this, I had the same exact experience.

      That said, anyone looking into a completely static typed language that has nice ergonomics, is easy to pick up but has enough depth to keep you busy for weeks on end, and is versatile enough to be used for anything, do yourself a favor and give Nim a try.

      https://nim-lang.org/

    • PaulHoule 17 hours ago

      It's so common for something like this to struggle for decades before succeeding.

      For instance people have been trying to make a memory safe C for a long time, just recently we got

      https://fil-c.org/

      which has high compatibility and relatively good performance for that kind of thing. The strength of Python is that so many people are trying things with it.

    • almostgotcaught 16 hours ago

      all of this is well and good if you completely forget that there are billions of lines of Python in prod right now. so your grand epiphany is basically on the level of "let's rewrite it in Rust". i'll let you hold your breath until that rewrite is done (and in the meantime i'll explore workarounds).

      • rangerelf 16 hours ago

        I kind of object to this take.

        Nobody's talking about porting billions of lines of code, for all we know it's just for personal projects, or a learning experience.

        This kind of replies is like killing an idea before it's even started, smells like the sunk cost fallacy.

        OTOH I do understand the weight of a currently existing corpus in production, evidence is the ton of COBOL code still running. But still, your reply kind of sucks.

        • almostgotcaught 10 hours ago

          > Nobody's talking about porting billions of lines of code, for all we know it's just for personal projects, or a learning experience.

          am i the only person in the room that can read tone? please tell me what is the force of this statement in what i've responded:

          > If you want static compilation, use a language and libraries built with that assumption as a ground rule.

          is this an imperative only for hobbyists? not sure.

          > This kind of replies is like killing an idea before it's even started, smells like the sunk cost fallacy.

          there is no idea - that's exactly my whole point. tear it down and build it again is not an idea.

      • ajb 15 hours ago

        Now there are billions of lines of python in production. But it wasn't so long ago that it seemed like the entire industry was going to completely standardise on C++, and if you wanted a picture of your future, it would be grinding away debugging buffer overflows and thread lockups - forever.

      • netbioserror 16 hours ago

        I finished the rewrite in just a few months and have been happily maintaining it for two years and extending it with powerful features it never had before, partially thanks to optimized native binary speed, partially thanks to the ludicrous compatibility of a musl-libc static binary. The rewrite is the backend foundation of a web product stack that is best-in-category.

        I didn't choose Nim because I was an evangelist; I had only toyed with it twice before. After much evaluating (and wrestling an ultra-frustrating previous attempt at a Rust rewrite my predecessor had tried), Nim surfaced as the best tool for the specific job. And it still is. It doesn't have to be our entire product stack; it's doing a small subset of very important jobs, doing them well, and is invoked by other languages that do their jobs better as web servers and such. A modular stack helps each language and tool shine where it works best.

mpweiher a day ago

Looks very interesting!

I remember chatting with one of the creators of PyPy (not the author of TFA) a number of years ago at HPI. He had just given a talk about how RPython was used in PyPy development, and I was fascinated.

To me, it seemed completely obvious that RPython itself seemed like a really interesting standalone language, but he would have none of it.

Whenever I suggested that RPython might have advantages over PyPy he insisted that PyPy was better and, more strangely, just as fast. Which was sort of puzzling, because the reason given for RPython was speed. When I then suggested that they could (after bootstrap) just use PyPy without the need for RPython, he insisted that PyPy was too slow for that to be feasible.

The fact that both of these statements could not really be true at the same time did not register.

  • albertzeyer a day ago

    I have asked about using RPython as a generic standalone language before. I think the official statement is that is was never intended to become one, and it's really a very minimal subset of Python (so basically no existing Python code will run, it would require heavy refactoring or complete rewrite), and it's only specifically those features that they currently need, and it might also be a moving target, and they don't want to give certain guarantees on stability of the language etc.

    Once you consider that you anyway need to write very different kind of code for RPython, then maybe just using Nim or some other language is a better idea?

    • kombine 12 hours ago

      A general purpose language should be suitable to writing its own compiler. If it's to slow for that, what's the point?

      • Hasnep 3 hours ago

        A language can be suitable for writing a compiler, but if there is another language that's 10x faster that's also suitable, then you're losing out on a lot of compilation speed for no reason.

        Dog-fooding a language by writing a compiler in it can lead to the designers adding language features to make compiler development easier, even if they detract from the design of the language for the 99% of users who aren't writing a compiler.

  • getnormality 20 hours ago

    I'm not quite seeing the contradiction either? I sort of get that you're pointing out some kind of tension, but it's not obvious that there's a contradiction. The statements involved don't seem to be interpretable in a self-contained way.

  • zahlman 20 hours ago

    I had understood that the only reason for RPython's existence was that bootstrapping was (or at least seemed) impossible without it... ? Although I didn't dig into that claim, either.

sevensor a day ago

Neat idea! Author’s ideas about different subsets of Python are worth the price of admission. What you can express in the type system, what performs well under JIT, what’s basically same and reasonable, may not be precisely specified, but are still useful and distinct ideas.

ic_fly2 16 hours ago

If in the end we can just have .spy on some files that have performance critical functions in them and the rest is just normal python, this could be down right amazing.

We recently swapped out mypyc optimised module for a rust implementation to get a 2-6x speed up, and not having to do that would be great.

  • adsharma 8 hours ago

    See my other comment in the thread. I would argue that anything that uses arcane dynamic stuff in python should be renamed to .dpy and the vast majority of the commonly used constructs retain .py

    The issue in HN threads like this is that everyone is out to promote their own favorite language or their favorite python framework that uses dynamic stuff. The majoritarian and hacker-ethos of python don't always line up.

    Like Chris Lattner was saying on a recent podcast, he wrote much of Swift at home on nights/weekends over 18 months. We need someone like that do this for spy.

  • oofbey 12 hours ago

    +1 this.

    Also, when I read about the language features which make Python intrinsically slow, generally I think "I never use that." e.g. operator overloading meaning you need to do all these pointer dereferences just to add two numbers together. Yes, I get that pytorch and numpy rely critically on these. But it makes me wonder...

    Could you disable these language features on a module-by-module basis? That is, declare "in this sub-tree of the source code, there shalt be no monkey-patching, and no operator overloading" and therefore the compiler can do a better job. If anybody tries to do the disallowed stuff, then it's a RuntimeError. Would that work?

cardanome a day ago

Common Lisp also allows you to redefine everything at runtime but doesn't suffer from the same performance issues that Python has, does it?

Doe anyone have insight into this?

  • a-french-anon a day ago

    Common Lisp doesn't use (expensive) CLOS dispatch in the core language, e.g. to add two numbers or find the right equality operator. That's one known pain point due to CLOS having been "bolted-on" rather than part of the language which makes the divide between internal (using typecase and similar) and external (generic functions) dispatch pretty ugly; and gave use the eql/equal/equalp/etc... hell.

    Thing is that you need a complex JIT like Julia's or stuff like https://github.com/marcoheisig/fast-generic-functions to offset the cost of constant dynamic dispatch.

    I actually had such a conversation on that comparison earlier this year: https://lwn.net/Articles/1032617/

    • majoe 16 hours ago

      > Thing is that you need a complex JIT like Julia's or stuff like https://github.com/marcoheisig/fast-generic-functions to offset the cost of constant dynamic dispatch.

      Julia is always the odd one out, when talking about dynamic vs. static dispatch, because its JIT compiler acts more like an Ahead-of-Time compiler in many regards.

      In the best case, types are statically decidable and Julia's compiler just produces a static dispatch and native code like e.g. a C compiler would.

      In the worst case, there are a big (or unlimited) number of type candidates.

      The grey area in between, where there are a limited number of type candidates, is interesting. As far as I understand, Julia does something similar to the link you provided. Based on some heuristics it will compile instances for a "sealed" number of candidates and fallback to a fully dynamic dispatch, if there are two many type candidates.

      At JuliaCon 2025 there was an interesting talk about this topic: https://m.youtube.com/watch?v=iuq534UDvR4&list=PLP8iPy9hna6S...

      For the worst case scenario, Julia chooses what's in my regard the nuclear option: If the types are not decidable, it just ships the whole compiler with your code and tries again at runtime. But I guess, that's not the only possible solution. Presumably, it would also be possible to fallback to a Julia interpreter for dynamic code. That would be more similar to what JavaScript is doing, just the other way around. Instead of interpreting the majority if the code and optimising hot paths with a JIT, our alternative Julia would compile most code statically and use the interpreter for the dynamic parts.

    • martinflack 20 hours ago

      > and gave use the eql/equal/equalp/etc... hell.

      You don't like those? I've always considered them a fairly elegant deconstruction of the problem domain of equality checking. DWIM languages can get very confusing when they DWIM or don't DWIM.

      • a-french-anon 19 hours ago

        Where's the elegance? Equality is well defined on everything handled by those three, since they only compare the same types without doing coercion. Plus, you can't extend these to handle user types.

        Which is why https://cdr.common-lisp.dev/document/8/cleqcmp.html exists, really; all the "copy-x" would benefit from the same fix, in my opinion.

  • brabel a day ago

    Common Lisp is not a runtime, it’s a specification. Implementations are free to compile everything to fast native code, or to interpret everything. Various available implementations do that and everything in between. That said , SBCL and the commercial implementations can be extremely fast, especially if you specify types on tight loops. SBCL comes with a disassembler that shows you right in the REPL the Assembly a function compiles to so you can even get close to C performance.

    • pjmlp 19 hours ago

      Addedum that having a disassembler is quite common language primitive in most compiled Lisps, since early days.

  • pjmlp a day ago

    Just like Smalltalk and SELF, also Lisp Machines and Interlisp-D.

    Usually comes down from a urban myth that Python is special and there was no other dynamic language before it came to be.

    The JIT research on those platforms is what gave us leading JIT capabilities on modern runtimes, OpenJDK HotSpot traces back to Smalltalk and StrongTalk, while V8 traces back to SELF.

    Especially in Smalltalk and SELF, you can change anything at any time across the whole image, and have the JIT pick up on that and re-optimize.

    Granted what messes up Python, or better said CPython implemenation, is that C extensions are allowed to mess up with its internals thus making void many possible optimizations that would be otherwise available.

    A reason why JVM, CLR, V8, ART make use of handles and have marshaling layers not allowing such kind of liberties with native extensions.

    • vidarh 19 hours ago

      > Granted what messes up Python, or better said CPython implemenation, is that C extensions are allowed to mess up with its internals thus making void many possible optimizations that would be otherwise available.

      I'm doing a Ruby compiler (very, very slowly, though faster again now with Claude Code doing most of the heavy lifting), and the same issue with Ruby has made me seriously toy with the idea of one day embedding a C compiler so that the Ruby compiler can optimise across both (it'd still have to deal with linking to third party C code, of course, which is one reason I'm hesitating) as a simple not-so-optimizing C compiler is like a trivial toy compared to compiling Ruby where just the parser makes you want to claw your eyes out, but it'd at least widen the surface a bit.

      • pjmlp 15 hours ago

        Have you seen how TruffleRuby makes use of LLVM bitcode, to ship C compiler as well?

        • vidarh 11 hours ago

          I haven't, but not surprised given some of the very aggressive (in a good way) things they've done to address performance. It's impressive. I spoke to Chris Seaton back when it was getting started, and loved many of the things they were doing. Personally I want something leaner, and self-hosting, but that's also why mine is still experimental and wildly incomplete and TruffleRuby works for a lot of things.

    • gjvc a day ago

      Great explanation. Five years ago I did the genealogical work to discover that StrongTalk begat HotSpot (by virtue of having some of the same authors) It was quite a joy to discover!

falcor84 a day ago

This seems to be going for a somewhat similar goal to Mojo [0] - anyone here who used both and is willing to offer a comparison?

[0] https://www.modular.com/mojo

  • miohtama a day ago

    Based on my understanding, Mojo aims to make number crunch computation faster (GPU), while as SPy aims to make generic Python application logic faster. Very similar, but different sweet spots and use cases.

    • ivell a day ago

      While GPU is a focus of Mojo, it is also planned to make it a general system programming language similar to C++ and Rust.

    • skavi 16 hours ago

      Your understanding of mojo is incomplete. Just visiting their website would have cleared that up.

      • falcor84 2 hours ago

        Taking that on a tangent, there's the seed of a very interesting sci-fi story in a world where visiting a website is sufficient to give people a complete understanding of something.

        EDIT: thinking about it some more, I would say that there isn't any real barrier with current technoly to having a relatively small on-device LLM downloading a LoRA file from an arbitrary site to get the AI equivalent of "I know Kung-Fu" - the real issue would be on the safety, security and trust aspects.

graemep a day ago

The problem with this is that the main value of Python is its ecosystem. SPy aims to be able to import Python libraries, but also not implement all Python features. If you are not 100% compatible how can you reliably import libraries?

SPy seems most likely to be more likely to be appealing as a more Pythonic alternative to Cython rather than a Python replacement.

  • antocuni 21 hours ago

    hello, author of the blog post and author of SPy here.

    > how can you reliably import libraries?

    the blog post specifies it but probably not in great level of detail. Calling python libs from spy will go through libpython.so (so essentially we will embed CPython). So CPython will import the library, and there will be a SPy<=>CPython interop layer to convert/proxy objects on the two worlds.

    • graemep 20 hours ago

      Thanks for the answer. I have to admit I missed the implications of embedding libpython. Sounds great.

  • rurban 21 hours ago

    I did a similar project, a typed perl. cperl. I could import most the modules, and did add types to some of the important modules. Eg testing was 2x faster. I needed typing patches for about 10% for most CPAN packages.

    A type is a contract, not a hint!

    • setopt 21 hours ago

      > A type is a contract, not a hint!

      In Python it is a hint.

      • rurban 21 hours ago

        Exactly. That was their worst mistake ever

        • setopt 15 hours ago

          I agree. I use Beartype to get runtime type checks, but it shouldn’t be necessary. Some support for type checking, whether at byte compile time or runtime, should land upstream.

          • almostgotcaught 4 hours ago

            Never gonna happen - the fundamental premise of the language is duck typing.

            • setopt 29 minutes ago

              Either you add type hints to your function and should expect it to be type checked, or you don’t add type hints and remain free to use duck typing as you want.

              But not receiving as much as a warning when you violate type hints is the worst of both worlds.

              Duck typing isn’t completely incompatible with type checking btw. Haskells type classes are an elegant solution to that, for example.

              • sevensor 2 minutes ago

                Python protocols work great for duck typing as well. You can specify exactly how an object has to quack without constraining it to an avian family tree.

intalentive 14 hours ago

As a prospective user the first thing I look for is lists, list comprehension, list slices, string methods, zip, zip*, tuple destructuring, generators, dicts and sets. These data structures, their syntax, and associated methods are what make Python a joy to use. They are what make it possible to solve a puzzle in a one-liner.

The examples in the playground are neat but I don’t see any of the Python bread and butter usage. I see C with Python syntax.

I’d like to see Python syntax solving a problem in a pythonic way, albeit with type annotations. And then I’d like to see the compiled version run 30x-100x faster. Is that ultimately the promise of this project?

  • antocuni 13 hours ago

    yes (work in progress :))

rcarmo 3 hours ago

…with WASM as a target. Hmmm. I would prefer it output C, or something I can link to other native code.

kilibe 4 hours ago

How do you envision SPy's generics evolving to handle something like SQLAlchemy-style query builders, where dynamic introspection is key? Eager for the next posts on the type system and static dispatch—already forking the repo to tinker with that raytracer demo. Thanks for open-sourcing this under Anaconda's wing; it's the kind of ambitious reset Python needs.

jszymborski 17 hours ago

While obviously this would need CPython to SPy `import` support for it to displace CPython for me, it seems like you can `import` SPy to CPython, which makes it an attractive solution for implementing fast libraries where Rust is perhaps too heavy duty.

  • intalentive 15 hours ago

    Seems correct. See point.spy in the playground here: https://spylang.github.io/spy/

    # - the unsafe module allows C-level direct memory access to pointers and unsafe arrays

    # - @struct maps directly to C structs

    # - most users will never have to deal with this directly: using the unsafe` module is the equivalent of writing C extensions or using Cython

nickcw a day ago

This looks like a very interesting approach bringing comptime to a static version of python. This version of comptime can then be used to define new types in the same way Zig does it.

I absolutely hate the terminology though red/blue redshifting etc. Why do blue functions disappear when redshifting? If you red shift blue then it goes down in frequency so you might get green or red. Perhaps my physics brain is just over thinking it!

> The other fundamental concept in SPy is redshifting.

> Each expression is given a color:

> blue expressions are those which can safely be evaluated ahead of time, because they don't have side effects and all operands are statically known.

> red expressions are those which needs to be evaluated at runtime.

> During redshifting we eagerly evaluate all the blue parts of the code: it's a form of partial evaluation. This process plays very well with the freezing that we discussed above, because a lot of operations on frozen data become automatically blue: for example, if we statically know the type of an object, the logic to look up a method inside the frozen class hierarchy is a blue operation and it's optimized away, leaving just a direct call as a result.

Please just rename it comptime then at least people who have learnt Zig will know what it means immediately.

In FORTH these would have been called IMMEDIATE words. Namely functions which run at "compile" time rather than run time.

  • antocuni 21 hours ago

    hello, spy author here.

    > Why do blue functions disappear when redshifting? If you red shift blue then it goes down in frequency so you might get green or red. Perhaps my physics brain is just over thinking it!

    yes I think you are overthinking :). It's not meant to be accurate physics of course.

    The usage of colors to distinguish comptime vs runtim code comes from PyPy: in that context, we used "green" and "red", and initial versions of SPy used the same convention.

    Then someone pointed out that green/red is not colorblind friendly and so I changed it to blue.

    Having actual colors for the two phases is VERY useful for visualization: e.g. we already have a "spy --colorize" command which shows you which parts are blue and which are red.

    As for "redshifting": the AST "before" has a mixture of blue and red colors, while the AST "after" has only red nodes, thus the final AST is "more red" than the first one, that's why I chose that name.

__mharrison__ 19 hours ago

This is really cool and what I thought mojo would be. The subset of Python that is easy to use, read, and removes the dynamic nature that we don't use.

Excited to see where this goes.

adsharma 19 hours ago

++spy ethos and ideas

But why limit to an interpreter? Translate to other excellent compiled languages and benefit from the optimization work there.

Giving up on C-API and the dynamic parts of python that 1% of the people use is a good trade-off.

In the age of cursor and windsurf it's not hard to auto replace incompatible code with something that works in the static-py ecosystem.

Would love to participate in an effort to standardize such a subset.

  • rich_sasha 19 hours ago

    I'd imagine a lot of packages that you may want to use make deep use of some of these obscure features. So much magical "it just works" of Django is surely various kinds of deep introspection.

    Not sure an AI can fix it yet. It's not just adding type annotations.

    • adsharma 16 hours ago

      The position I take is that such obscure code in the guts of a popular package could be slowing down large amounts of deployed code elsewhere. If such code must exist, it should be marked as special (like how Cython does it).

      Beyond adding type annotations, there are other important problems to solve when translating python to rust (the most popular path in py2many so far).

        * Translating inheritance -> traits
        * Translating exceptions -> Result<T>
        * Handling incompatible pattern matching
      
      This is why I've urged FastAPI and pydantic maintainers to give up on BaseModel and use fquery.pydantic/fquery.sqlmodel decorators. They translate much better.
  • nusl 19 hours ago

    There is a compiler detailed in the page on the link;

    > 3. We have a compiler for deployment and performance. The interpreter and the compiler are guaranteed to produce the exact same results at runtime.

    • adsharma 16 hours ago

      Where is it? Would love to compare the approach to py2many.

      • intalentive 15 hours ago
        • adsharma 7 hours ago

          Py2many would fail to compile dynamic code whereas spy runs it through the interpreter.

          Otherwise the internal structure looks similar. Py2many has been around for 10+ years under previous names and has significant test coverage.

wodenokoto a day ago

I like the idea of a compiled language that takes the look and ethos of Python (or at least the "looks like pseudocode, but runs"-ethos)

I don't think the article gives much of an impression on how SPy is on that front.

  • walterlw a day ago

    I believe that Python is as popular and widely used as it is because it's old enough to have an expansive ecosystem of libraries. It's easy enough to implement one in pure Python and possible to optimize it later (Pydantic is a great recent-ish example, switching to a Rust core for 2.0). That same combination of Python + (choose a compiled language) makes it quite difficult for any new language to tap into the main strength of Python.

    • ReflectedImage 13 hours ago

      Python is popular because of it's expansive ecosystem of libraries, which only exist because the language is duck typed. If it was statically typed, the expansive ecosystem of libraries wouldn't exist.

      There is a factor of 3x difference in dev speed between the two typing systems.

    • rangerelf 16 hours ago

      It's not just its age, it's how easy it is (was?) to jump in and start writing useful code that could be revisited later on and be able to read it and understand it again.

      All of these efforts to turn it into another Typescript are going to, in the end, kill the ease of use it has always had.

  • greener_grass a day ago

    This is what F# provides.

    F# has a similar whitespace syntax to Python, but is statically typed and can be compiled AoT.

    Bubble sort Python:

        mylist = [64, 34, 25, 12, 22, 11, 90, 5]
    
        n = len(mylist)
        for i in range(n-1):
          for j in range(n-i-1):
            if mylist[j] > mylist[j+1]:
              mylist[j], mylist[j+1] = mylist[j+1], mylist[j]
    
        print(mylist)
    
    
    
    Bubble sort F#:

        let mylist = ResizeArray [ 64; 34; 25; 12; 22; 11; 90; 5 ]
    
        let n = Seq.length mylist
        for i = 0 to n - 2 do
          for j = 0 to n - i - 2 do
            if mylist[j] > mylist[j + 1] then
              let temp = mylist[j]
              mylist[j] <- mylist[j + 1]
              mylist[j + 1] <- temp
    
        printfn "%A" mylist
    • stOneskull 20 hours ago

      Nim:

        var mylist = [64, 34, 25, 12, 22, 11, 90, 5]
      
        let n = mylist.len
        for i in 0..n-2:
          for j in 0..n-i-2:
            if mylist[j] > mylist[j + 1]:
              swap(mylist[j], mylist[j + 1])
      
        echo mylist
  • summarity a day ago

    You can have that today with Nim.

    • Imustaskforhelp a day ago

      Nim feels like a really amazing language. There were some minor things that I wanted to do with it. Like trying to solve a codeforces question just out of mere curiosity to build something on top of it.

      I felt like although it was similar to python. You can't underestimate the python's standard library features which I felt lacking. I am not sure if these were skill issues. Yes these are similar languages but I would still say that I really welcome a language like SPy too.

      The funny thing is that I ended up architecting a really complicated solution to a simple problem in nim and I was proud of it and then I asked chatgpt thinking no way there can be anything simpler for it in nim and I found something that worked in 7-10 or 12* lines and my jaw dropped lol. Maybe chatgpt could be decent to learn nim imo or reading some nim books for sure but the packages environment etc. felt really brittle as well.

      I think that there are good features of both nim and SPy and I welcome both personally.

      • summarity 17 hours ago

        GPT is amazing at Nim. Ive used it to find a subtle bug in a macro that’s hundreds of lines of code.

    • odie5533 16 hours ago

      There don't seem to be great web frameworks like Flask, Django, or FastAPI for Nim.

tonyplee 17 hours ago

The feels like JS -> TS type of change on JS side, except that was done with transpiler (sp ? ).

srean a day ago

If you want different parts of your code to be a statically typed Python lookalike Cython is a mature option

  • leobuskin a day ago

    Yes, it's mature, but you (and your potential audience) basically need to learn a new language, a lot of quirks and "weird" (I'd even say counter-intuitive) nuances, and it's also significantly less readable in comparison with strict and typed Python. Even its modern syntax doesn't click immediately (also performance wise the new syntax somehow is a bit slower in my tests)

    • srean 21 hours ago

      I am by no means a Cython fanboy but I think you are exaggerating the syntactic differences and readability differences.

      Apart from type annotation they are very minor, well worth the speed benefits and type-error benefits. Given that we are discussing it in the context of SPy, SPy is not fully compatible with Python either, which is quite understandable and in my opinion a Good trade-off.

      The benchmarking features are great, interactivity with C libraries is great.

      One annoyance I have with Cython though is debuggability. But it's an annoyance, not a show-stopper.

      Have used in production without problems.

seg_lol 10 hours ago

It is has been a hot minute and no one has mentioned ChocoPy, which is basically this project. https://chocopy.org/

The author invents so many terms, I don't want to uncharitably ascribe this to anything, but they should use existing terminology.

peter_d_sherman 3 hours ago

>"During the years there have been many attempts to improve Python speed; generally they fall into two categories:

Implement "full Python". To be able to support all dynamic features and be fast, they usually employ a Just In Time (JIT) compiler.

Examples are PyPy, GraalPy, Pyston, and CPython's own JIT.

Implement a "subset of Python" or "variant of Python", either as an Ahead of Time (AOT) or JIT compiler which is able to produce fast code. The usual approach here is to remove many (if not all) of the dynamic features which make Python hard to compile.

Examples are RPython, Mypyc, Cython and Numba.

The problem of "full Python" JIT compilers is that sometimes they work very well and produce huge speedups, other times they don't produce any speedup at all, or might even introduce slowdowns, or they might use too much memory, or they are slow to "warm up".

The problem of the subset/variant approach is that by removing the dynamic features of Python, you end up with something which does not feel pythonic, and in which many typical and idiomatic Python patterns just don't work. You often end up with "Java with Python syntax" (nothing in particular against Java, but I hope it gives an idea of what I mean)."

Isn't that interesting!

You know what I'd love to see?

A Python compiler that works on a function-by-function basis...

That is, for each function, make the determination if a straight "clean" compilation of the function is possible -- that is, if it doesn't use special Python features that make compilation difficult/challenging/complex/impossible -- or have dependencies on other functions that do...

So if you have a Python function that adds simple integer variables, let's say, then that can be converted to C or Assembler or VM or LLVM or QBE code in a straightforward way, but if a function uses objects and lambdas and higher-level/complex constructs in a way that makes compilation challenging, complex or impossible, then flag those functions (write them out in a log, so the programmer could optionally simplify them, etc.) -- those will continue to be interpreted like they always are...

Yes, some or all of that infrastructure might already exist... I'm just thinking aloud... :-)

>"The first problem is that Python is extremely dynamic. I'm not talking only about dynamic typing, but also about the fact that in a given Python process, the "world" is a moving target and "everything can change at any time" "

(If we had a future language that supported both interpreted and compiled functions, then the interpreter should have the concept of "locked" functions and objects -- that is, once the compiler has compiled something, it's now "locked", and changes (if we want to keep it dynamic) to it mean invoking the compiler again post-change, at runtime... it would be messy, but there could be a hybrid dynamic interpreted yet JIT compiled language... but it would require runtime interaction between the interpreter and compiler... which could be messy, to say the least... and yes, some of that infrastructure might already exist...)

AmazingTurtle a day ago

> SPy is [...] a compiler

> SPy is not a "compiler for Python"

I think it's funny how it's confusing from the first paragraph

  • ForceBru a day ago

    Reading the next sentence clears the confusion:

    > SPy is not a "compiler for Python". There are features of the Python language which will never be supported by SPy by design. Don't expect to compile Django or FastAPI with SPy.

    • AmazingTurtle 21 hours ago

      Yeah but then don't say that SPy is a (interpreter and) compiler in the first place? Just say it's a interpreter.

      • yorwba 21 hours ago

        It is a compiler. It is not a compiler for Python, because there are valid Python programs it can't compile and isn't intended to compile.

      • Hasnep 20 hours ago

        You can think of it like this:

        SPy is a compiler. SPy is not a compiler for OCaml. SPy is not a compiler for COBOL. SPy is not a compiler for Python.

  • amelius a day ago

    To make it more confusing: SPy is not spyware (at least, I hope)

toast_x 19 hours ago

i thought this was super cool and informative thank you so much for writing it.

i work a lot in python and tried to build a runtime type checker for it that basically acted as automatic assertions on all stated types at function boundaries, and it worked really well to bring all TypeErrors in my code to the surface on first run.

but, my knowledge is woefully short on compilers and languages. this definitely gave me a great frame of understanding, so thanks again for writing it

ksk23 a day ago

Good level of detail (for me) to understand (some things).

ltbarcly3 17 hours ago

Statically typed. That's just Java with python syntax again, which the article tries to talk it's way out of but that's what it is.

  • Smaug123 15 hours ago

    This assertion is so vague as to be meaningless - say more? You're presumably not asserting that all statically typed languages are fundamentally Java, because that would be saying the patently false "C and Haskell are fundamentally Java". Are you specifically saying the article's hope that it's not "Java with Python syntax" is misplaced; if so, why?

    • ltbarcly3 13 hours ago

      Python, if you take away dynamic typing, is very Java like. No pointers, functions/methods always pass by reference, immutable strings, always garbage collected, etc. So if all you did was require static typing in Python, but changed nothing else, it will end up with a lot of java semantics (even if the syntax itself is different).

ranger_danger 18 hours ago

I'm still looking for a python-ish (at least the syntax) embeddable library for C that is easy to include in a project, a library that does not have its own build system with dozens of files... but I don't think one exists.

IshKebab 19 hours ago

Overall this looks very interesting - I always thought more could have been done with RPython, but there was never any documentation for it. I do have some nits though:

> The following silly example happily passes mypy

In fairness that's because Mypy is shit. Pyright catches this mistake.

> As such, we need to treat Python type checkers more like linters than actual theorem provers

Again I think this is true of Mypy but Pyright is much closer to a sound type checker.

> redshifting

This is just constant propagation isn't it? C compilers have been doing this for decades. I don't think we need a silly new term for it. Let's not cause another "tree shaking" situation.

> So far, this is not different than usual constant folding, with the difference that it's guaranteed to happen. What makes it more powerful is the ability to mark some functions as @blue.

That's not different. It's just constant folding with C++'s `consteval`. And @blue is an absolutely abysmal name.

It would be much clearer if @blue were changed to @consteval or @comptime (either's good I think), and you just call it "compile time evaluation" or "constant propagation" instead of "redshifting".

vidarh 19 hours ago

I sympathise with the motivations for this, though I don't use Python much. I occasionally work on a toy Ruby compiler that started as a long blog series. More recently I've picked it up again with heavy AI use - I set Claude working on improving Rubyspec pass rates (which are atrocious). It's chugging along right now, actually.

One of the things I've spent a lot of time thinking about are the ways to avoid a lot of the dynamic features of Ruby without affecting actual, real code much.

There's a lot that can be done there - e.g. all of the research on Self and JS VMs is highly applicable.

But I say "real code" because a lot of the "worst" dynamic features of Ruby (and Python) either doesn't appear in production code very often, or at all (there are still aspects of Ruby I have never seen used in real-life use despite having used Ruby for 20 years), or could be mitigated trivially, so I still believe you can do quite decently without a lot of the more complex optimisations.

As an example (from Ruby): You can re-open the Integer class and override +:

  ruby -e 'class Integer; def +(other); 42; end; end; p 2 + 2'
(don't do this in IRB; it crashes)

But nobody does that. The problem with a lot of these features isn't that people use them, but that people might use them.

That leaves two main avenues: We can do like the author of thise post and strip away the costly features that are rarely used.

Or we can provide ways of promising not to use them through code or options.

The first option is perfectly valid, but I quite like the second:

In Ruby, it turns out a lot of the optimisation challenges goes away if you get an app to freeze the most important system classes after setup, because even most of the most horrific examples of Ruby monkeypatching tends to do most of it only during startup, and you then tend to get to a stable state where you can let applications opt in to additional optimisations just by calling "freeze" on a number of objects.

Ruby programs will also do things like dynamically decide which files to load based on reading the directory, but if you compile an application, most of the time you want that to happen ahead of time with a few exceptions (e.g. plugins), and so similarly, if you freeze as many classes as possible at a given point, you can partially evaluate manipulation of the runtime up until that point, and treat it as mostly static afterward, and fall back to slow paths for anything you can't statically resolve the names of, and still end up with lots of optimisation potential for most of the low level code.

I think a lot of the same would work for Python, and might bridge the gap between the categories of alternative implementations the author mentions with more predictability than relying on a JIT doing the right analysis.

E.g. your compiler can eat least potentially guarantee under which circumstances it can statically determine that an Integer can inline the fast path if Integer is frozen so that you can in fact reason about the code.

bboynton97 9 hours ago

imagine having a GDPR banner on your personal blog

jmpeax a day ago

I can't view the site on my mobile without accepting cookies.

  • alexaholic a day ago

    Specifically Google Analytics cookies, but I found you can uncheck the box.

    • pred_ a day ago

      It's still pretty confusing: Uunchecking the box doesn't seem to do much (is it actually unchecked when you click it? There's still a checkmark); you still have to click Accept to see the text; what are you accepting?

      In any case, pre-checked boxes are not valid consent under GDPR (“Planet49”).

  • austinjp a day ago

    No cookie notice at all for me using Firefox on Android with the "I Still Don't Care About Cookies" extension.