Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This isn't an attitude of "no" - it's an attitude of "yes" to other things. The arguments are that making Python startup fast makes other things worse, and we care about those other things.

Here are some other things we can say "yes" to:

- Rewrite as much of Mercurial in Rust as possible, which will provide performance improvements well beyond what Python can possibly offer. https://www.mercurial-scm.org/wiki/OxidationPlan

- Spend resources on developing PyPy, which (being a JIT) has relatively slow startup but much faster performance in general, for people who want fast performance.

- Write compilers from well-typed Python to native code.

- Keep CPython easy to hack on, so that more people with a "can do" spirit can successfully contribute to CPython instead of it being a mess of special cases in Guido's head.

Will you join me in saying "yes" to these things and not convincing ourselves to accept mediocrity?




I have to note that none of the projects you suggested, all of which are good and useful, will do anything to address cpython startup latency problem under discussion. Why shouldn't cypthon be better?

There's also no reason to believe that startup improvements would make the interpreter incomprehensible; the unstated assumption that improvements in this area must hurt hackability is interesting. IME, optimizations frequently boost both simplicity and performance, usually by unifying disparate code paths and making logic orthogonal.


I think you misunderstood the point. These weren't things that would address the cpython startup problem - these were other priorities that can be worked on, instead of (or in addition to) the latency problems under discussion.

Saying yes to fixing one thing usually means saying no to all the other things you can be doing with your time instead. Unless you're lucky and can "kill 2 birds with 1 stone".


> - Write compilers from well-typed Python to native code.

That is one thing I really want to happen, because I think it begins to open up python to the embedded space. Micropython is nice, but it still needs an interpreter embedded into it.


There have been plenty of attempts to compile Python to faster code (usually by translating to C).

Cython can use type annotations and type inference to unbox numbers for faster numerical code, but uses ordinary Python objects otherwise. http://cython.org

ShedSkin translates a restricted (statically typeable) subset of Python to C++. https://shedskin.github.io

RPython has a multi-stage approach where you can use full dynamic Python for setup, but starting from the specified entry point, it is statically typed. Since it was created for PyPy, it comes with support for writing JIT compilers. https://rpython.readthedocs.io

Pythran translates a subset of Python with additional type annotations to C++. http://pythran.readthedocs.io

In general, the major hurdle for all attempts to compile Python to native code is that Python code is dynamically typed by default.


An hurdle that has been solved for quite some time in Lisp, Scheme, Prolog, Smalltalk, SELF (was the basis of Hotspot), Dylan, Ruby, JavaScript.

All not less dynamic than Python.

What Python lacks is the funding and willingness to actually push one of those implementations to eventually become the new reference implementation.


Nuitka might be interesting for this use case, too. http://nuitka.net/index.html

It will compile python to C++ and then compile that code to machine instructions and calls to the CPython library.


Thanks for that rundown. It's pretty good.


> Why shouldn't cypthon be better?

The point is that "better" is almost never a well-defined direction unless you only consider a single use-case. It's almost always a tradeoff, especially in a widely used project.

A language is a point on a landscape of possible language variants, and "better" is a different direction on that landscape for every user.


> cpython startup latency problem

The problem under discussion is that projects that currently use CPython have slow startup. One potential solution is for those projects not to use CPython. (Certainly it's not the only potential solution, but, a language that tries to be all things to all people isn't going to succeed. Python has so far done an extraordinarily good job of being most things to all people, with "I want native-code performance" being one of the few out-of-scope things.)


>IME, optimizations frequently boost both simplicity and performance, usually by unifying disparate code paths and making logic orthogonal.

I would really like to see some examples where this is the case. Optimizations in my experience have made systems more brittle, less portable and ultimately less maintainable.


Programs a fast when they don't force the computer to do much stuff, so speed overlaps (albeit imperfectly) with simplicity of code. Mostly this explains why programs start fast and then slow down as they cover more use-cases. But some optimisations also amount simplifying an existing system.

For example: as you get to know your use-cases better you might simplify your code to sacrifice unwanted flexibility. Or you might replace a general-purpose data structure with a special purpose one that not just faster, but concretely embodies the semantics your desire.

A case, that is not quite a simplification is removing code re-use. Instead of using function in three different ways, you use three separate optimised functions. Now changes to one use case don't cause bugs in the others. That's the kind of thing that quotemstr meant by "making logic orthognal".


>A case, that is not quite a simplification is removing code re-use. Instead of using function in three different ways, you use three separate optimised functions. Now changes to one use case don't cause bugs in the others. That's the kind of thing that quotemstr meant by "making logic orthognal".

And which is what I mean by making systems more brittle, less portable and less maintainable.

You find a corner case in the original function that's not covered, now instead of fixing it in one place you need to fix it in three places with all the headaches that causes.

So the next maintainer thinks: "Gee I can fix this by bringing all these functions together".

So if they're using an oo language they make an abstract base class from which the behaviour is inherited, or a function factory otherwise.

So now you're back to a slow function with even more overhead, that's even harder to debug.

So the next maintainer comes around and thinks: "Gee I can speed this up if I break out the two functions that are causing 90% of the bottleneck".

Now you have 4 completely independent functions to keep track of.

Repeat ad-nauseum.


I'm so longing for a Python(like) compiler.

MicroPython put together a Python in 250kb. Why the hell can't we make an LLVM frontend for Python that can use type hints for optimization? Sure, you lose some dynamic features as you optimize for speed, but that's the dream. Quickly write a prototype, not caring about types, optimize later with adding types and removing dynamicism.

I'm currently learning Racket and LLVM and I have about 70 more years to live. I'm gonna try make Python fast on slow weekends 'til I die.


Since you're after micro-controllers you might be interested in Nim. At this year's FOSDEM we showed off some micro-controllers running Nim code[1]. The language is definitely less Python-like than Cython, but it might just be similar enough for your use cases (I started using Nim as a Python replacement).

1 - https://twitter.com/nim_lang/status/959736268870639616


For people who don't want to bounce through twitter to get to the home page:

https://nim-lang.org/


Unless your Python compiler can use cpython modules without a massive performance penalty, it's going to see very limited adoption. The ecosystem matters.


We had a chance with ctypes and now CFFI to move away from the platform calcifying cpython module interface that is overly coupled to the cpython runtime. I am very disappointed in the lack of affordances that cpython gives to alternative pythons to support their work. The stdlib is a crufty mess that is overly coupled to cpython as well. The batteries are corroded and need to be swapped out for a modular pack.


I don't think it would be hard to add type annotations to existing projects, though. Something similar happened in the JS world with the transition of JS projects to TypeScript and it wasn't a big deal, IIRC.


> I'm so longing for a Python(like) compiler.

There is Cython, of course, which is a great python (+) compiler. I assume you mean a just-in-time compiler as opposed to a static compiler.


No. Pypy already does JIT. And Cython has the speed, but not the size.

The target of my phantasy compiler are microcontrollers. That's why the (correct) comment of quotemstr isn't that big of a concern to me.


Just throwing Python code at Cython doesn't really improve performance all that dramatically, because it'll be doing pretty much the same thing as the bytecode interpreter, except that all the saucy special-cases are now unrolled many times across all code.


Isn't it what Numba does quite successfully for a subset of Python?

[1]: https://numba.pydata.org/


Not static AOT, not creating tiny binaries that fit on a microcontroller.

There is a lot of stuff out there that goes in this direction. There is nukita (again no small binaries), there is even an abandoned GCC frontend that can compile some minimal examples, but has been abandoned long ago.

Seriously, the time I spent researching this topic - if a proper compiler engineer would spend that on the actual compiler, it'd be done by now.



Seeing as that page states the resulting executables still require numpy, I'd guess it was the static requirement that it misses.


You might be interested in Matthew Might's course on compilers. In one of his courses he targeted a Python compiler written in his weapon of choice, Racket.


> PyPy, which (being a JIT) has relatively slow startup

    > time pypy -c 'print "Hello World"'
    Hello World
    pypy -c 'print "Hello World"'  0.08s user 0.04s system 96% 
    cpu 0.120 total

    > time luajit -e 'io.write("Hello World!\n")'
    Hello World!
    luajit -e 'io.write("Hello World!\n")'  0.00s user 0.00s 
    system 0% cpu 0.002 total


Sometimes I wonder why we're not all using Lua instead of Python. Lua seems to get a strange amount of hate in some circles, but I've found both Lua and Python to be reasonably pleasant languages to work with.


From my personal account about Lua [1]:

> Three, the language is not a mere combination of syntax and semantics. Any evaluation should also account for user bases and ecosystem, and in my very humble opinion Lua spectacularly fails at both. I'm not going to assume the alternative reality---Lua has a sizable user base and its ecosystem is worse even for that user base.

> [...] The lack of quality library also means that you are even more risky when you are writing a small program (because you have less incentive to write it yourself). I have experienced multiple times that even the existing libraries (including the standard ones) had crucial flaws and no one seems to be bothered to fix that. Also in the embedded setting the use of snippets, rather than proper libraries, are more common as libraries can be harder to integrate, and unfortunately we are left with PHP-esque lua-users.org for Lua...

I think this critique still holds today, and unless miracle happens (like D), I doubt this is fixable.

[1] https://news.ycombinator.com/item?id=13902023


I had a similar feeling a while back, but when I actually picked up Lua for a project I was shocked by how limited the standard library is. Third party libraries aside (which Python clearly has in spades), even just the standard library is pretty sparse. It makes sense, since Lua is at least partly motivated by being lean and embeddable, but it puts Lua in a completely different space for me.


Other folks complain about the lack of libraries. Personally, the two things which turn me off on Lua (luajit) are 1-based arrays and the conflation of hash-tables and array-lists into a single thing.


I don't like how everybody invents their own class system.


> the conflation of hash-tables and array-lists into a single thing.

Precisely, one of the things that turns me off on Python (coming from Lua), is the unnatural proliferation of different container types.


Oddly that's one of the things I like most about python. The containers module has so many very useful things. Plus hash-tables and array-lists shouldn't ever really be the same thing.


To each their own :-)

You might like Tcl - associative arrays (hash tables), arrays (lists), strings, numbers, and code are all the one type (at least conceptually).


no batteries


Is ... that faster than CPython? Wow. Maybe I should symlink /usr/bin/python -> pypy on my laptop....


It's much slower. On my machine, "$PYTHON -c ''" (execute nothing) takes 60ms on Python 2.7, 80ms on 3.6 and 250ms on pypy.


It's not. You can test it on your system. In every case I've seen, Python starts up faster than PyPy. Neither takes a super long time.

PyPy has some great performance characteristics, but startup time isn't one of them.


Startup << warmup.


None of these address, for instance, the issue raised about the firefox build invoking python many times. This seems both an accepted use case of cpython and an area where traditionally cpython has a huge edge on the JVM and PyPy. If scripts are not a priority, what is the expected use case of cpython?

I would like to note, the cpython ties to the PyObject C abi seem to stymie rather than encourage “hacking”. Cpython seems to have traditionally valued stability over all else.... see the issues pypy has had chasing compatibility with c and retaining speed.

So: normally i’m with you and a language should lean into its strengths, but i’ve always listed startup time as a primary strength of python!


In my experience, "script" is usually well-correlated with "a bit of inefficiency is okay." There's a reason that, say, many UNIX commands that could be implemented as scripts (true, false, yes) are actually implemented as binaries. There's a reason that most commercial UNIXes/clones (Solaris, macOS, Ubuntu, RHEL, etc.) switched from a script-based startup mechanism to a C-program-based one.

I certainly write and continue to write Python scripts where even an extra half second won't matter. It's doing some manipulation of data where the cost of what it's doing is dominated by loading the data (e.g., grabbing it from some web service), and even if the script is small and quick, it's not so small and quick that I'll notice 50-100 ms being shaved off of it.

Use cases where CPython continues to make sense to me are non-CGI web applications and things like Ansible, where load time isn't sensitive to milliseconds and runtime performance is pretty good. (Although if you believe the PyPy folks, perhaps everything that's PyPy-compatible should be running on PyPy.)


This hits the nail on the head.

Optimization is very, very rarely completely „free“ - and usually a concious trade of some property for another trait that‘s deemed more important in a specific case.

Simplicity for performance. Code size for compilation speed. Startup time for architectural complexity. UX for security.

For a great product, you need to say „no“ much more often than not. Do one thing and do it well. Be Redis, not JBoss.

I love how this article gets down to the essence of it: https://blog.intercom.com/product-strategy-means-saying-no/


Agree. I recently found that trying to optimise code can make it a lot more complex.


> Rewrite as much of Mercurial in Rust as possible, which will provide performance improvements well beyond what Python can possibly offer. https://www.mercurial-scm.org/wiki/OxidationPlan

I read that article and I'm still wondering: why Rust?


The last three paragraphs of the section "Why use Rust?" should address that - basically, they have experience with solving this problem by writing parts of the code in C, they are not fans of that experience, and Rust is a compelling better C (and there are specific reasons they don't think C++ is compelling).

Are you asking in comparison to some other language? The most obvious other languages in the "compelling better C" niche I think are Ada, D, and Go; Ada and D (I think, I do not know them well) don't have as good of a standard library or outside development community, and Go is less suited to Rust to replacing portions of a process. Go would be a reasonable choice were one writing a VCS from scratch today.


The C++ rationale is bizarre. That a 2008 compiler doesn't provide modern features is unsurprising. They've chosen to use Rust is a strange reaction to this limitation, since it would be just as easy, from a toolchain perspective, to just use a modern C++ compiler.


One big advantage of rust is that (while some people won't like this), rust assumes you won't install it from your package manager, but download a script which installs it in your home directory. This script is quick and easy.

Trying to install a c++ compiler from source (and I've done it several times) is a much less plesent experience, so most people stick with what their package manager provides.


Language features aside, Rust is a lot nicer to work with because it has cargo and using libraries is no longer a pain.


Depends which libraries we are talking about, try to use GUI libraries from Rust.


That isn't fair, all languages besides JS+HTML+CSS have issues with GUI libraries. Either you go Electron/webview or you have to deal with Qt/GTK for cross-platform GUI.


Sure it is fair, Java, C++, C#, VB.NET, Delphi, Objective-C, Swift have quite good GUI libraries available.

And regarding JS+HTML+CSS, they are still on the stone age of RAD tooling.


I think you missed the cross-platform part of my answer.


Some of those languages do have cross-platform GUI offerings.

Even AWT is better than any option currently natively available to Rust.

After all, "using libraries is no longer a pain" is not what I felt when converting an old toy application from Gtkmm to Gtk-rs.


> Go is less suited to Rust to replacing portions of a process

How so? Is it because Go has a GC and Rust doesn't?


That's part of it, but more generally, Rust prioritizes fitting into other programs: it offers direct compatibility with the C ABI for functions and structs (because the C ABI is the effective lingua franca for ~all present-day OSes), it uses regular C-style stacks instead of segmented stacks, threading is implicit, calls between Rust and C in either direction are just regular function calls and involve no trampolines or special handling by the GC/runtime, there is no runtime that requires initialization so you can just call into a random Rust function from a C program without setup, etc.

Go has cgo, and has slowly come to a few of the same decisions (e.g., Go gave up on segmented stacks too), and gccgo exists, so it's certainly possible to use Go for this use case. But it's not as suited as Rust.

There's a nice post about calling Rust from Go which goes to lengths to avoid the cgo overhead, even though Rust can just directly expose C-compatible functions and cgo can call them without any special effort on either side: https://blog.filippo.io/rustgo/


> How so? Is it because Go has a GC and Rust doesn't?

More generally a heavy runtime, which creates issues when you're trying to replace parts of a process which has its own runtime, unless you can make the two cooperate (by actually using the same runtime e.g. jvm or graal or whatever).

Go's FFI is also easy to work with but the source of… other issues which is why the Go community often prefers reimplementing things entirely to using cgo and existing native libraries.


Yes, manually move objects between GCs is tricky.


Because he works for Mozilla.


That is probably the only reason to use rust over go or cpp.


Really? The only reason?


Only one I can see. Want speed and performance and safety? C++. Want easy multithreading? Go. Rust's only claim to fame is that Mozilla is dogfooding it.


> Want speed and performance and safety? C++.

Speed and performance sure, but safety automatically rules out C++.

> Want easy multithreading? Go

Want speed, performance, safety, and easy multithreading? Rust.


C++ still does multi-threading better than rust, just that go does it better. Similarly go does perf better than rust, just that cpp is even better. So yeah, if you want the worst of all worlds coupled with the pains associated with a brand new language (try compiling rust for a armv5 soc) rust all the way!


Can you show a benchmark where Go outperforms Rust?


I agree with you. As the limitation of developing resources, say "no" is difficult but important.


I am slightly afraid to ask, but what is a "well typed python"?


Have you seen MyPy, static type annotations / checking for Python? http://mypy-lang.org/

In context, what I'm really getting at "a sufficiently non-dynamic subset of Python that it can be compiled statically, but also a sufficiently large one that real Python programs can have a chance of being in the subset." PyPy has a thing called RPython that fits the former but not really the latter (I don't know of any non-PyPy-related codebases that work in RPython). In general, adding complete type annotations to a codebase is pretty correlated with making it static enough to do meta-level things on like compiling and optimizing it - for instance if you have a variable that changes types as the program runs, at least now you've enumerated its possible types. It's not the only way of doing so, but it seems to work well in practice and there seems to be a correlation between compiled vs. interpreted languages and static vs. dynamic typing.


correct. Every time you say yes, your saying no to something else. Its important to realize what your saying no to, before you say yes.


It's funny when developers themselves think effort is so fungible. Like if you spent 1 hour on A, then you would've also made 1 hour of progress on B, C, or D, and that it would've been worthwhile. To the point of fallacy in your post.

I would think developers have the experience to realize this isn't true but I see it all the time on these forums.


I think I'm making the opposite claim - effort isn't fungible (and availability of effort isn't fungible). You can't necessarily spend 1 hour that would otherwise go into, say, rewriting Mercurial into a compiled language and instead spend it on making CPython faster and get the same results. One of these is more likely to work, and also the two problems are going to attract interest from different people.

And one of the things that affects how productive one hour of work will be - and also whether random volunteers will even show up with one hour of work - is the likelihood of getting a change accepted and shipped to users. This is influenced by both the maintainers' fundamental openness to that sort of change, and any standards (influenced by the maintainers, who are in turn influenced by their users) about how careful a change must be to not make the project worse on other interesting standards of evaluation. It's also influenced by the number of people working on the project (network effects) because a more vibrant project is more likely to review your code promptly, finish a release, and get it into the hands of more users.

So I'm claiming that it's better to spend time on rewriting Mercurial in Rust than to spend time on getting CPython startup faster, because the Mercurial folks are actively interested in such contributions and the CPython folks are actively uninterested, and because there are fewer external constraints in making Mercurial startup faster than in making CPython startup faster. And I'm saying that the more we encourage folks to help with rewriting Mercurial in Rust, the more likely additional folks are to show up and help with the same project, thereby making 1 hour of effort even more productive.


> This isn't an attitude of "no" - it's an attitude of "yes" to other things.

You are literally bringing an attitude of "no" to the question of whether you are being an attitude of "no" to the discussion....


If those who complain about no-attitudes are insisting that the only acceptable response to anything is "yes", I doubt they'll get far.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: