I'm trying to figure out what Extism is actually providing here.
The underlying runtime appears to be Wasmtime, an existing project that you can use separately.
For the system API, Extism supports WASI (a POSIX-like API for WASM) which is already supported by Wasmtime. However it sounds like it also has a different, non-WASI API that provides similar functionality. I'm curious to hear a compare/contrast between these two system APIs, or what motivated inventing a new non-WASI system API. It does appear that WASI is in its early days; WASI was announced in 2019 (https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webas...) but it appears that all of the specific proposals are still early stage and far from being standardized (https://github.com/WebAssembly/WASI/blob/main/Proposals.md).
For the API, Extism provides a C API/ABI that can be called through FFI, but AIUI Wasmtime already has such an API: https://docs.wasmtime.dev/c-api/
Basically I'm trying to understand the conceptual difference between this project and Wasmtime.
It's a good question. It's hard to understand what all is involved in building something like that until you have to get into the details. You can think of Extism as a layer around wasmtime. There is an ABI of sorts that helps you communicate with the plugin: Send data to it, invoke functions, and get data out. With our system, you don't need to enable WASI to use a plugin. You can invoke functions directly. However, you can use WASI for other purposes. And we are working on a way to do POSIX-like stuff (e.g. programs with a main function that use stdin and stdout).
Because we wrap wasmtime, we can also switch it out. That's how we are able to run the same plugins in the browser. There we use the browsers' implementation.
I think one day we will replace some internal pieces of Extism with pieces of the Component Model spec. As of today it's not in a state where we can do all of this in this many languages.
That makes sense, thanks. It sounds like a key difference is that Extism is trying to be portable to both web and standalone WASM runtimes. And maybe part of the motivation for a new WASI-like API is that WASI doesn't aspire to be portable to the web, and Emscripten's standard library only works on the web, whereas your system API is designed to be portable to both.
Yes I think that's a good way of putting it. Extism's primary goal is universality. I think the idea of having a plug-in system that is truly universal is exciting. Now we can share and maybe even sell plugins into different ecosystems. No more silo'd environments. I hope to see a future where standards can be built on top of this and plug-ins can outlive the applications themselves. Think VSTs if you are into music software.
That's interesting, one of examples that is challenging is a universal html template plugin. I'd love to try if it's feasible. Basically it should be logic less like Liquid. The unsure part is the custom tag, can it be called by host or not.
Linking wasmtime with host functions through the c abi is a bit cumbersome so I believe (in theory) this product can serve a real need by making plug-in integration more streamlined. Wasm as new plugin target / intermediary is a nobrainer (unless your game is written in c# or you like lua)
Hey! Super exciting to see your progress on Extism.
I'm Syrus, from Wasmer. I did a quick review of your plugin architecture and it looks great (tons of languages supported, congrats!). I think Wasmer might be able able to help you so you have the same implementation of the runtime inside and outside of the browser (something similar as we did in wasmer-js [1], where we reuse same WASI implementation, but using the native Wasm engine from the browser).
I'd love to see how we can integrate your plugins into Wasmer as well!
Syrus, thanks for the kind words! Would love to work with you on integration. I'll reach out & find some time to sync up on it. Or, feel free to join our Discord and we can loop in the team: https://discord.gg/cx3usBCWnc
Looks interesting. Based on prior experience, here are some concerns people will bring up with this approach:
1. Spectre. You may have to assume the plugin code can read anything in the address space including any secrets like passwords, keys, file contents etc. If the plugin can't communicate with the outside world this may not be a problem.
2. When you say WASM has a "sandboxing architecture", this is only partially true. It's quite easy to define a simple language that doesn't provide any useful IO APIs and then claim it's sandboxed - that's practically the default state of a new language that's being interpreted. The problems start when you begin offering actual features exposed to the sandboxed code. The app will have to offer APIs to the code being run by the WASM engine and those APIs can/will contain holes through which sandboxed code can escape. If you look at the history of sandboxing, most sandbox escapes were due to bugs in the higher privileged code exposed to sandboxed code so it could be useful, but you can't help devs with that.
3. WASM is mostly meant for low level languages (C, C++, Rust etc). Not many devs want to write plugins in such low level languages these days, they will often want to be using high level languages. Even game engines are like that: "plugin" code is often written in C#, Lua, Blueprint, etc. This is especially true because WASM doesn't try to solve the API typing/object interop problem (as far as I know?), which is why your example APIs are all C ABI style APIs - the world moved on from those a long time ago. You'll probably end up needing something like COM as otherwise the APIs the host app can expose will be so limited and require so much boilerplate that the plugin extension points will just be kind of trivial.
I've been saying it for years, but I think finally 2023 has the chance of being the year in which Wasm GC ships and managed languages start targeting Wasm more widely. We've made a lot of progress with the design, and V8 has a basically complete implementation. Google is targeting some internal apps to Wasm GC and seeing perf improvements over compile-to-JS, so I think this will likely be a success.
That would be cool but I wonder how much difference it will make. Most managed languages share at least two attributes:
1. Large runtimes and std libs. Python's "batteries included" is the epitome of this but even just java.base is large. This doesn't play well at all with browser cache segmentation.
2. You need a JIT for performance.
A good test of whether WASM is really heading towards generality is whether you could implement V8 as https://www.google.com/v8-js.wasm and just auto-include it into HTML pages for backwards compatibility. I know you have unusual experience and expertise in meta-circular VMs - is WASM really heading in this direction? The two obvious sticking points today are: V8 would get downloaded fresh on each origin, and JITd fresh on each page load, and what does such a runtime emit as compiled code?. Is your JITC being JITCd by a JITC and if so is the JITCd output then being JITCd a second time? If so, how on earth does this make sense?
An alternative would be to explore whether the process level sandboxes are now good enough to just allow native code to run inside them and let people use their existing managed language VMs. Google thought that was close to plausible many years ago with NaCL, and kernel sandboxes got a lot stronger since then. It seems we ended up with WASM more due to Mozilla politics than what makes sense technically.
Indeed. With the web's model, it seems tempting to make the browser cache do the work for you by putting the language runtime at a standard URL. That works, modulo the security features today that cache Wasm modules per-origin to avoid an engine JIT bug creating a cross-origin vulnerability. GC helps a bit with that in the sense that the GC algorithm itself moves down into the engine.
> 2. You need a JIT for performance.
I worked a bit on a prototype JVM on Wasm that used the Wasm bytecode format to encode Java constructs. That helps because then you don't have another bytecode interpreter running on level up, but ultimately you want somewhat more control over the JIT and the code it generates. Wasm engines supporting dynamic code generation at all (any finer-grained than a module) would help a lot there.
Compiling V8 whole-hog seems like it would take a lot of doing. In particular, it has JITs and an interpreter that want to spit out machine code. That'd have to be replaced with Wasm backends.
> It seems we ended up with WASM more due to Mozilla politics than what makes sense technically.
The politics were...complicated. I'd tell my side but it's probably best I don't.
Hmm interesting. I thought the cache segmentation was to block timing attacks by the web server (measure time between first page send and js execution to figure out what files are cached i.e. your browser history). I didn't realize it was due to lack of confidence in the JIT. Isn't a WASM JITC a fairly straightforward thing?
Re JVM on wasm with gc: it might be simpler at first to build a Graal/native-image backend for wasm+gc. No runtime JIT needed. Happy to join in on the fun.
> 1. Large runtimes and std libs. Python's "batteries included" is the epitome of this but even just java.base is large. This doesn't play well at all with browser cache segmentation.
Right but that's only one, niche use case (why you'd want plugins in a web page ?).
Even if you are web app with plugins
* that is not a problem for first load, user adds plugins later once they get familiar with the app
* you can still (I assume) just download it in the background and shove it into local storage
The whole use case seems to be "there is an app that would benefit from plugins and we don't want someone to learn the language just to write that plugin" and the idea is pretty sound - WASM embeds well and is fast enough.
I think there’s somewhat of a disconnect between the original idea of WASM (in browser) versus headless. In the browser folks get JavaScript for free which collects its own garbage. WASM is there to supplement higher level language for performance-intensive tasks and as such, “lower level” languages make more sense for these code paths.
I’d like to point out also that providing users a million languages to write plugins in for a product could create a lot of bloat. Imagine an image editor with 5 plugins, each written in its own language running in WASM sandboxes: golang, C#, assemblyscript, ruby, python. That’s 5 runtimes each running it’s own garbage collection logic.
I can see the value for compute hosts because the very nature of the provided service is allowing users to write sandboxed apps. But I think for stand-alone applications it’s best to support one or two simple targets, whether sandboxed or otherwise.
There are languages (Lua for example) optimized for this already.
I suppose the benefit is that each application which uses the WASM backend can decide on their “official” language and provide a decent built-in IDE experience.
I don't think WASM should/would unify the GC across memory models, that could be extremely problematic.
The gist of the idea is polyglot languages can leverage libraries across many languages. The fastest code is the code that was already built (that you didn't need to write).
It's unlikely applications would actually implement libraries from 5 different runtimes (they could, but shouldn't), and if they use RUST libraries, there definitely wouldn't be any GC anyway.
The benefit of this tech is it allows a new language to leverage historical codebases quickly without needing to re-invent every common utility library.
This will inevitably speed adoption of newer languages, zero code tools, etc .. and is the epitome of Proebstings law, which could also accelerate Proebstings (which is every decade) to being to approach Moores law (but I'm not specifically saying that will happen, only that it could).
> I don't think WASM should/would unify the GC across memory models
WASM already has a GC proposal[0] which is already at the "Implementation stage"[1] so it looks like this IS going to happen, although it's uncertain if language runtimes like Go will actually make use of the feature, or what.
A glance of the overview and spec seems to indicate that WASM will provide some primitive data types, and any GC language can build their implementation on top of it. As I understand it, it's heavily based on Reference Types[3], which allows acting on host-provided types, and is already considered part of the spec [4]. It doesn't remove the need for the 5 different runtimes to have their own GC, but it lowers the bulk that the runtimes need to carry around, and offloads some of that onto the WASM runtime instead.
A one size fits all GC is never going to be a great solution though, is it?
Different languages have different GCs that are designed to work with their semantics. Some languages use a flag bit to tell the runtime if a value is stack or heap (Go, Ocaml), some languages allocate almost everything and assume a lot of short lived objects (Java)...
But the competition is compile-to-javascript, which has exactly the same problem. With WASM, you get to choose between using a generic, potentially sub-optimal GC, or having a larger payload and including a GC bundled with the application.
There's no such thing as one-size-fits-all GC. Wasm GC will probably be just as successful as other attempts at generic "managed" runtimes, which is to say, not very.
One is the implementation, e.g. the GC algorithm. They vary widely in their performance characteristics. For the most part, they are semantically invisible. I fully expect many different engines to have different algorithms, and ultimately you can choose and tune the GC algorithm to your application's needs.
Two is the semantics. We're aware of many failed attempts to make generic runtimes, and a critical factor is how universal the object model is. Of the many over the years, most have originated for a single language or paradigm of languages and have, in some sense, too high a level of abstraction. Wasm GC is a lower level of abstraction (think: typed structs), from which higher level constructs are implemented (like vtables, objects, classes, etc). Being lower level is a tradeoff towards universality that we have consciously made. That said, there are downsides, such as more casts, because it gets increasingly harder to safely encode invariants of source languages to avoid such casts at the lower level. We're OK with the overheads we've measured so far but are always looking for mechanisms to reduce or eliminate these.
> We're OK with the overheads we've measured so far but are always looking for mechanisms to reduce or eliminate these.
You could encode arbitrary invariants by implementing verifiable proof-carrying code within Wasm. Then a wasm-to-native compiler could be designed to take advantage of such invariants in order to dispense with these overheads.
That's a legitimately neat idea. There are couple of projects to improve safety of Wasm code using linear memory (such as RichWasm by Amal Ahmed and MSWasm by a number of folks at Stanford, UCSD, and CMU). Obviously unrestricted aliasing of the giant byte array that is memory makes this more difficult. I hope that Wasm GC can offer an abstraction base to express even more invariants. In some sense that will be a study in adding more powerful types and more powerful proof constructs that are either on the side or embedded in the code. So, exciting future directions!
There are, Go can also be compiled to WASM, but it has to carry the whole Go runtime with it (including but not limited to the GC), so the WASM files are a bit fat. You can however use TinyGo, a "Go compiler for small places" (https://tinygo.org/).
Yeah, I get the runtime can be big, but letting gc cross module boundaries seems really bad for sandboxing. I also kind of wonder why we'd want to use those languages in wasm other than their libraries and runtimes. If all you want is gc and performance why not use JavaScript or typescript? C# or go after a ~20% wasm penalty isn't going to be that much faster than js right? Or use something like nim that compiles to js and get libraries as well. The case for wasm always seemed to be absolute max performance in a safer package, which would send you towards languages that support manual memory management anyway.
One of the improvements that you get from the coming Wasm GC proposal is an object model that is inherently more space-efficient than JavaScript. While a lot of speculative optimizations can make JITed JS (of the right form) run fast with few checks, the object model inherently requires boxing or tagging and is not as memory-efficient as what Wasm GC structs give.
Lots of good points here. I'll try my best to address them. But you are right, There aren't really complete answers to each of these problems.
Regarding #1, it's good to point out that spectre is still an ongoing problem. wasmtime, the runtime we use, has mitigations for spectre but things will likely come up. I think we need more time and tools to work on things like detecting attacks and mitigating future problems. Fortunately there are some big companies working on it. Our team cannot solve that problem.
Regarding #2, sandboxing here refers to the memory access model and fault isolation. For each capability you give the plugin you may introduce risk. We don't claim to address this problem but I think education and mitigation are good goals for us.
Regarding #3, I think there has been some good progress here. I have an experimental C# plugin PDK and a JS one based on quickjs. We also support Haskell. I think there will be improvement here. And regarding the ABI comment, there are going to be layers on top of this to make it more ergonomic.
At least the common plugin language lua runs in wasm, and micropython is less than a megabyte in wasm, so that point is a bit weak. (having an extra level of abstraction may make the plugins minimally slower, but running lua in wasm adds an extra level of security)
Authors are here to answer questions! To add a little bit of detail:
Extism is an open-source universal plug-in system with the goal of making all software programmable. Easily embed Extism into 13 popular programming languages (server or browser) and safely run high-performance WebAssembly plug-ins inside your code.
What does it mean to "make software programmable"? Simply put, you can give end-users the ability to extend your software with their code.
Plug-in systems are usually implemented in 3 ways:
1. execute a binary that is external to your process (like protoc)
2. re-compile a program with an implementation of some interface
3. dynamically link to native code / dlls
All 3 have major trade-offs on the performance-to-security ratio. Extism provides a way to "have your cake and eat it too" in a sense, that it doesn't compromise security for performance. True, executing WebAssembly as we do here is not running at fully native speed, but it's darn close. And its sandboxed architecture offers the security you want if you're considering an alternative to dll/dlopen.
We're only getting started here, and welcome feedback good and bad. Please join our Discord[0] if you want to chat, or open issues on GitHub[1].
There's at least one more approach to program extensibility that you should probably address: interpreted languages, especially Lua. Many games and utilities today use Lua or JS as an extension language. They have battle-tested runtimes, come with high-performance JITs, and provide the potential for rich interactive debugging and incremental development options that are not free with a WASM-based statically-compiled approach.
There are even entire applications written this way - Adobe Lightroom was originally built from some core C++ imaging code lifted from Photoshop but with all of the UI built in Lua. The dev builds of Lightroom have an entire integrated Lua dev environment in them.
This is really interesting to me. I used to run a team that owned a software library (that you've probably heard of) that runs on Mac, Windows, iOS, Android, and embedded Linux. The product is over a decade old, so it's in C++ because that was the only real choice back then. We bolted on static analysis yet still had senior engineers working full time to iron out stability issues (deadlocks and other race conditions). I've been thinking about alternatives for a while now; Rust naturally, but also C# with Native AOT in .NET 7 (only supports Windows and Linux so far, but maybe in the future). It got me thinking though, why have to choose? There are a good number of languages that can compile to WASM, so maybe just bridge the platform-native presentation layer to WASM and put all the core logic in WASM. It "should" provide near-native performance and open up many other languages, and provide a nice migration path to run the existing C++ and new code in another language side-by-side. I know it's not explicitly the goal, but Extism seems like it could provide that functionality. I'll be following this project!
Very interesting, would love to know more about the library ;)
It does sound like you have found a _great_ use case for WebAssembly, and yes, Extism could provide similar functionality! We call it a "plug-in system" because that's a fairly concrete thing to say, but there are many other ways to use it.
Awesome. Now I just need a way to define a cross-language contract and this would be very helpful for my uses.
Ignoring performance for a second, one wonders if you could take proto and use that as the data in/out _and_ the API/RPC definition. Like many others, I've been wanting to add plugin support to my software, but I want a well-defined contract usable from others w/ complex types and known RPC calls. I think code-gen from proto for all supported client/host languages could get you there (at a perf cost compared to flat buffers or capn proto).
I've had great success with a fourth way: my project language compiles to C, which is loaded at runtime with libtcc (specifically: git://repo.or.cz/tinycc). I've gone down the .so/.dll route a few times in the past, but I can safely say: never again. libtcc has the advantages of a jit (native C speed), but with an elegant API and laudable portability.
If that is something you need come join the discord and let's work on it! I've been experimenting with higher level languages, specifically quickjs (js) and c#. Python should work from what I know, but I can't speak intelligently to how well it would work.
Hey folks, one of the authors here. Extism is a plug-in system. If you aren't familiar with this terminology, plug-in systems make your software programmable by end users such as your customers or your open source community (e.g. VS-Code Extensions). Currently plug-in systems are quite difficult to build and limited to certain host and guest languages. Extism makes this easier regardless of your language or domain knowledge.
Thank you - I think the intro page could help make this clearer. I’m not super familiar with the programmable nature of things beyond something like an Arduino, so I was very confused what “programmable software” meant in this context, and the landing page still isn’t super clear in that regard.
Your comment helps - would make sense to recalibrate on the shared page.
Extism tries to cover two completely different things in one package: 1) runtime 2) component model. And this is a problem. Those things should be separated because the component model would be useful independently, without any ties to the specific runtime environment be it WebAssembly or something else.
We already saw this playbook many times before. For instance, .NET. It has a handy set of system types that define the component model, but surprise, it can only be used in the realm of .NET which makes it unusable in, say, Go. Java - the same thing. C++ is the same. Everything more abstract than some primitive data types and plain functions just cannot cross the boundaries between the language ecosystems.
If we had a standard component model then it would allow us to create a library in one language and then use it from many other languages without any manual work. But all we have now is the old plain C-like API as a common denominator between them. It's 1978 all over again for the last 40 years. But I still believe that we can do better than that.
Instead of m * n complexity when every library is doomed to be manually ported to n languages, we may have just m + n complexity by leveraging the benefits of a standard component model. Just imagine the economic effects of such achievement.
The main problem of an imaginary de-facto standard component model is the danger of being opinionated. We should solve that, otherwise all such efforts will be doomed to fail from the beginning.
Data and functions are good starting points, and they are universal by the laws of math and algebra. That's why they are not opinionated. Consequently, they are used everywhere. We should build a similar formal apparatus for, say, objects to allow OOP interoperability between the languages once and for all.
Another marketing related comment: Extism is not a very nice name. It sounds like exorcism, which apart from being a rather unsympathetic concept, is more about ridding yourself of foreign stuff that’s controlling you rather than the other way round. If anyone has any suggestions, drop them here.
* I am confused about why it's used for a project like this and not some kind of internal NSA project, or maybe a nu-witch house band logo, or something
I intended to invoke thoughts about how Extism enables one to "extend from within", thus the octopus crawling out from the skull. And also that the thing Extism should replace is rather cursed... loading DLLs / dlopen tons of plug-ins into your program to execute untrusted code is downright scary.
Interesting (I think), but the page lacks a problem statement that the project seeks to solve.
As others have noted, "make all software programmable" seems a bit vague. And it's vague because there's no problem in there. When is software not programmable?
I think the idea is to make application extensions easier to integrate (like photoshop plugins), but I'm not sure.
Start with the problem statement, and everything else will fall into place. Leave out the problem statement, and leave your readers mystified.
Point taken. We've been focused on talking to people who have built, or tried to build, plug-in systems. But it's still a confusing concept to the general public without enumerating some examples.
I've built a plugin-system back in 2003 or so based on the JVM which can load/re-load bytecode relatively easily.
(the concept became popular in the JVM world and lead to abominations like OSGi)
The problems that arose quickly were:
- Executing order of plugins attaching to the same extension point.
- Third party library dependencies having different versions
- Traceability and debugging
- Thread-safety
OTOH, it gave our custom dev team to develop integrations and extensions that could be deployed and maintained independently of the main product.
So there's definitely a use-case in there, but it requires some coordination regardless.
Would love to hear more about your experience there.
> (the concept became popular in the JVM world and lead to abominations like OSGi)
I remember this, though it was a couple years before my time. Although some of the underlying technology has changed those problems you outlined have remained the same. These things are all relevant to our next steps. We've been thinking a lot about what developer experience problems need to be solved.
> Maybe a "max_MB" property might be more useful to plugin authors, and then just calculate the # of pages internally from that?
yeah, that's something to consider. You can only pass in parameters that are a multiple of the page size so that may not be an accurate representation. I do think we need to hint at the unit in the name though.
The pdk is missing Zig which is, for many developers, considerably the best for wasm target. It's as fast as Rust (from benchmark I saw, Rust is fastest), though Zig's binary size is as small as AssemblyScript's. Rust's binary size is considerably in a range of middle to large, mostly middle.
It would be nice if there's an official wasm benchmark of source languages, showing speed and binary size comparison.
As others have said, the term "software" is confusing. Application or software product seem more apt.
The other small point I'd raise: there's mention that due to the sandboxing of WASM it's "safe" to run untrusted code. Maybe I've misunderstood. To me that seems true in so far as the untrusted code cannot break out and can only do actions the hosting app decides to allow, but this isn't much consolation if the app allows actions that can be subverted.
For instance, if the app allows control over saving a file, untrusted code only gets to handle that within the rails the app sets but that still means dodgy code could fill up a hard drive by saving over and over, or it could possibly save over important files.
> As others have said, the term "software" is confusing. Application or software product seem more apt.
That's a great suggestion thanks!
> To me that seems true in so far as the untrusted code cannot break out and can only do actions the hosting app decides to allow, but this isn't much consolation if the app allows actions that can be subverted.
Yes i think safe is a relative term here. Any user input is "unsafe" to some degree. Your example is a good one! I think we wrote this in the context of other relative ways to do this but will be discussing better ways to talk about security and what Extism protects and what it doesn't.
We're both all in on extensible software powered by WebAssembly, but the scope and domains differ.
Suborbital is more of a turnkey / batteries-included service that handles the full lifecycle of extending SaaS applications with user-defined plugins. So it includes a web-based editor widget, a module builder service, storage and compute, administrative dashboards, etc.
Extism, from my lay understanding, is more tightly scoped toward being a great library for running WebAssembly modules, in the same way you might embed a Lua runtime into an application for user scripting.
Another big difference is that you can use all of Extism right now. Suborbital's hosted platform is still in closed beta :) (Waitlist at https://form.typeform.com/to/DHxjRGKx)
Congrats on the launch! Just yesterday I was pondering if I could do something like this for a saas I’m working on: I’d like to offer users the ability to extend their dashboard in certain ways (a la WP/Shopify plugins), but those ways require extending the ui AND the server code.
Extism seems like a great fit for this, I’ll definitely be checking it out :)
Thanks! I want to highlight that Extism supports both server-side AND browser environments, running the same plug-ins. So SaaS is a great example of a place where end-users may want to extend functionality that runs on the client, server, or both. Feel free to reach out if you have any questions.
Sounds very cool and like it could be a good fit for our browser based runtime! There are still a few limits, but you can currently run the same plugins in your backend and frontend.
This looks fantastic! I'm working on a desktop app and I've been struggling with the extensibility story in the back of my mind for a couple of weeks now.
Thanks for building this!
edit: For what it's worth, the use case and value of something like this was immediately apparent to me.
Awesome! We'd love to see what you end up building, and if you use Extism please let us know what you find missing...
> For what it's worth, the use case and value of something like this was immediately apparent to me.
Thank you for saying so. Negative feedback doesn't bother me (I appreciate anyone taking time to speak up), but it's also usually the only kind you get on the Internet :) so we appreciate hearing that. Translating ideas into words is hard, especially in software.
To be honest, I don't see why it is advertised here at this stage.
I appreciate effort, but project is too young and unable to do any serious plugin. I guess it is try to get new contributors on board?
I see that project on github started few months ago. Isn't it too early to adwertise it to the world?
But it already have fancy website with modern styles and so on. But it lacks good documentation.
Article says that docs have "dozens of examples in different languages", but it just have dozen languages and helloworld in them.
And basically examples are just simple function call from host to plugin. Operating on strings/basic types, and JSON.
That's not what we want from plugins. Wee need some way to expose Host API some way, perhaps in OOP fashion. To let plugin interract with host app, perhaps even change UI.
But not of examples show that, how to pass at least basic functions into plugin.
As I understand it comes with it's own HTTP stack, presumably implemented in Rust. This can be used as starting point to make your own macro processor that would be able to expose API for plugins, and then dogfoof this codegen for your own HTTP lib.
And passing JSON around is not thing that is needed. With same success IPC could be used, with relatively similar performance.
We need proper marshaling.
There much work to be done, sadly. That's big endeavor.
Well, I hope this project would grow in something good, but it's in really early stage.
If so, then super interesting product! Have actually had a somewhat similar idea myself for a product that allows you to create "subsystems" that are isolated from one another, allowing you great freedom in how the subsystems are deployed. They could be deployed all on the same machine, or, if greater scalability is needed, a subsystem (or plugin) could be moved to its own machine, or even scaled up to run multiple instances.
Have only read through the simple code example on your website, but also, it would be great if there was a standard for calling and receiving requests through FFI's. Because this would give it the utmost flexibility on where the plugins can be deployed to. To me, this means both the actual mechanism for the call (REST over HTTP, graphQL...) and in the plugin and host themselves, with the syntax of the call. So for the syntax, it would also be great if this looked more like a regular method call instead of having to wrap parameters in an object:
hostWrapper.somemethod(param1, param2) or
hostWrapper.call("somemethod", param1, param2)
(Although, not sure how difficult this is to do, given all the different method call syntaxes of the different languages).
And, am glad that you and your company is really trying to make this happen, it's a great idea! Looking forward to giving it a try!
it's not quite the sidecar pattern (assuming i'm interpreting the link you shared correctly) - since Extism is actually _embedded_ into your program's process, not isolated over a network boundary like a sidecar.
the benefit of this is typically much faster execution speed, and thanks to WebAssembly's security model, it's safe to execute plug-in code - unlike a DLL or dlopen to a .dylib or .so file. in effect, it becomes an actual function call, not a RPC.
please correct me if i've misinterpreted your post!
Think you interpreted the Side Car pattern pretty well:) It definitely is typically done using HTTP (REST), and the benefit of this is it gives it great flexibility, allowing it to be deployed in many different ways.
Like Extism, sidecars are typically developed in some type of container like Docker (I have a limited understanding of WASM but since it's also a container technology, think you could also use this instead). And since the calls into the container are done through a standard like HTTP REST (or GraphQL), it's no problem if you'd like to have the container deployed locally, or on the same machine as your host container, or even on it's own server if you need to run it as its own microservice.
Although typically, sidecars are deployed locally and work almost exactly like Extism - simply as a plugin to the main application. And the performance of the local call is pretty good, because the call is usually made over a virtual network you'd setup in your docker configuration files.
I came across sidecars for the first time a couple of years ago while doing a job at Atlassian. And, for me, creating an entire product like Extism to take plugin/sidecars to the next level seems like a great idea. Because sidecars are awesome and we need a way to make them easier and easier to develop!
Hmm, was just thinking it over, wonder if it be useful if Extism did allow flexibility in deployment (meaning that the mechanism for calls wasn't just limited to using WebAssembly to do the call/security), but could switched to using HTTP REST or GraphQL by some simple changes to some config files? Because now the plugins can be deployed in many different ways, and even work in legacy systems (they may have their own security model. Seems like some type of REST security is pretty popular)...
... although, as mentioned, from what I saw, seemed like 95% of the time, sidecars are used locally as well, like Extism, so maybe just focusing on local calls is good enough??
... Am also wondering if supporting both Docker and WASM might be useful/possible?
And of course, I have very limited understanding of Extism, so of course, I may be waay off in what the future directions of your product, so please take everything I said with a grain of salt. But, Extism does seem like a great idea! Will give it a try.
> Hmm, was just thinking it over, wonder if it be useful if Extism did allow flexibility in deployment (meaning that the mechanism for calls wasn't just limited to using WebAssembly to do the call/security), but could switched to using HTTP REST or GraphQL by some simple changes to some config files?
You could always deploy an actual sidecar that runs Extism -- but we believe operationally it is far simpler to eliminate other deployments and run WASM in-process as it was designed to do. But, it's certainly possible to ship Extism in many different ways :)
> ... Am also wondering if supporting both Docker and WASM might be useful/possible?
I don't think it would be practical to support Docker, unless you shipped the plugin runtime environment as a sidecar. But at that point, it's a microservice / FaaS thing. And for Docker, there are many other options that handle this well.
I think there is a really interesting middle ground that is the WASM for Proxies stuff, from Envoy, Istio, etc. Run a subset of application logic or plugins via WASM in your service mesh - I think these can terminate requests and respond directly back to the caller, acting like a microservice itself.
> You could always deploy an actual sidecar that runs Extism -- but we believe operationally it is far simpler to eliminate other deployments and run WASM in-process as it was designed to do.
Ah, yeah, actually, I can see this (focusing on just local and in process). As mentioned, 95% of the time (probably higher), it seems like sidecars are used locally anyways, so having the simplest way to use sidecars/plugins could be super beneficial. Will give Extism a try.
... and WASM for proxy type stuff sounds super interesting too:)
I'd love to see C# support for something like this as well. Would be nice if Unity games could start supporting wasm plugins. Not sure if something like that works for Ureal already.
Another question... Is something like this possible on iOS or will these kinds of runtimes be banned by Apple?
C# support on which side? The host or the plugin side? I've got an experimental C# plugin almost working. I think I can do it. A Host SDK library would be pretty easy since it's just FFI to the runtime.
> Would be nice if Unity games could start supporting wasm plugins
That would be pretty neat! I go back and forth over whether this kind of thing will happen or not. Extism's goal is to be very generic (universal). A game engine may have some competing goals like performance or predictability. Still, I wouldn't be surprised if some alternative engines didn't do this in the next few years.
> Another question... Is something like this possible on iOS or will these kinds of runtimes be banned by Apple?
Not today, but I think I know how to get there.
If you need this stuff for your project come join the discord and we can try to prioritize it!
The idea is to offer extensibility points in software by embedding their runtime into your current software. Say you have a database and instead of a DLS for querying, allow someone to upload a WebAssembly binary that has access to APIs you'd expose (`filter`, `map`, ...). I'm guessing they ease some of the complexity in moving data back and forth, their runtime is supported on N languages, and they use wasm's sandboxing properties.
The problem, for me, is even though the runtime supports many languages, the languages the plugins can be written in is limited. Rust and Go support wasm well, but AssemblyScript* is not JavaScript / TypeScript. If the idea is to extend software and make it more accessible, they need better support for interpreted languages: JS, Python, Ruby, ...
There will be ways to handle this problem in the future with the Component Model spec. I've seen it working but it's not easy to do yet. As of today though, yes bringing your own runtime is costly.
Extism is a plug-in system. Plug-in systems make your software programmable by end users (such as your customers or your open source community). Currently plug-in systems are quite difficult to build and limited to certain host and guest languages. Extism makes this easier regardless of your language or domain knowledge.
> Plug-in systems make your software programmable by end users (such as your customers or your open source community)
I am confused. Who is the "end user" or the "customer?
It seems like "developer" who is writing software for a customer is your end user or may be not. Who will actually use this is not clear from the website.
From couple of examples I think this comes close to something like a SQL CLR integration, where for example you can call a C# routine from SQL query.
Your end user would be a user of your application, e.g. a customer. But it could also be a marketplace like situation where people are developing plugins for your customers. Examples of plugin systems are things like VS-Code Extensions, Figma plugins, firefox extensions, etc.
No, it took me a bit to understand as well. It looks like a set of host SDKs and a sandboxed runtime (guessing this is why they're using wasm) you can drop into your own software and expose some hooks that would allow your users to write their own plugins for your app in a variety of languages.
I think it would be better described as a 'universal framework for incorporating plugins into your application'.
If I am right about these aspirations, they are quite grandiose. Shiver Shades of COM or corba reborn?
If I understand it, this is more about the plumbing of calling the Rust wasm execution engine from various languages. And probably the secondary problem of how do you package wasm-hosted code such that it can interface with multiple calling languages. Rust can build a shared object with C linkage. All the languages have ways to call "native" code (code with C linkage). This is the sauce to connect those dots in a multi-language, batteries-included way. Hopefully I got that right.
It's all in-process so not more like OLE than Corba ;)
If I want to make all software programmable, I install Frida and easily hook into pretty much anything at the same privilege level.
Still, misleading headline aside, this sounds pretty cool as a reasonably well sandboxed plug-in architecture for software that chooses to use it.
Though if running in-process, it seems unlikely to be able to defend against hostile plugins that use e.g. speculative execution techniques to extract otherwise inaccessible data. But perhaps that's not the threat model here.
As others have mentioned, "making software programmable" isn't really landing for me.
In the tradition of borrowing terms from the games industry (where we often see early popularization of good ideas), I wonder if "modding" could be a helpful addition somewhere in your marketing.
This seems to have worked for the term "multiplayer", though "moddable" probably isn't as widely appreciated yet.
Will WASM finally be the write once run everywhere system we've been promised for the past few decades?
I can imagine every language compiling to the common format that is WASM, so you can mix and match libraries from other languages as you please, as well as chip manufacturers adding hardware accelerated WASM processing units if it gets popular enough.
No. WASM will have the same problem that every "run everywhere" system ever had: what makes software hard to port is not the ability to execute it, it's the environment differences.
But it will be a powerful low trust portable VM, like none mainstream today. Odds are it kills Lua.
(And yeah, it removes the Javascript monopoly on the browser. At this point, it can't be killed, but it will shrink.)
Lua is more like a C library and less like a VM. (Similarly, LLVM isn't a VM, which is a common misunderstanding, given the name)
As far as I know, people don't ship code to remote Lua VMs and execute it. There is no compatibility guarantee across versions, and there are nontrivial compile-time options (like what the number type is).
That doesn't mean Lua isn't useful; it's just not designed for the same things that WASM is.
> Will WASM finally be the write once run everywhere system we've been promised for the past few decades?
I think it has a good shot! If I'm hedging my bets though I'd say there are some things it will just never be good at. That's okay though it's not a zero sum game.
> This really is the birth and death of Javascript.
One thing I will not bet on is the death of javascript!
Interesting. Just this week I've been building a little experiment in order to utilize WASM based plugins in a project I'm involved with. I'm using WasmEdge for the task and so far am having pretty good luck.
Questions:
1. Can WASM plugins with Extism easily call back into host provided APIs?
2. Complex types are supported?
WasmEdge is really cool -- I'm super impressed with the work they are doing and hope to eventually provide an alternative runtime backend to Extism using WasmEdge (maybe they'd like to help!)
To answer your questions:
1. Extism provides a specific set of host provided APIs, and currently we don't have support for user-supplied host functions beyond the ones we make available. This will change though, and we're looking for feedback. We held off because there wasn't a clear way to make it easy across ALL the languages we support.
2. Complex types are definitely supported, you need to encode the data into raw bytes and can use whichever format you want (only limited by which formats are available in host & plug-in languages..)
Eventually we will move towards the Component Model which will make the complex types story much simpler.
Thanks for the info! I'll be keeping an eye on this for sure. What I'm working on is a PoC and it's working well thus far. As Extism advances and supports some of these upcoming features, it may turn out to be "just right" for my needs.
Damn, this looks really cool. I've wanted to add wasm support to my project at work for some time now, but unfortunately with no good C# integrations (with Unity as the host), it just hasn't met the mark yet. Really hoping that can be addressed in the near future.
Currently it is not, but we are closely tracking the Component Model to see how we can best utilize it. There are a few places we know we can leverage it, namely in the HTTP interfaces and other imports we provide to plug-ins. But, we also want to contribute to the language support on the codegen side. In order to get the language support we have already, we couldn't invest the time up front to build all the codegen in wit that would have been necessary. Over time want to get there though!
I think you're probably right, but I don't think many people would look at the JVM as a failure. Instead, I think WASM is trying to bring the good parts of the JVM such as being a simple compile target, small binaries, and a stable VM while fixing the bad parts like having a huge attack surface area and lacking certain features critical for performance (pointer chasing, GC, etc.).
In many ways yes. We need to re-invent many things for this new world. But I'd encourage you to read a bit more about how Wasm is different. It's true it is a stack based virtual machine but that's about where the comparisons end.
No, it's just "let's take random languages and transpile them to Javascript but call it Webassembly and hope nobody notices". In that sense it's much worse.
for JS on the Web, yes - we ported our runtime specific APIs to TypeScript and expose them to the WebAssembly runtime in the browser
for JS in Node, we use wasmtime embedded within our runtime -- looking into what the tradeoffs are to re-implement the whole runtime in Node on its native WebAssembly runtime though. Feedback welcome & appreciated!
yes, Wasmtime does use a JIT. We haven't tried on mobile yet, but I think I have some paths to make it work. If this is something you need come join our discord and we can experiment on it!
We also have some example projects in the GitHub org, pointing out this one specifically, to create a UDF engine in sqlite3: https://github.com/extism/extism-sqlite3
There are some examples, but the announcement is focused on the project itself - we will follow up over the next week+ with some end-to-end examples. Stay tuned!
The plugins are, but not the host. You can create pools of plugin instances if you need concurrency. Threading inside a Wasm program is still a new concept but I think it will become more common.
The underlying runtime appears to be Wasmtime, an existing project that you can use separately.
For the system API, Extism supports WASI (a POSIX-like API for WASM) which is already supported by Wasmtime. However it sounds like it also has a different, non-WASI API that provides similar functionality. I'm curious to hear a compare/contrast between these two system APIs, or what motivated inventing a new non-WASI system API. It does appear that WASI is in its early days; WASI was announced in 2019 (https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webas...) but it appears that all of the specific proposals are still early stage and far from being standardized (https://github.com/WebAssembly/WASI/blob/main/Proposals.md).
For the API, Extism provides a C API/ABI that can be called through FFI, but AIUI Wasmtime already has such an API: https://docs.wasmtime.dev/c-api/
Basically I'm trying to understand the conceptual difference between this project and Wasmtime.