14 ms·
The future of WebAssembly – A look at upcoming features and proposals
- vardump 8y agoI hope WebAssembly will not only be a web technology, but the de-facto format for cross-platform high-performance embedding. Such as for plugins, scripting and extensions. Something you could send over the wire to the remote application and it could execute it with high performance and reasonable security. Cryptographic signatures can be used for more security sensitive contexts. So one thing I'm really hoping no matter what happens to WebAssembly, that the external interface and requirements are kept simple. Minimal required dependencies, no built-in class library, etc. It'd be ideal if WASM runtime environment is very lightweight, preferably just 100s of kB. The smaller, the better. Especially some kind of dependency for Javascript would be disastrous. It'd be amazing if it was possible to run small ~10 kB WASM modules remotely on a microcontroller, like Cortex M4+ or such, with say 64 kB of RAM. You could add a lot of flexibility in some applications. It actually looks very interesting for cross-platform "scripting", once there's a good cross-platform optimizing compiler library for it. From where I stand, currently the most interesting proposals of the listed ones: 0) High-performance non-web "embeddability" with low memory requirements. (Not actually listed, but very much desirable.) 1) Threading. Would greatly help performance and portability in some cases. I'm a bit sceptical whether there's a way to add this after CPU speculative attacks (Spectre, etc.) became known. 2) SIMD. Lots of filtering and data processing algorithms can greatly benefit from this. 3) Tail calls / bulk memory ops. 4) Export / import mutable globals (and good module support in general) 5) Exceptions. (Minor, portability).
- madeofpalk 8y agoThat's more or less what Javascript is today.
- vardump 8y agoWhile Javascript can serve a subset of these applications, its runtime is bulky and high performance Javascript JIT weighs a lot due to required complexity. WebAssembly is a lot less complicated, and has a lot of potential.
- swsieber 8y agoI would say that a nice simplified view of things is that the WebAssembly lifts complexity from execution optimization into compilation (or wasm production) optimization, allowing the runtime to be much lighter/faster.
- simion314 8y agoI assume with WebAssembly you could get existing c/c++ etc libraries and recompile them and use them. Even a JS lover that wants to make desktop apps could benefit of having access at the large number of existing libraries without having to use a bridge to the native libraries.
- pjmlp 8y agoUniversal bytecode formats have been tried since UNCOL. https://en.wikipedia.org/wiki/UNCOL https://en.wikipedia.org/wiki/UNCOL Outside the browser it adds very little over Java, MSCLI, LLVM, P-Code, M-Code, Python Bytecodes, TIMI, DEX and a myriad of other formats. Cortex M4 is already targeted by MicroEJ and MicroPython.
- vardump 8y ago> Universal bytecode formats have been tried since UNCOL. No doubt there have been plenty of those. > Outside the browser it adds very little over Java, MSCLI, LLVM, P-Code, M-Code, Python Bytecodes, TIMI, DEX and a myriad of other formats. It does add one very important thing: a large ecosystem. One where security and performance matters: the web.
- pjmlp 8y agoWebAssembly manipulation tooling is in its infancy compared with what is available for manipulating some of the bytecodes I mentioned on my comment. Regarding libraries, graphical debuggers and reverse code generation. Security and performance were part of Java and .NET design, hence why they have validation as part of their execution workflow. As for security on the Web, cross site scripting and WebGL exploits prove that is still room for improvement.
- wtetzner 8y agoThe fact that it's the only standard way to run on the web without Javascript means that every language and its dog will have a WebAssembly backend. I wonder if the real difference between WebAssembly and the other bytecodes you mentioned is just the number languages that will end up targeting it. Though, one advantage over LLVM is that it's simpler.
- seanmcdirmid 8y agoHas WASM bridges the DOM problem with a nice solution yet? If not, it isn’t even a way to run on the web yet.
- krapp 8y ago>Minimal required dependencies, no built-in class library, etc. It'd be ideal if WASM runtime environment is very lightweight, preferably just 100s of kB. The smaller, the better. Especially some kind of dependency for Javascript would be disastrous. Unfortunately, what's likely to happen is that everyone just ships their WASM apps in Electron since that's already the de facto standard.
- pjmlp 8y ago> Unfortunately, what's likely to happen is that everyone just ships their WASM apps in Electron since that's already the de facto standard. Standard where? A couple of well know apps beloved by startups with high end desktop systems?
- krapp 8y agoIt's the standard for packaging "web applications" to run natively, and the path of least resistance for doing the same with code compiled to WASM. Also VS code runs on Electron, so it's hardly uncommon.
- pjmlp 8y agoThat is called PWA. Electron apps are as native as PWAs, with the caveat that they bring a 300 MB runtime alongside with them. I bet there are still more Swing applications in production than VSCode users. That doesn't make JAR a de facto packing format.
- krapp 8y agoThe point is that existing solutions in practice, however bad they might be, will always beat better solutions which only exist in theory. Electron apps (or, fine, PWAs) will become the standard model for WASM development because that model already exists, and is what developers will most readily use... and because most of the interest in WASM comes from the web development community. By the time something better comes along, it will have to fight against the network effects.
- zaarn 8y agoThere is another area where WASM could become very interesting; Operating Systems. Or more specific: Kernels. A nanokernel with the capability to run a WASM binary with a simple GC could have highly portable kernel modules and due to the properties of WASM, run userspace code in ring 0 without much risk to hardware and software. Additionally stuff like paging and memory management are much simpler to begin with as the memory access pattern of WASM is much simpler (with some dynamic relocation tricks that should be possible you could even identity map and don't do paging at all) I've also thought about doing microcontrollers as you mention, however, I was thinking about Arduino's (ATmega). They would need a much simpler and more reduced WASM since you only have about 2 KB of work memory.
- kam 8y agoThere's already a WASM-centric OS in development: https://github.com/nebulet/nebulet https://github.com/nebulet/nebulet
- zaarn 8y agoYup, that's part of where the idea comes from, I would favor more research in this area though.
- pjmlp 8y agoI case you aren't aware of these, here are some pointers for Burroughs[1], Xerox's Mesa/Cedar[2], Pascal UCSD[3], M-Code[4] and Oberon Juice[5]. [1] - http://retro-b5500.blogspot.com/ http://retro-b5500.blogspot.com/ [2] - http://worrydream.com/refs/Teitelman%20-%20The%20Cedar%20Programming%20Environment,%20A%20Midterm%20Report%20and%20Examination.pdf http://worrydream.com/refs/Teitelman%20-%20The%20Cedar%20Pro... [3] - http://pascal.hansotten.com/category/ucsd-p-system/ http://pascal.hansotten.com/category/ucsd-p-system/ [4] - http://pascal.hansotten.com/niklaus-wirth/lilith/ http://pascal.hansotten.com/niklaus-wirth/lilith/ [5] - ftp://ftp.cis.upenn.edu/pub/cis700/public_html/papers/Franz97b.pdf
- bryanlarsen 8y ago"the external interface and requirements are kept simple." I would bet strongly against that happening long term. Everybody developing WebAssembly is interested in making the web better and pretty much only that. One of the biggest issues preventing WebAssembly usage right now is that you have to ship a large run-time along with your app. So there's going to be a lot of pressure to move that run-time into the browser. See the linked article: GC is the proposal the author highlights the strongest. The biggest pressure in your favour is the disparity of languages supported. They'll probably want to ensure that any built-in library functions they add are useful to a wide range of WebAssembly communities.
- couchand 8y ago> Everybody developing WebAssembly is interested in making the web better and pretty much only that. This is demonstrably untrue. Please peruse the design repo, I think you'll find that there are very frequently discussions of non-web applications, something folks are actually quite keen to support.
- bryanlarsen 8y agoPerhaps, but the real stakeholders are the browsers. Do you really think they'd hold off on GC if somebody told them that would make it problematic on embedded?
- TomMarius 8y agoEmbedded maybe, but it's a good feature for literally the rest of applications.
- steveklabnik 8y agoThe same people who work on the browsers are the same people who are in favor of this. The initial authors of wasm created the spec in this way for a reason; it's something they care about.
- wahern 8y agoThe moment GC is added to WebAssembly will the the moment WedAssembly becomes no more secure than JavaScript. Either that or performance will tank. The GC is one of the most complicated parts of the browser engine, and serious bugs and exploits are regularly discovered in all of them. Safer languages like Rust won't help at all in the case of WebAssembly because it's not sharing the same type system. Further more, it's all kind of pointless. No two GCs are the same. A GC is more than simply tracing. Different languages provide different semantics with regards to finalizers, for example.[1] The semantics of the GC closely mirror design decisions of the language. If you're using the JavaScript GC then your language will be limited to the semantics of JavaScript, in which case why are you bothering with some random language? [1] Are finalizers even supported? Can they run arbitrary code? Can they resurrect the object? If they can, will they run again? Can they throw an error? What happens if they throw an error? In a language like Lua these rules are very specific because they're important to the semantics of the C API, especially wrt to bindings. For example, within a collection cycle Lua finalizers are guaranteed to be run in reverse order of construction.
- jmull 8y ago> I hope WebAssembly will not only be a web technology, but the de-facto format for cross-platform high-performance embedding. I don't think that's what's happening. They are looking to integrate webassembly more deeply with its host environment (which more-or-less assumes a browser and Javascript). I don't think this is a bad thing, BTW. You may be disappointed, but they are just looking to solve a different problem then what you are concerned with. It's an imminent, practical problem, so nothing wrong with someone addressing it, even if it isn't your problem.
- kodablah 8y agoDisagree. Watching all of the WebAssembly discussion around proposals and the spec in the GitHub issues, the leads are always mentioning non-web uses and are always being careful to separate the JS/Web ifaces/impls.
- jmull 8y agoI guess we'll see, but integrating with the host garbage collector is pretty suggestive, to me. Aside from that, an app/program/whatever delivered as webassembly will typically have strong dependencies on the target host environment, which means its not portable or cross-platform. It's not useless, since you still get to choose your own language for any target that supports webassembly (assuming things work). But code, whatever language its written in, is very strongly influenced by the frameworks & patterns provided/imposed by the host environment, by environmental constraints, not to mention the problem domain itself. E.g., assume there are bindings for any language you want... if you write a To-Do app for iOS using native controls, it's going to look pretty similar whatever the language. > ...and are always being careful to separate the JS/Web ifaces/impls I'll just point out that this is quite important if your goal is to cleanly extend browsers. You specifically don't want to duplicate or impinge anything the browsers already provide. I'm not trying to be a downer, but it seems like people are hoping/expecting webassembly to do more than it can or will (maybe I'm wrong, but that's the impression I'm getting). Meanwhile, we have a very solid use case for it, which is a much better compile target than Javascript for whatever language you might want to use for web development.
- 8y ago
- kodablah 8y ago> 4) Export / import mutable globals (and good module support in general) Already done (at least at the spec level), ref: https://github.com/WebAssembly/spec/pull/814 https://github.com/WebAssembly/spec/pull/814. I'm currently implementing it in my non-web WASM backend now :-)
- pocketaces 8y agoI hope not. The subset of native (for example, x86) assembly that is equivalent to webassembly is already perfectly secure. You just limit the native assembly to pure computations without any system calls. It will also always be significantly faster than webassembly. When it comes to the security of system calls, then both webassembly and native assembly needs to make sure that whatever platform-calls that are available are secure. webassembly have no benefits over native assembly when it comes to this. Also, I doubt that it will gain as much popularity as some people predict. asm.js (the "original" webassembly) has been available for quite a long time already (and the technology behind it have existed for very very long), and if it were going to create a flood of developers targeting it instead of using javascript, then I think it would have happened by now. Inertia when it comes to development tools should not be underestimated and I doubt that all of the web developers who have invested in becoming javascript "experts" want to see the ecosystem change and see all of their "experience" and "expertise" become worthless.
- fold_left 8y ago> I doubt that all of the web developers who have invested in becoming javascript "experts" want to see the ecosystem change and see all of their "experience" and "expertise" become worthless. Can you expand on what you mean when quoting those words in this context? I can't put my finger on what point you're trying to make here.
- pocketaces 8y agoI am just a bit biased when it comes to my perception of most javascript developers. I should probably have left out the quotation marks. That would have made the comment more focused. However, with that being said, then the point is, that I find that there are significantly more developers who identify as being javascript experts than there are actual javascript experts, and that both groups contribute to the inertia.
- batmansmk 8y agoFirst time I read JS and inertia side by side. I heard/read way more often complaints about its speed...
- jsheard 8y ago> 1) Threading. [...] I'm a bit sceptical whether there's a way to add this after CPU speculative attacks (Spectre, etc.) became known. The plan is to rely on site isolation, where every origin runs in a separate process. Spectre only exposes memory in the same process so this should make it benign. SharedArrayBuffer was disabled due to Spectre but Chrome plans to re-enable it soon: https://bugs.chromium.org/p/chromium/issues/detail?id=821270 https://bugs.chromium.org/p/chromium/issues/detail?id=821270
- nine_k 8y agoOf course the very point of Spectre is reading memory of unrelated processes or of an OS kernel [1]. Reading memory of the same process you're running is normal and trivial. [1]: https://en.wikipedia.org/wiki/Spectre_(security_vulnerability)#Detailed_explanation https://en.wikipedia.org/wiki/Spectre_(security_vulnerabilit...
- tathougies 8y agoSomeone must have forgotten Java.
- wtetzner 8y ago> High-performance non-web "embeddability" with low memory requirements. I don't think Java fulfills this requirement. Or the one about tail calls. Java bytecode is too high-level, too. It forces you into a very limited execution framework.
- DonHopkins 8y agoLarry Ellison is an irresistible reason to forget about Java.
- austincheney 8y agoYour vision sounds like a potential vector for the widest possible distribution of malware. If you want to spin off WASM out from the browser into an independent technology then fine, but you need the same (preferably greater) security limitations that the browser already provides. Ensuring that level of constricted access uniformly and assuredly without any kind of accreditation is extremely unlikely. > Especially some kind of dependency for Javascript would be disastrous. I will not speak to outside the browser, but inside the browser this isn't changing. JavaScript remains the language of the browser and WASM is not in competition there. This isn't my personal opinion. It is the stated goal of WASM as a technology. The primary reason for that: security.
- s-macke 8y agoI am still a little bit disappointed that most transpiled languages have to provide a litte operating system to run their code including memory management and garbage collection. With this overhead webassembly can be even much slower than Javascript (downloading, compilation, simplified but slow memory management). If I remember correctly Rust adds 200kB of code to the webassembly binary. For me it was only possible to produce small binaries with emscripten C without any includes (bare metal). The proposals look promising and might reduce this overhead somewhat. However I don't think they will manage to design the virtual machine that is able to run all major rogramming languages efficiently. What ab0out features such as longjmp and goto in C?
- steveklabnik 8y agoThat is incorrect; the smallest rust produced binary is ~100 bytes. Only the code you use is included; if you want an allocator, choosing a smaller one is a good idea, for example. We are usually significantly smaller than emscripten for the same code.
- s-macke 8y agoI just programmed a function, which added 2 numbers and compiled it and got a huge binary. But maybe I did something wrong. I will try again. Thanks.
- markdog12 8y agoI gotta say, I'm surprised to see threads being mapped to WebWorkers. Are they an appropriate target, being that they're heavyweight, with a lot of overhead? Also, it seems like it'd be a nightmare for compilers to convert threads to WebWorkers. I also noticed Chrome Canary has had WebAssembly threads via a flag for a few weeks now, is that based on WebWorkers as well?
- 7373737373 8y agoHow probable is it that it will support multiple memories one day?
- ColinEberhardt 8y agoI think that will come fairly soon - I forgot to mention that the reference types proposal also include multiple table support https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md https://github.com/WebAssembly/reference-types/blob/master/p...
- deleted 8y ago[deleted]
- a9t9 8y agoJust to mention a real life use case: We are using WebAssembly for the image recognition features in our Visual UI Testing browser extension "Kantu". Before switching to WA, we tested many other approaches, including WebGL (old demo here: https://a9t9.com/demo/templatematching.js/ https://a9t9.com/demo/templatematching.js/ ). Whatever we tried before, it was either too slow (pure Javascript), too unreliable (WebGL) or required 3rd party installations (C++). Finally, switching to WebAssembly solved all these problems.
- cpeterso 8y agoInteresting that WebAssembly could have such a big impact on the viability of the web version of your product! How much faster was WebAssembly than JavaScript for your Kantu tests? Were the WebGL issues because not all uses had WebGL enabled or because of GPU-specific quirks?
- a9t9 8y agoOur initial tests were with standard template matching algorithms. With the Javavscript implementation we were stuck in the 60 seconds+ range per image search. With WebGL it was ~0.5s on a "good" machine and ~6s or "did not work at all" on a "bad" machine. We never figured out why it worked well on one machine, but not so on others. Of course, I am talking only about machines with WebGL enabled ;) This would have been a support nightmare. With WebAssembly we are now in the 0.1-0.5s range per image search and it just works. So far, we have had exactly 0 WA-related support issues, for both, Chrome and Firefox.
- cpeterso 8y ago60+ seconds to 0.1-0.5 is a pretty nice speedup! :)
- deeg 8y agoI'm sure there's a good reason for this and I just don't know it: what's the advantage of wasm over the JVM; i.e. why not just use the JVM in the browser? I assume there are complexities in compiling C/C++ to the JVM but wouldn't wasm have many of the same issues?
- feniv 8y agoThe WebAssembly format is better designed to be served over the web (compact representation, streaming compilation, low startup overhead, etc.) There's a discussion thread on this topic in the WebAssembly github: https://github.com/WebAssembly/design/issues/960 https://github.com/WebAssembly/design/issues/960
- kodablah 8y agoWaiting for @steveklabnik to write his post on this as it comes up in all of these threads. To give you a brief answer, the JVM bytecode is tied to JVM OO use cases and carries with it a significant runtime library burden. There are many many other details I can give you about how JVM bytecode is tailored to Java the language, but suffice to say it is not simple and not generic.
- steveklabnik 8y agoI’m hoping to get that out next week. I just gave a talk in Barcelona about wasm today, so that took up all my time.
- varjag 8y agoJVM sucks as a platform for anything but Java family languages. The execution model (no lexical binding, 64Kb code jump segmenting, inadequate rigid primitives type system) make running any decently modern language a pain. It's the reason a language like Clojure will never have a sensible backtrace. People do an honest effort with that but it's really polishing a turd.
- repolfx 8y agoBut wasm doesn't do exceptions at all, nor does it have a GC, so it's very far from being able to generate a stack trace through Lisp code. You don't seem to be comparing like with like. Bytecode has its flaws but the trend is away from using bytecode for all languages and towards partial evaluation of AST interpreters. That works well for managed OO like languages, and also other managed scripting languages, and it can also run C/C++/Rust/FORTRAN etc, with interop between the languages. WASM has no real roadmap to get to running anything other than small, manually memory managed programs. It's being billed as "generic" but I don't see it. GraalVM is generic. WASM struggles to run anything that requires a more sophisticated runtime than malloc.
- mrfusion 8y agoWill web assembly make it possible to do all your JavaScript stuff in python instead?
- notheguyouthink 8y agoYes.. sort of. For that scenario, we need a lot of things in place that are down the road for WASM. Technically it would work today, but you'd have to ship a Python runtime with every "app". That's a lot of overhead, so much so that it's basically a non-starter for many people. In the future it may work, because a built in GC is on the roadmap for WASM. Unfortunately I'm not sure that it will work great for most scenarios. For example, Go(lang) ships with its own GC which is very tailored to its use case. Defaulting to a WASM GC could work, in theory, but would it impose difficulties such as unexpected performance characteristics with longer GC pauses or whatever? There's a lot of edge cases that will have to be covered for this stuff to work instead. Perhaps shared WASM binaries would be the best solution, allowing runtimes to be offloaded and cached regardless of user land code running.
- Jach 8y agoWhen many websites are already shipping down megs of crap, I don't think the few extra megs of a python runtime would matter that much to the end user, especially if it's cached. Especially if it's marked by the browser as cross-site 'cached' (perhaps by verifying a signature and installing it as a plugin) so it's only done once per version. You can go further with more browser support, for instance browsers could bundle popular runtimes with their own distribution (Chrome + Flash).
- crooked-v 8y ago> Especially if it's marked by the browser as cross-site 'cached' That runs into the problems that have generally prevented browsers from cross-site caching common scripts already.
- wpdev_63 8y agoI feel like browsers would just cache these runtimes like they do with many js libraries so it wouldn't be a problem. I am really excited at the prospect of writing my front and backend in a sane language like C# or kotlin.
- haberman 8y agoIs anyone working on a small, portable, reasonably fast standalone C implementation? I am looking for the Lua of WebAssembly implementations.
- TomMarius 8y agoWhy C and not Rust? There is Cranelift JIT and my startup is working on full VM.
- haberman 8y agoI want something that could easily be embedded into dynamic languages VMs like Ruby, Python, PHP, Lua, Node.js, etc. I like Rust a lot, but for better or worse, all the infrastructure around this is currently built around C/C++.
- TomMarius 8y agoNot really? Almost everything (except V8 support and some experiments and a few minor (by code size) exceptions) regarding WASM is written in Rust, there are libraries like yew[0], Rust compiler has excellent support... And I'm not really sure what does it have to do with embedability, because Rust shouldn't restrict anything; at the same time, you don't really embed JVM into Python most of the time, rather the other way around. [0] https://github.com/DenisKolodin/yew https://github.com/DenisKolodin/yew
- kodablah 8y agoIncorrect. Rust does very well at embedding into those dynamic languages. It exports the same ABI C. In fact, due to how well its compilation tools work, IMO it's actually easier to use Rust than C to embed into those languages. The "infrastructure" is usually a just a C header. For Node.js it's more C++, but you'd need to write C++-to-C glue anyways just like you'd need C++-to-Rust glue (of course there's neon [0] that makes this easy). Basically, for most FFI-based use cases, anything that C can do Rust can do. 0 - https://github.com/neon-bindings/neon https://github.com/neon-bindings/neon
- haberman 8y agoAre these proposals "a la carte" or does each accepted proposal make the basic WebAssembly spec bigger? Like if the GC proposal is accepted, does every WebAssembly implementation now need to support GC all the time? Or can a slimmed-down version of WebAssembly still load modules that don't use GC?
- Feneric 8y agoOther languages can be compiled into WebAssembly, too, including Nim: https://news.ycombinator.com/item?id=17314581 https://news.ycombinator.com/item?id=17314581
- munificent 8y agoWebAssembly sits at the crux of directly opposing forces: If it goes higher-level: * Compiled applications get smaller because each instruction corresponds to a higher-level semantic behavior and contains more information. Think how a virtual method call is a single instruction in the JVM but several instructions in x64. * Compiled applications get smaller because runtime facilities can be baked into the browser and shared across all apps. GC is the big one but things like object representation, strings, "standard library" functions, etc. * More host-level optimization opportunities open up. The JVM JIT can do lots of optimizations because it understands directly what things like interface and virtual calls are and doesn't have to try to reconstitute that information by pattern matching on lower-level instruction sequences. If it goes lower-level: * It's a viable target for more diverse languages and paradigms. You can compile other languages to JVM bytecode, but the less like Java your language is, the harder that becomes. The VM has a grain to it. WebAssembly, by virtue of having fewer things baked in, is more open to a varied languages. C/C++ are the big ones because any memory-safe instruction set makes it really hard to support those. * More application-level optimization opportunities open up. Optimizing compilers can output code that's closer to the metal. They can take advantages of constraints in the source language that the VM may not know about and generate code specific to that. * Peak execution speed is higher. If your instruction set lets you directly map to something close to what the CPU executes, you can take maximum advantage of it. Despite decades of JIT engineering, C/C++ are still the fastest for that reason. * The instruction set is simpler. That makes it easier to implement, target, optimize, security audit, and build tooling for. There is no Goldilocks instruction set that gives you all of these. Adding instructions for GC is going to make it much more complex and is deadweight for languages like Rust and C that won't use it. Defining how the GC works is going to be really difficult given languages like Python (ref-counting), C# (finalizers), etc. where specific GC policy decisions are user-visible. Making the instruction set statically typed is what you want for low level typed languages. But it makes it harder for dynamically-typed languages to be implemented efficiently. Every dynamically-typed language that compiles to JS gets to reuse the incredible JITs inside JS implementations because JS is itself dynamically-typed. But if you compile, say, Python, to WebAssembly, do you ship a Python bytecode -> WebAssembly JIT inside the application? Does every language have to do that? Having strings means you need to pick a string format, which is basically impossible since every language out there makes different, incompatible choices for string representation (null-terminated? length-prefixed? null-clean byte-arrays? UTF-16? UTF-8? multi-encoding?). But not having strings means every app has to include a string library in its runtime and means you can't reliably pass strings around in interop. No amount of hard work is going to magically fix these because they are directly opposed. I think WebAssembly is really interesting, but one of the things that has always turned me off about it is that its proponents don't often acknowledge the hard trade-offs that have to be made.