CPython's main branch running in the browser with WebAssembly
twitter.com
twitter.com
How does Python-in-WASM work around that? For example, how does `for line in sys.stdin:` work if you can't actually block on stdin?
Emscripten has some support for this via the "asyncify" transform, which layers additional control flow to enable return all the way up the call stack, and then "rewind" back down into it. But this bloats the code (and is also buggy) so maybe it's not being used.
Python allows you to reach in and replace the core interpreter loop, so this may be an avenue to have our own asyncify-like function pop out to JS land and restore state correctly (which we can be smart about since we are the interpreter).
It may also be possible to write something that runs Python in a webworker and communicate with it over a sharedarraybuffer, but that I'm a bit more hazy on. Pyodide has some discussion of this in https://github.com/pyodide/pyodide/issues/1219 and https://github.com/pyodide/pyodide/issues/1503.
This is definitely the hardest part of getting Python to work. Well, hardest after the hardest part of building a compiler toolchain like Emscripten :)
When building Runno (https://runno.dev) I forked off that project and did a bunch of other things on top to get blocking to work in Safari and non-cross-origin-isolated contexts.
Ultimately I think it's JavaScript's (or whichever host language) responsibility to block when the binary calls out (if that is the expected semantics).
There is also a proposal to bring stack switching to the browser.
0: https://github.com/jlongster/absurd-sql
1: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
2: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
If people actually develop stuff in Python for the web, they should do something like that.
If you've found any bugs in Asyncify please file them! There are no open issues atm about any general bugs, aside from some corner cases with features like dynamic linking.
https://beuc.itch.io/the-question-web
(I'm the lead developer of Ren'Py, though Sylvain Beucler did most of the work. He also has a 3.8 port here: https://www.beuc.net/python-emscripten/python/dir?ci=tip )
Right now, most of the I/O is synchronous - the files are downloaded to the browser before a game starts, so all of the calls are fast, so far as I can tell, as they're happening within the browser.
Output is through SDL, and there's a call into a cython-defined function that calls __emscripten_sleep, with the path of calls to it listed in the ASYNCIFY_WHITELIST. That's the only place we block. (It's a bit late, so I might be misremembering the exact emscripten function.)
But Python and Lua didn't "look like Java" enough for Netscape.
https://news.ycombinator.com/item?id=17061967
>In 1990, Sun played with the idea of putting a PostScript interpreter in the SunOS kernel.
>Like NeWS was the Network extensible Window System, so NeFS was the Network extensible File System, or NFS 3.0.
>It was actually a great idea, just a wee bit before its time, and very poorly named and positioned!
>For example: If you want to make a copy of a file on the server, you can send a PostScript program that runs in the kernel and copies the file locally on the server in the kernel with ZERO context switches, instead of sending it over the net to the client, then back from the client to the server. Even if you rsh'ed the user command "cp" on the server, it would still incur context switching, but if your copy loop was running in the kernel then it didn't need to switch in and out and in and out for every block it copied.
>There are more examples of why it's a great idea in the paper.
>This comparison of NeWS to AJAX also applies NeFS, which is like kernel NeWS with file operations instead of a graphics library -- it also saves you lots of user/kernel context switches even if you're not doing any networking:
https://en.wikipedia.org/wiki/NeWS
>>NeWS was architecturally similar to what is now called AJAX, except that NeWS coherently:
>>- used PostScript code instead of JavaScript for programming.
>>- used PostScript graphics instead of DHTML and CSS for rendering.
>>- used PostScript data instead of XML and JSON for data representation.
>It didn't go over very well because the unenlightened philistines of the time couldn't get their head around an API to the file system that wasn't compatible with creat open close read write and ioctl.
http://donhopkins.com/home/nfs3_0.pdf
>Network Extensible File System Protocol Specification
>1.0 Introduction
>The Network Extensible File System protocol (NeFS) provides transparent remote access to shared file systems over networks. The NeFS protocol is designed to be machine, operating system, network architecture, and transport protocol independent. This document is the draft specification for the protocol. It will remain in draft form during a period of public review. Italicized comments in the document are intended to present the rationale behind elements of the design and to raise questions where there are doubts. Comments and suggestions on this draft specification are most welcome.
But if not PostScript, Python, or Lua, then at least Netscape didn't use TCL in the browser. Around 1994, long after NeWS and right before Java, Sun announced they were going to make TCL the official scripting language of the world wide web, which triggered RMS into kicking off the Great TCL War:
RMS's "Why you should not use Tcl" flame:
https://news.ycombinator.com/item?id=17061858
>And with that diplomatically worded message, RMS kicked of The Infamous TCL War. That was Stallman's response to Sun bombastically pushing TCL as the official scripting language of the web, BEFORE Live Oak / Java was a widely known (or evangelized) thing.
>At the point anybody started talking about a Java/TCL bridge, it was already all over for TCL becoming the "ubiquitous scripting language of the Internet".
>Sun's unilateral anointment of TCL as the official Internet scripting language trigged RMS's "Why you should not use Tcl" message, which triggered the TCL War, which triggered Sun to switch to Java.
>After the TCL war finally subsided, Sun quietly pushed TCL aside and loudly evangelize Java instead. The TCL community was quite flustered and disappointed after first winning the title "ubiquitous scripting language of the Internet" and then having the title yanked away and given to Java.
>Any talk of bridges were just table scraps for TCL, the redheaded bastard stepchild sitting outside on the back porch in the rain, smoking a cigarette and commiserating with NeWS and Self.
>Tom Lord's description of what happened is insightful and accurate:
https://web.archive.org/web/20110102015130/http://basiscraft...
>The Infamous Tcl War
>[...] Mr. Ousterhout had, a few years prior, developed Tcl while on the faculty of UC Berkeley - mainly, I think, to have a handy tool for other research and only secondarily as an experiment in language design. And he topped it off with Tk. Tcl/Tk took off in a huge way. It was easy to understand. The source code, written in Mr. Ousterhout's methodical and lucid style, was a joy to read. At the time, about the most convenient option for developing a GUI to run on a unix system was to write C code against the Motif toolkit - an ugly, expensive, and frequently disappointing process. With Tcl/Tk in hand, people started handing out new "mini-GUIs" for this and that, like candy. Tcl/Tk started to find application in some rather intense areas, like, for example, the "control station" software for some oil rigs. It was a smash hit.
>Meanwhile, I don't think I'm letting too many cats out of the bag here, the informal Silicon Valley social network of well placed hackers were quietly and unofficially circulating some very interesting confidential whitepapers from Sun Microsystems. One of their researchers, a fellow called Mr. Gosling, had dusted off a language he'd once led the design of called "Oak". Oak was originally intended for use in embedded systems. Its basic premise was that devices ought to be Turing complete and hackable, whenever possible. Oak's approach to statically verifiable byte-code comes from that origin. Mr. Gosling came out of Carnegie Mellon University and the attiude behind Oak was popular there. As one grad student had quipped a few years earlier: "If a light switch isn't Turing Complete I don't even want to touch it."
>In light of the rising star of web browsers, the folks at Sun conceived the notion of offering up a derivative of Oak to serve as the extension language for browsers. (It is probably worth mentioning here that Mr. Gosling was earlier well known for making one of the very first unix versions of Emacs.) Oak was re-named "Java" and the rest of its history is fairly well known.
>I've read, since then, that up to around that point Brendan Eich had been working on a Scheme-based extension language for Netscape Navigator. Such was the power of the hegemony of the high level folks at Sun that the word came down on Mr. Eich: "Get it done. And make it look like Java." Staying true to his sense of Self, he quickly knocked out the first implementation of Mocha, later renamed Javascript. This phenomenon of Sun's hegemony influencing other firms turns out to be a small pattern, as you'll see.
>Mr. Ousterhout was hired by Sun (later he would spin off a Tcl-centric start-up). The R&D; team there developed a vision:
>Java would be the heavy-lifting extension language for browsers. The earliest notions of the "browser as platform" and "browser as Microsoft-killer" date back to this time. Tcl, Sun announced, was to become the "ubiquitous scripting language of the Internet". Yes, they really pimped that vision for a while. And it was "the buzz" in the Valley. It was that pronouncement from the then-intimidating Sun that led to the Tcl wars.
>Mr. Eich, bless his soul, brute-forced passed them, abandoning Scheme and inventing Javascript. [...]
https://news.ycombinator.com/item?id=1905155
(2010, he was still at Mozilla)
WASM is meant to allow for fast/efficient programs written in low level languages like C/Rust to run in the browser, not subject the client with slow clunky experiences because the developer only learned Python.
E.g. we have https://github.com/pyodide/pyodide and other examples.
The cool part here is Emscripten, which has been around for a long time.
I wonder if anyone has tried the same approach using MicroPython.
I’d expect MicroPython (or Lua/mruby/etc) could be an order of magnitude smaller. Still larger (and slower) than just using JavaScript, though.
Fengari [0], a Lua interpreter written in JS, is a little over 200Kb. (And was intentionally written in JS [1] because of a variety of reasons that made WASM not work that well.
200Kb isn't that bad of a price to pay to switch languages, on most websites. It'll be about the cost of a single image added to the page. And it's fairly performant.
For most sites, the costs in terms of requests and performance will be negligible compared to what you're trying to achieve.
And Fengari makes it nice and easy to interact with JS, too. Using React with Lua's syntax was what sold me on it. No ecosystem lockout, like I'd expect with most WASM ports.
[1] https://hackernoon.com/why-we-rewrote-lua-in-js-a66529a8278d
Jokes aside, JS ecosystem really needs a competitor. Web developers have been cutting corner after corner for decades, with ever increasing disregard for performance and memory consumption.
Now with both Python and Rust in the browser, things may change for the better.
It is interesting from an interoperability point of view, but this purely negative from a performance and maintainability point of view.
But in picking up modern frontend, even in the past two years, the frameworks and toolchains have matured or simplified a great deal.
The training options are plentiful. To some extent, Node has Deno “competing” to add features and provide performant backend.
Esbuild, for example, is built on rust and unlocked massive performance improvements in bundling.
It seems like JS is in a better position than it has ever been.
All others have lots. That's the point.
It is definitely too early for benchmarks, this is a "I got it working!" update.
The original data file with all of the standard library was a bit over 200MB. Slashing what isn't going to be run in the browser (e.g. tkinter) and zipping the standard library got it down to about 20MB. There is probably more that could be removed, and there are modules we don't need to build that we currently do. There are other things we can do like set the less frequently used modules to be loaded asynchronously.
While I doubt this will be production ready "soon", I do hope to keep working on fixing bugs and such.
The demo I put in the tweet is the same code as when you type `python3` in the terminal, just running in the browser. So it is much more compatible and is mostly [1] feature complete.
[1] minus whatever libraries are likely never to be used that we ripped out
[0] https://yasoob.me/2019/05/22/running-python-in-the-browser/
So the answer to the question "Can WASM access the DOM?" is both yes and no, always has been, and probably always will be ;)
(In asm.js, memory was provided by an ArrayBuffer of fixed size, so there memory could truly not grow at runtime.)
If anyone does choose to do this I hope they spend significant amount of effort making their caching and code splitting optimal.
Many devs already make me download their SPA to display static text and images.
There have been several libraries that provide the concept of a promise, but with modern python these are built into the stdlib with native async/await support, though many interfaces are still sync-only (though you can work around that with things like gevent that monkey-patch those interfaces to work with an event loop under the hood).
I agree that python would be a poor fit for the kind of uses that JS in the browser usually serve, but it's really a matter of ecosystem, not core language design.
You could still use JS while Python support catches up.
What they can do is to provide GC to unbloat a lot of those runtimes I guess.
the hard part at the time was obviously all the hooks between the dom and the javascript runtime as well as concurrency story. python 2 was not built to be driven by callbacks, which is how the whole browser/javascript ecosystem works.