WebAssembly Backend for Scala.js with Sébastien Doeraene
The JVM-to-Web journey continues! In this episode, Thomas Steiner welcomes the original author of Scala.js, Sébastien Doeraene, to discuss the major, experimental leap to WebAssembly. You’ll learn why the team decided to target Wasm now and how it complements the existing JavaScript emission. This episode offers a technical deep-dive into how Scala’s powerful, nominal type system maps its objects and classes onto Wasm GC, and examines the critical details of interoperability, including what happens when a Scala object crosses the boundary to a JavaScript function. Finally, Sébastien covers the current status of the Wasm ecosystem for Scala.js, and the key limitations you need to know before you flip the `withExperimentalUseWebAssembly(true)` switch. Tune in to discover how a mature typed language is laying a fast, new foundation on the web!
- Published
- Published Jan 5, 2026
- Uploaded
- Uploaded Jun 13, 2026
- File type
- YouTube
- Queried
- 00
- Source
- youtube.com
Full transcript
Showing the full transcript for this video.
AI-generated transcript with timestamped sections.
[00:06] Welcome to WebMess Ampli episode 18. In the last episode, we explored Kotlin's journey to the web with Salim Bashoff. Today we stay in the realm of strongly typed languages that usually run on the JVM, but have found a second home in the browser. I am thrilled to welcome Sébastien Duran, [00:30] into the nitty-gritty of compilers, you're not just a code virtuoso, but also a voice virtuoso. Singing and choirs like the Ensemble Vocal et Boyer, I think I'm pronouncing this right, do you find any commonality between composing music and composing compilers? That's a good one. Yeah, I do sing quite a lot. And I do compose a little bit. I conduct more. [01:00] community between the competitors themselves and composing, but you could make a parallel between language design, which is also part of the job, because there are lots of moving parts, and you need to make sure that, I mean, you always want to add more features and more voices, more parts, but you want to make sure that they all sound or work well together. So in that sense, I think [01:30] little bit of commonality in the creativity aspect of making things [01:34] various things, um, play well together. Well, and both are art forms and both are out of reach for myself. So I think this is where the commonalities are even stronger there. So it is singing, it is compiler building both things. I am not really good at both things. I have to learn and try, but I will most likely fail. So I'm on Sing. Um, I'm here to, yeah, get very interesting
[02:04] So people know there's Scala, some people know there's Scala.js, some people even know that there is Scala native. There's the Scala Center, which you work at, are involved in, are CEO of something. So can you just help us put a bit of structure into the Scala ecosystem? Who does what, what came when, and so on. [02:24] So first, Scala Center is a little bit different from the other things you mentioned. Very obviously so, but it has Scala in the name. Right, right. So the Scala Center is, you can see it as the foundation that's behind Scala, similar to the Node.js Foundation or patent foundation or whatever. It is a [02:48] technically hosted inside EPFL, the technical university at Lausanne in Switzerland. So, but it's, it functions as, yes, a mostly independent foundation. And it works together with [03:05] three other... [03:06] units, let's say, that steward the SCADA programming language. One is the LAMP Laboratory at EPFL as well, which is led by Martin Odersky. You may have heard the name. He's the author of SCADA. So that's the research group where they do all the fancy forward-looking stuff.
[03:36] who is mostly maintaining the Scala 2 line of the compiler. And then there is VirtusLab, who is stewarding the Scala 3 efforts on the company side. We're consulting and compiler development, tooling development as well. So those are the four units that work together to maintain Scala. Then you mentioned Scala.js, Scala Native. [04:06] designed for the JVM, right? And when we say Scala, we [04:10] primarily think about that. That came out in 2001, I believe, the first version. So it's been a while now. Scala.js appeared about 10 years later in 2013, I think was the first. Yeah, I started working on it in 2013. Martin had a chat with me when I applied for a job and he said, how would [04:40] I said, "Sure, sounds great." So that's how I started. I'm still there 13 years later. [04:49] And yeah, so the first development started in 2013. We had our first non-experimental release in 2015, the infamous version 0.6. Infamous because it was supposed to last for six months before we turned to one, and it lasted for seven years because we never broke backward compatibility.
[05:19] got version 1 in 2020. And since then, we haven't broken compatibility. So we're at 120.1, last I checked. And then Scala Native came, the first version came out in 2017, I believe. And so Scala Native directly compiles to native code. It uses an LLVM backend to produce x86 or x64 or RM or [05:49] and that is considered stable since version 0.5, which came out last year, somewhere in 2024. [06:01] So yeah, there you have it. One thing that I always like to put emphasis on is that [06:09] Scala.js and Scala Native were not compiling Scala to JavaScript or to native code. They're their own dialects, right? Scala.js is a dialect of Scala that compiles for the web. It doesn't have Java interrupt, but it has JavaScript interrupt, which makes it a different language, basically. And then Scala Native is yet another dialect that has interrupt with C. [06:39] But again, those are really different dialects, and we think of them as such. That said, they do share a substantial... [06:48] common subset, probably more substantial than many other languages that target several very different backends. So you can typically write the same code and it runs, compiles, runs exactly the same on all the platforms. So you're mostly involved with everything Scala JS, right? So you were not involved in Scala native. And you said you were looking for a job and then this sort of dropped out of nowhere.
[07:18] Martin's bucket list of things that he wants to do in his life, like get a language that compiles to JavaScript? Or what was the involvement there? [07:27] Well, I was not even looking for a job. I had... [07:32] Started a PhD at UC Louvain in Belgium a year prior, but then I got this email on the Scala internals mailing list back then, which said, brilliant compiling engineers want it. And it was like, this is for me. I need to apply. And next thing I knew, I was moving to Switzerland and I dropped my PhD, started a new one at EPFL. [08:02] But yeah, it had been on... [08:05] on Martin's mind and several other people's mind for a while. ScalaJS was not the first attempt at compiling something Scala to JavaScript. There had been two other attempts in-house, like in Martin's lab. One was ScalaGrid using the GWT technology from Java. [08:30] you may have heard of it maybe not or you may have not um so that was compiling from the class files but then making grids [08:40] happy with Scala Glass files, basically. [08:45] That got good demos, but it was hard to use. Also, the grid technology itself was already kind of declining at the time. There was another one which was more in the shape of DSLs. Like you could write inside a Scala application, write...
[09:03] JavaScript. [09:05] ish code that looks like Scala as a DSL and that your Scala application would then emit JavaScript at runtime, if you want, which... [09:18] could be used if you have a Scala server, but you want to emit a little bit of dynamically generated JavaScript for your clients, then that would be... But you can't really write a full... [09:32] web-side application, client-side application using that technology. So those were two attempts. And then there were two other attempts in the community, in the open source community. One was Scala for D. [09:49] I don't remember. Two different other things, but I didn't get much traction. Scala.js was the fourth or fifth attempt at compiling Scala to the web. [10:06] which... [10:07] worked well because I had previously done something like that, compiling Scala to a dynamically typed language, and I had already realized that [10:16] Compilation itself was not going to be the difficult part. You can write a compiler. It's fine. [10:25] What's hard is interrupt. How do you interrupt with JavaScript? And so from week one of this work, my mind was on.
[10:37] we have to get interoperability right. And that has been the leitmotiv of Scala.js for its entire life. It's still our number one priority. [10:47] So, yeah, and that worked out. In the span of a few months, we had a good demo, and then it only took seven years to make it right. So you mentioned JavaScript a lot, and I guess a lot of our listeners are mostly JavaScript developers, [11:07] developers obviously getting in touch with TypeScript. And Scala is often described as a blend of object-oriented and functional programming, which sort of is a little weird maybe already for a JavaScript developer. It's concise, static, it runs on the JVM. There's Scala.js, which is the main topic of this episode, which compiles Scala to JavaScript. But can it just give us an elevator [11:37] for the browser instead of just using... [11:39] TypeScript or JavaScript directly. [11:41] Well, TypeScript already provides a good stepping stone into an elevator pitch, right? If it were not there, we would have to... [11:49] try and motivate why you want static types in the first place. I think in 2025, the industry has mostly converged to, well, you know, static types are actually good. We should have them. TypeScript has the gargantuan effort of taking JavaScript semantics and somehow putting types on them and making that sort of work.
[12:19] that they have one overarching non-design goal, which is to be sound. So it's very easy to write [12:29] code that type checks according to TypeScript rules, but is actually not type correct at all. And you can still run into a lot of runtime errors, which is fine. I mean, they still achieve their goals of helping [12:45] code bases be mostly right, and helping with auto-completion, and all of these things, right? So it's definitely useful. Scala goes a step further. Scala [12:59] has a sound type system, or at least if there is an unsoundness somewhere, it's considered a bug, right? So there you get a much stronger [13:10] story for what you want to do with a safe application, a correct application. Then the blend of OO and functional is... [13:20] I mean, Scala was a pioneer there, but it has made its way through several mainstream languages. You could argue that JavaScript at this point is a blend of functional and object-oriented programming. You've got classes, you've got first-class functions. The core data structures are not immutable, which is... [13:41] the one thing that really is missing to adopt the coding philosophy that you would want for a functional mindset. But the ideas are there now, and they are fairly well accepted at this point, that immutability is a good thing. Sometimes you need mutable data structures, sometimes
[14:11] you can design in most of your application in a functional mindset, in an immutable mindset, it helps. And so, Scott, I... [14:21] gives you a language that [14:24] helps you... [14:26] writing immutable first codes, whereas JavaScript, TypeScript, you have to kind of fight the language at every step of the way to do that, right? So the elevator pitch today is not so much about the blend itself, but really the language and its main data structures. They encourage you, they help you write immutable first code as opposed to, [14:54] along with you, but not really helping you. [14:58] So people, when they program TypeScript, they typically, like, [15:03] use escape hatches sometimes like something as any, which sort of breaks the contract that you have with the TypeScript language. But then, yeah, it's frowned upon, but people do it. But essentially, even despite such weaknesses, if you will, TypeScript has sort of won the war for typed JavaScript. It offers structural typing that maps 101 to how JavaScript actually works. Scala, [15:33] and has, as you say, a much more robust and sound, even you could say strict type system. But then you look at the industry today, do you see ScalaJS competing with TypeScript, or is it solving a completely different problem for a different kind of team, maybe? There's even a Scala2 TypeScript compiler, which is interesting. So where do you position ScalaJS versus TypeScript today?
[15:58] All right. So it's difficult to argue that Scalagist is not competing in any way to TypeScript, right? There are obviously two languages that you use to write your client-side application in. So clearly, you're going to have to choose at some point. Do you want to use TypeScript? Do you want to use Scalagist? Do you want to use ClosureScript? Do you want to use any of the other languages? Kotlin, right? [16:28] It's definitely competing in that sense. Of course, yes, Tabscript is definitely winning, and I don't think we want to compete in terms of market share per se. But if your team is more into the functional-oriented or immutable-oriented mindset, then, as we discussed previously, Scalach.js is going to be more suited, I think. [16:58] that. One is really all in into the purely functional style. It's called Tyrion. If you're familiar with the Elm and the Elm architecture, that's basically the Elm architecture transposed into Scala.js. The more popular one is Laminar, which uses a functional reactive programming paradigm. So in such a paradigm, you're not really manipulating immutable data structures, [17:28] time-varying signals, right? And then you compose signals, you derive signals that are, for example, the sum of two other signals. And that means it's not that you have an immutable value and you perform an addition and you get a new immutable value, but you have at any given time one value that you derive another value from, right? And then that means you can still reason about your
[17:58] of immutable way because the relationships between all your variables hold. [18:06] right? And laminar and its FRP system prevents glitches, so you don't have weird inconsistent states where some of the values have updated and some others haven't. And then it directly [18:21] modifies the DOM, right? So it's more efficient than a virtual DOM. A virtual DOM, you have to build an entirely new data structure [18:30] diff it against the previous one so that the system can update the DOM for you. With an FRP system, the system knows about the signals propagating and then it directly updates the DOM, so it's actually more efficient than virtual DOM-based systems. [18:48] Um, [18:50] All that said, there are some teams that actually use both TypeScript and Scala.js. [18:58] That's where the Scala.js TypeScript compiler you mentioned is not really a compiler in the sense that it doesn't translate the body of functions. It's more providing TypeScript type definitions for what the Scala.js side of your application would expose to TypeScript. [19:20] directly. [19:21] If you use that code from TypeScript, you don't get a typed version of the API you just wrote in Scala.js, which is kind of a bummer, given that it was statically typed in the first place. So what you can do is, indeed, there are some tools that...
[19:39] take your Scala.js application and consider it as a library to be intended for TypeScript, and then writes down, I mean, generates the types for TypeScript to see the right API with all its static types. So that's useful if you have an existing front-end team that is comfortable with TypeScript, [20:09] logic besides that you want to write in Scala.js for its correctness or because you want to share code with your backend, which happens to be written in Scala on the JVM as well. And then you want to interoperate between TypeScript and Scala.js on a fairly deep level. And that's something that some people do. That's very interesting. So you might be burning for finally getting into the [20:39] Before we do this, we need to first actually introduce WebAssembly because this is the very topic of this podcast after all, right? Oh, right. That's right. But like... [20:50] If you go there, for a long time, ScholarJS targeted JavaScript. It's in the name, exclusively. But then starting with ScholarJS site 117.0, which was released in, I think, late 2024, and then improving significantly in the 119 release, you officially added first experimental WebAssembly as a back-end, which seems like a major shift. What motivated this discussion?
[21:20] to target WebAssembly now, and is the goal to eventually replace the JavaScript emission or to complement it? So will it be Scala.vasm instead of Scala.js? Right. So one thing that has completely changed a year and a half or two years ago is that Wasmgc appeared. [21:50] complete no-go to compile Scala.js to WebAssembly. [21:55] Many people said, why haven't you written up WebAssembly back in? Like, everyone's doing it. It's going to be fast. Except, no, compiling to WebAssembly does not suddenly make your program fast. [22:13] Before, it was a GC compiling your linear memory language to WebAssembly [22:20] was going to make your program faster. [22:26] But if you had a GC-based language, and even more so if you wanted to interrupt with JavaScript, that was basically a no-go. You would have to... [22:41] essentially, right, an interpreter that you would compile to WebAssembly instead, which some people do. I mean, there is a Python interpreter compiling to WebAssembly in the linear memory system. It's entirely isolated. It works, right? But if you want to interrupt with JavaScript, then that's not really a possibility.
[23:04] But wasn't GC completely changed that story because now you can actually hold values that are JavaScript objects. [23:13] put them into your objects allocated on the GC, but also go the other way around. Give one of your WebAssembly objects, give them to JavaScript. It can hold on to them. You can have cycles between the GC, and it can give them back to you, and then you can call your methods again and manipulate these things, right? So that completely changed the game. [23:43] in one browser. We sat down, there were two of us, worked for six months, and we had Scholar.js and WebAssembly. [23:53] So... [23:54] Remember earlier I talked about the fact that Scala, Scala.js, and Scala.native are three dialects of Scala, right? So they're languages that have a set of semantics and you can do things with them. And so Scala.js on WebAssembly. [24:12] is really that. It's not Scala Wasm. It's Scala.js. It's the same language. It's the same dialect that you can compile to JavaScript, and now you can compile it to WebAssembly. So you get all of the JavaScript interop for free. The compiler is doing all the hard work for you. You don't have to think about it. You can write calls to your JavaScript objects, methods, put them into fields,
[24:42] call higher order functions, give them Scala functions, and get back results. It's all as was always possible. [24:53] you can write subclasses of JavaScript classes and implement methods and it all works. So in that sense, [25:03] the WebAssembly backend for Scala.js is really an alternative backend. You can flip a switch in your config and suddenly you have WASM. It works the same. You can see it works the same. [25:16] And if you're lucky, it's faster. If you're unlucky, it's slower, depending on your workloads. [25:25] But there is one thing that you gain from compiling to WebAssembly is that you can leverage JSPI, the JavaScript promise integration feature of WebAssembly. And that's a game changer, because on the web, on JS, you can't ever wait. [25:46] not wait for a promise to resolve. You have to yield to the event loop somehow. But with JSPI, as long as you enter somewhere into an [25:59] JSPI async function, then you can [26:03] Call as many methods as you want, put as many normal looking methods as you want on your call stack, and then somewhere deep inside your call stack,
[26:12] wait for a promise to be resolved. And JSPI is going to suspend your function call, yield to the event loop, and eventually when the promise gets resolved, your stack gets resumed. And that's a complete game changer because now you can write applications in synchronous style and somewhere deep inside, do an IO call, wait for the result. It's all free, right? So can you just walk us through maybe [26:42] uses VASMGC [26:44] Does it map Scala classes directly to asm structs and arrays, or is there still some magic happening to make Scala semantics work? [26:52] For the most part, we do what you would expect if you've ever thought about how to compile a Java-like language to Wasm. So every class becomes a struct. Subclass relationships translate into subtyping relationships between your structs. You have a first field in every object that's your Vtable. [27:22] about the class name, its runtime metadata, if you need it. [27:29] And then some more elaborate system for interface method dispatch, which is absolutely atrocious performance-wise. But that's another story. So that's what we use. So that works because by default, in the semantics of Scala.js, Scala classes and instances of Scala classes are opaque to JavaScript.
[27:59] it can hold on to it. [28:02] pass it around, store it, give it back to Scala eventually, and then Scala can again pick up from there, call its methods, access the fields. But JavaScript itself cannot, by default, see any of the fields or methods that are defined in your Scala class. That's great for us on WebAssembly, because right now on WebAssembly on JS, if you have a wasm struct and you give it to JavaScript, there's nothing you can do with it. [28:32] not even like [28:33] caught too straight. [28:36] So, [28:36] That fits mostly with our semantics today. So then you're going to ask, but how do you interrupt with JS? Like what if you want to call a JS function that expects an object that has certain methods that uphold some interface? Well, that's then a different hierarchy. [29:06] side hierarchies. One for what we call the Scala classes, which have the semantics as just described, and then one for the JavaScript classes. And JavaScript classes have JavaScript semantics. They have runtime method overloading, for example, whereas Scala classes have compile-time method overloading. JavaScript classes can only extend JavaScript classes. They can implement JavaScript interfaces. But you cannot have a JavaScript class extend the Scala class or conversely.
[29:36] an instance of a JavaScript class as an instance field of a Scala class, and conversely, you can even instantiate generic parameters of a Scala class to a JavaScript type, and conversely, right? It's just the inheritance relationship that is not allowed. [29:55] And so if you have a JavaScript class, even that you wrote in Scala.js, right? It's just you write a class in Scala.js. It extends to JS class. It becomes a JavaScript class because of its belonging to the hierarchy. And then all these public members are... [30:12] automatically visible to JavaScript through the usual JavaScript property resolution rules. So how do we compile that to WebAssembly? Well, [30:23] exactly the same way we compile it to JS, which is that those classes, we actually generate JavaScript code for them. So in JavaScript glue code that we generate automatically, we define the classes, we define their fields, their methods, but the body of each method is calling to the web assembly implementation of those methods, right? And that means you can extend JavaScript classes, [30:53] the implementation of their methods, [30:55] are calling into WebAssembly. And this is how Scala.JSON was works. So we have this, this, these two hierarchies that are [31:06] separate from a class inheritance point of view,
[31:10] the Scala classes that are compiled to structs and are opaque to JavaScript, the JavaScript classes are actual JavaScript objects that are therefore visible and entirely manipulatable from JavaScript. Well, so there's a lot to unpack. So I want to dive a little deeper. So you said JSPI is very important for this. So just to take a step back, one of the trickiest parts of WebAssembly [31:40] is famous for being really good at it, so you can interact with React code if you want. [31:47] When comparing to JavaScript, when comparing to WebAssembly, how do you technically handle that boundary? If I pass a Scala object to a JavaScript function or the other way around, so what is actually crossing the boundary? Right, so we [32:03] we touched a little bit on that already, right? So the thing that we give to JavaScript is the wasm struct, right? And with wasmgc, that works, right? You can give a wasm struct reference, give it to JavaScript, and it can hold on to it, right? So this is what happens, except it's opaque, right? The only thing you can do is give it back eventually. So this is how it works. And [32:31] Interop still works because for the interop aspects, we have the JavaScript classes that are different. There is one additional thing that is interesting
[32:41] very unique in the way that we compile to WebAssembly on the JS host. [32:48] is our handling of primitives. If you have an int, 32-bit sign integer in Scala, and you give it to JavaScript, to a function that accepts an int in its declared type signature, or pretty much any language, including linear memory languages that have some sort of FFI with JavaScript, will then convert that in a way that your int becomes a JavaScript number in the right range. [33:18] If you get it back, get the same, right? What is unique for us is that if you... [33:25] put that primitive int inside the generic context, like in a type parameter, or you upcast it to any. [33:36] Usually what happens and what happens on the JVM, for example, is that you box that primitive int inside a... [33:44] class inside an instance of java-long integer, for example. If we did that, then as soon as we enter a generic context, we would have an instance of java-long integer, which is a scalaft class, which is opaque to JavaScript. We would give that to JavaScript, and JavaScript would say, I can't add that. It's an opaque struct. It's going to throw a type error. So, [34:10] What we do instead is...
[34:14] When we upcast or put in a generic context, which is the same because of type erasure, a primitive int inside an any, [34:22] we turn it into a JavaScript number. [34:26] Right then. And how do we do that? Well, we call the JavaScript function that is an identity function from the JavaScript point of view, except its WASM signature says, I'm taking an I32 and I give you back an NERF. And because of the magic of how JS interoperates with WebAssembly, that gives us a JS number. [34:51] inside an edref. And this is the thing that we manipulate. If we have to cast it back down or take it out of the generic context into being a primitive int again, we ask JavaScript again to do the conversion for us. And this way, even if it's already in a generic context, and we give it to JavaScript, [35:14] Well, it's a JS number. So JavaScript sees the JS number and it's happy to perform an addition on it. Right. So we do that for all the primitives and it works. Semantically, we achieve exactly all the right semantics. [35:29] It is however dreadful for performance because that means every time we upcast or downcast or perform a type test on an int, we have to ask the JavaScript, the WASM JavaScript boundary to do some work for us. And that boundary is...
[35:47] terribly slow. So yeah, it works. But if you have to box a lot of integers or Booleans or doubles or whatever, then you're going to hit that boundary way too often. [36:03] For ints, we actually can most of the time avoid that using a trick with i31ref. So it's actually kind of okay. [36:14] If it were not, I think that the whole performance story would be completely dead. But because of that trick, it kind of works, but it's still a pain for booleans, for doubles. [36:28] So that's not great. This is precisely what I wanted to address with a proposal I made to WebAssembly, which is now at phase two. It's... [36:42] javascript primitive built-ins so that would be a small [36:46] ish set of wasm.js built-ins. So special functions that you can import into your WebAssembly module, and that are actually provided by the JS engine itself, rather than being written in JavaScript code. [37:04] to perform these conversions. So, for example, the boxing of an i32 into an NERF. And then, [37:11] It would still have to perform the same conversion, of course, which has a cost. I mean, you need to allocate a heap number and stuff. But at least you're not crossing the WASM to JS boundary back and forth. And so you can cut a lot of the overheads from that. So this proposal is going to help a lot for that use case. And we're going to be able to fix that performance issue.
[37:37] We will talk about the exciting VASM proposals that you're championing or interested in a little bit. I was about to ask about performance, but you answered that already with great detail. You mentioned all primitives, but JavaScript has gotten one more primitive recently, which is recently-ish, which is BigInt. Do you have BigInt support as well? [38:01] uh yes i know big josh begins as seen from a [38:06] from Scala.js is... [38:08] some JavaScript thing. You can call methods on it. You can... [38:13] apply operators on it but there's not a corresponding scala primitive so we don't have that problem i mean basically it's it's as if it were any other object the fact that it happens to be a [38:31] is of no real concern for Scala.js as far as that is, as far as BigInt is concerned. Understood. Cool. So Scala.js is mature. It's been released many years ago. Its ecosystem of libraries has had many years to develop. There's a page called Scala.dex, the Scala library index, and according to this Scala.dex, roughly one third of Scala libraries are available on JS as well. [39:01] of the library ecosystem for the BASM target? And more forward-looking, is it realistic to build a full application in Scala.js on WebAssembly today? So usually when you have a new ecosystem of libraries, and Scala.js was like that, you build a compiler and then you can use a standard library because you compile the standard library with your compiler to JS. And then you can write small
[39:31] of the libraries that people have written before because those are compiled to JVM class files. And yeah, so you need a lot of time for the ecosystem to first take you seriously and willing to update their build and publishing procedures to also build the [39:52] Scala.js version, publish that to Maven Central, the JVM repository of libraries. So it takes a while. [40:01] And for Scala Native, same story. It takes a while for your ecosystem to catch up with the fact that, yes, you're actually serious about this new target. And yes, we should invest in making it work. For the Web WebAssembly targets... [40:20] Since we're actually compiling the Scala.js semantics, [40:25] just to a different backend, we can actually reuse all the libraries that have been published over the last five years. So you take any library that was published for Scala.js, [40:41] the binaries that are readily available for you. You don't have to wait. Today you can use this entire ecosystem of Scala.js libraries, compiling them to WebAssembly. The only thing you have to do in your build to switch, I'm going to target WebAssembly, and then your build is going to generate WebAssembly for all the libraries that you're using. So, um,
[41:07] I mean, assuming you believe that it's realistic to build an application using Scala.js today, which I believe many people do too, then it's also possible right now to build it with WebAssembly because you have your entire ecosystem. I mentioned Tyrion and Leminer earlier, front-end libraries. [41:27] You can use them from WebAssembly. I have a personal project where I do that. I [41:34] use all those libraries just like that and compiling through a assembly. [41:39] So yeah. Nice. We can link to this project in the show notes if you want us to. Can you just provide some background compared to maybe [41:48] the paradigms of how it would have been had you programmed this in JavaScript, regular JavaScript, versus how you approached this in Scala.js? You mean from the front-end UI point of view? Anything really, like from the programming approach, from the programming paradigms that you use, but also from if you build the front-end choices that you had available and so on. [42:18] mindset when it comes to your UI, right? You write your entire application in this FRP style, which is fairly comfortable. That is more or less like you would do in Scala.js usually. It doesn't really change the story much. There is one thing. Again, I mentioned earlier JSPI, and this is the reason that this specific application I compiled to WebAssembly. It's
[42:48] It's a game. It's a maze game. You can customize it. You can write your own squares, effects, things like that. So basically, script the game, right? And to do that, well, somewhere inside your script, you might want to display a message to the player or ask for a confirmation or something. And it's a game. [43:12] If you had to do that on JS, waiting for the reply of the user is not something you can do. You will have to register a callback. And then that means your entire scripting experience needs to be asynchronous, work with promises. It's a nightmare if you want to explain that to someone who's not a professional programmer, right? [43:42] really synchronous way I can write show message or ask confirmation and I receive a result. [43:49] Right there. I don't have to play with callbacks or promises or anything. JSPI is providing all the magic for that. So that's really, really nice. [44:01] Yeah, that's good. Talking about the WebAssembly starting point, there was some confusion or doubts about which of Scala.js or Scala native would be the best starting point to compile a Scala. You said it's different languages, it's different dialects to WebAssembly. But now that WebAssembly is also entering the picture, particularly with VASI, the WebAssembly system interface,
[44:31] seems to blur a little. So is the VASM backend purely a Scala.js thing for browsers, or do you see a future where a Scala native could target VASM as well for server-side workloads with maybe even the component model, as suggested by a blog post by a company called VirtusLab? [44:48] Right. So Scala.js, as a dialect, it really wants a JS host, right? If you're not going to talk to JavaScript libraries, then Scala.js as a language means nothing. Nothing works. So Scala.js on Wasm is definitely for the web or at least for JS engines. I mean, you can run it on the server on something like Node.js or something, right? Which... [45:14] you might want to do. [45:17] But there's no way you're going to put it in the WebAssembly container that doesn't have a GSHost and that provides you with a component model instead. [45:27] So... [45:28] For that, we are working on... [45:34] a new dialect, which this time I guess we could call Scala WASM or maybe Scala CM for Scala in the component model world. And then the question is more indeed relevant. Do we want [45:52] to use the Scala.js compiler architecture or the Scala native compiler architecture to build this new dialect? Or do we need an entirely new architecture? Right? And then it's not really about this. It's not a question of semantics. It's really about the question of compiler design. Like how do you design your intermediate representation? How do you design your optimization pipeline? So,
[46:20] For that, you could indeed make the case that Scala Native would be a better starting point as a compiler architecture. But the problem remains that you want a GC. And if you're going to use Scala Native, which has a pipeline going through LLVM, [46:50] linear memory. And you're not going to get a GC. You will have to build your GC yourself, which is what Scala Native does when it targets the native code, obviously. But if you target WebAssembly in the linear memory and you want to build your own GC, it's really, really difficult. And there are some [47:11] really hard roadblocks there. You can't scan the stack, for example, to get your roots. So you have to build shadow stacks and a bunch of things like that, right? So... [47:22] It's a lot of work. [47:26] And... [47:28] If instead you want to reuse wasmgc, but not in the JS host, right? Just wasmgc in a wasmvm that is a server side without JS, then you get the GC for free. And that's what you really want, right? For all sorts of reasons. [47:49] But then if you start from Scala Native,
[47:53] going through LLVM [47:55] you have a really, you have a big problem, right? Because LVM is not going to use WasmGC. They're not going to change that. It doesn't fit, the entire architecture of LVM is geared towards a linear memory model, right? So this is not going to happen. So then, could you intercept the pipeline between Scala Native and an LVM and target WasmGC instead? [48:25] key slope to recover the GC abstractions out of your linear memory IR, which ScalaNative uses for optimizations and stuff like that, right? So... [48:38] As opposed to coming from the Scala.js community, [48:41] compiler architecture which is oriented towards a GC target. Yes, there is more work to do at the language level to interrupt with a component model. And you might even argue that lowering that down to WebAssembly is still a bigger [49:04] diff compared to coming from Scala Native, except going uphill 20 meters on a ski slope is much harder than going downhill three kilometers. And with compilers, it's exactly the same thing that happens. It's much easier to get down three kilometers of abstraction levels
[49:34] Let's compare the architecture [49:37] to wasmgc without a gc without a js host but with a component model and this is what we're currently doing and the blog post you mentioned uh was i think written by rikito taniguchi who is working on this new dialect of scala [49:56] for the component model using the entire Scala.js compiler architecture to target WebAssembly in the component model. So there we definitely have a future. I'm eager to see what is going to happen there. [50:15] When... [50:17] difficulty in getting now your GC language... [50:22] inside the component model is that the component model itself, currently its main and only ABI is linear memory oriented. [50:35] So you can compile down your interrupt with the component model to the linear memory so that you can talk to the component model and then back into your GC structures. [50:46] This is all fine for immutable structs and records, lists, because it's basically serialization, right? You can take an immutable structure, serialize it however you need to talk to your... [50:58] function, get it back, deserialize it into your structs. But if you have a component model resource, which is a handle to a stateful entity, that's more problematic, especially because at some point, the resource expects you to drop it.
[51:21] If you have a linear memory language, you typically have a built-in, a well-defined point in time where you free your objects. And that's the time that your compiler would call the drop operation on the WASM component model resource. But if you have a GC... [51:46] There's no point in time where your GC object is going to be freed. Wasm doesn't even let you see that. It doesn't have weak references. It doesn't have anything. So there's no... [52:01] no way your compiler can decide to call drop at the right time. And that's going to be a challenge. Do we... [52:07] enhance the component model to be friendlier to GC languages, which is probably the most promising option, but might be very difficult. Or do you then require your user of your GC language [52:24] to actually put in their source code an explicit call to drop to compensate for the fact that the compiler cannot do it for you it's not as nice but yeah you know it's better than nothing i can see already we need to have you on in maybe six years so six years or so when the scala vasem back end is uh fully baked out um but for now let's say a little closer to what we can do now so
[52:54] for the WebAssembly target as it is today. There's some limitation with JS export, for example. Are there any other gotchas blockers that you should be aware of before you flip that with experimental use WebAssembly switch to true? Anything you want to give developers on the way when they are about to make that switch? [53:18] Right. So there are two things. One thing is simply something we haven't implemented yet, which is multi-module support. In Scala.js, you can configure your builds to image not just one giant JS file with your entire application, but you can decompose it, split it into modules that are either statically loaded depending on the points or even dynamically loaded using dynamic import calls of JavaScript. [53:48] Overbessingly, we haven't implemented that yet. There's nothing blocking us from doing it. It's just we need to sit down. [53:55] for a few weeks do it and ship it. [54:00] The other thing that is much more problematic is those at JS export annotations. Remember when I said if you have a Scala class, an instance, and you give it to JavaScript, it's opaque and you cannot do anything with it from the JavaScript side. Well, I lied. [54:18] Because there is one thing you can do with them. It's called methods that have been explicitly annotated with at JS exports.
[54:30] and scale a [54:31] class method with a js export we make sure that the js object that we [54:38] which give to JavaScript has a meaningful method with that name that accepts arguments and that will then call the inner code that sits within Scala, right? And you can also annotate properties with getters and setters. [54:55] in the same way. And so with WebAssembly, that's the one thing that we cannot implement today because wasinstructs [55:05] is opaque to JavaScript, and there's nothing you can do about it. So they're always stuck. And that's the one thing that we say, "IJS exports," that whys them back and just ignores it. [55:19] Fortunately, few code bases actually rely on that anymore, since in most situations where you need to give something to JavaScript that JavaScript can call methods on, you would actually give a [55:35] compared to separate. [55:36] actual JavaScript objects. So all of that works. But still, the AdJS exports, they don't work. [55:45] But for that, there is a proposal in the pipeline, not by me this time, but I'm contributing fairly closely. Thomas Lively is the champion. It's the custom descriptors proposal.
[56:06] one stays entirely within Western core. [56:09] It's so that you can attach descriptors to structs. And the descriptors can, for example, hold your virtual method table. And then the engine can fuse [56:20] your descriptor [56:22] with its engine-level metadata for the objects, right, for the GC to work and stuff like that. So you... [56:31] you remove the footprint of every object by one word because instead of having the engine hidden words plus your vtable world and then only the user level fields you only have the engine level word which also acts as your vtable because it's a descriptor and then the user land fields so that's one thing and then the second so that's that's a that's a [56:55] optimization-oriented feature, if you want, from our perspective, which [56:59] we will use. But then on descriptors, you can add a special field that will act as the JS prototype of [57:12] wasm structs that use that descriptor. And that's exactly what we need to implement ajs exports because now we can attach on the Scala class that defines an ajs exported method, foo, we can in the descriptor for that class, [57:31] put a prototype that has a foo.js method that then calls into the WebAssembly implementation for the methods. And this is exactly what we need. And it will...
[57:47] fix that last one percent of semantics we can't yet compile. We already have a PR. Open can't merge it because it's not stable in V8 yet. But we have a completely developed PR with all test passing, including all the IJS export test passing that targets the custom descriptors. So I'm really [58:17] finish our support. We will actually be able to claim that we have compiled Scala.js, the full dialect to WebAssembly. Oh, very exciting. So you mentioned a bunch of proposals already. So there was the custom descriptors one just right now. Before, you mentioned your built-in printatives proposal. I forgot the exact name. I [58:42] I think stack switching is also something that is of interest to you. Can you just very briefly, because we're already running a little late, summarize what other proposals you're interested in in the WebAssembly world? All right, so stack switching is definitely something that we're looking to. We don't have anything like that today in the Scala [59:03] languages. So we'll see what the stack switching offers us and will provide [59:10] language features to use that power eventually. Another one that [59:16] We'll definitely look into with the shared everything proposal, right? So because that would theoretically allow us to have multiple threads sharing GC memory, which would...
[59:33] and expand the possibilities of Scala.js as a language. Currently, Scala.js is single-threaded by nature, whether it targets JS or WebAssembly. But with a shared everything proposal, we could consider adding short memory threading support. [59:53] nice very exciting so yeah this already brings us to the end of the show i feel like we could go on forever but yeah i just wanted to leave sometime for the last part which is a basm but not which always [1:00:08] helps us understand a little more about you as a person. And when you, Sébastien, instantiate streaming on any of your streaming devices, what is it that you currently watch or listen to? [1:00:20] Well, right now we have started watching X-Files, the good old series at my wife's suggestion. Yeah, exactly. That one. There I am singing. And I promised you won't sing. Yeah, yeah, you did. You did. [1:00:50] That's one thing that I listen to a lot. And watching is a lot of Zelda lore YouTubers who create content about the Legend of Zelda game.
[1:01:04] So when people talk about film music, one name typically comes up, which is Hans Zimmer. Is that you as well? [1:01:12] Hans Zimmer is definitely up there in the top composers for music. [1:01:20] the most famous one. James Horner is also a big name. [1:01:27] And then, yeah, several others that we like. And of course, for the video game music, it's Koji Kondo. He composed most of the Zelda musics. Mario as well. He's a legend. [1:01:43] That's definitely a legend, yes. Cool. And then the final question, if there's one thing that you could local get [1:01:50] in something that you do, and then global set as in something that you wish everyone else did, what would it be? And of course, as always, if you wish, you can also swap the question around. So yeah, what is it that you would look at global set or vice versa? I wish every Scala developer hesitated with the Scala 2 braceful syntax and not went to the indentation-based syntax that Scala 3 added to the language. But that's not going to happen. [1:02:20] yeah that's interesting because I've read on Wikipedia about this guy that people really were into this change so you don't like it? [1:02:30] No, it's too hard for me. It doesn't work with my brain. I need to spend too much brain power to parse indentation beast code. I like to do braces. I'm going to keep writing my braces.
[1:02:45] That's interesting because I think people like Python also just because of that, but [1:02:54] Do you enforce any kind of indentation with, I don't know, what the Scala.js version of Pretia would be, like a JavaScript kind of beautifier? Or do you just code well-intended as well, but indent it anyways? [1:03:12] Yeah, I'm a bit particular. I still format all my code by hand, but most Scala developers don't do that. They use Scala FMT, which works the same, whether it's Scala, Scala.js, Scala native. It works at the syntax level, so this is all the same. So yeah, most Scala developers use Scala FMT to enforce a specific coding style and... [1:03:35] Yeah, that's... [1:03:36] All right. Yeah, that was kind of surprising insights here, but yeah, that's why we have this session. And the final, final question. So if people, after listening to this episode, after watching this episode, if you watch on YouTube, have any more questions about you, the ecosystem, they want to know how to best get started, [1:03:59] what would be the best way to do so? Do you have social presence? Do you, I don't know, have a forum, discord? How can people reach out? Right. So one important source of information is Scala long on all the socials, either Scala_lang or Scala_lang depending on the particulars, which is for all
[1:04:29] We have the same for Scala.js. So again, Scala underscore JS or Scala dash JS for Scala.js specific things, including Scala.js and Wasm, obviously. And then if you want to reach out, the best is probably the Discord server of Scala. You can find it at Scala Discord server. We have a Scala.js channel. I'm looking there all the time. So you can reach me there. Nice. Brilliant. Cool. So with that, thank you so much, [1:04:59] This was very insightful, and I learned a lot about Scala.js, about the Scala ecosystem, about why you don't like the annotation system that they introduced. [1:05:12] I will definitely play around with the Scala.js Playground as well, which is something that you can just do in your browser. There's no install or anything required. Just hang out and play. And, yeah, with that, also thank you, listeners, watchers, for listening or watching. [1:05:29] And if, as always, you have something interesting to say in the world of WebAssembly, be sure to reach out. I am Tomajak on all the social networks that you can think of. I mostly hang out on Mastodon, but I watch everything else as well, except for maybe Axe, which is something I stopped actively using. And yeah, with that, thank you, Sébastien, again, and happy next time. Goodbye.
[1:05:59] Thank you.
Want to learn more?