5 ms·
Thinscript: language that compiles to both WebAssembly and JavaScript
- oldmanhorton 11y agoThis looks a lot like typescript. Is there any particular reason for not either 1) adding a wasm backend to tsc (which tsc may or may not allow), or 2) implementing a strict subset of typescript? It just seems like piggybacking off of a larger language would help this sort of idea gain traction.
- Scarbutt 11y agoIt does say that it is inspired by Typescript.
- azakai 11y agoTypeScript is garbage collected, like JavaScript, while WebAssembly is not. So directly compiling TypeScript to WebAssembly isn't possible, without also compiling in a userspace GC implementation. I'm not sure what Thinscript does for this. edit: README says nothing is deleted, so I guess that each new() allocates but nothing is freed?
- constexpr 11y agoI'm planning on experimenting with either pure reference counting (Swift), reference counting + cycle collection (Python), or garbage collection. I'd love to hear about what people are doing for emscripten actually. I've read that Unity uses IL2CPP which uses the Boehm GC but I couldn't find anywhere that described how that actually works in emscripten. Local variables correspond to "registers" in machine code, but how does the garbage collector read them so it can scan them during a collection?
- azakai 11y agoYeah, a bunch of projects use Boehm (or their own GC, like the Lua VM). For large projects the extra size of including a GC implementation isn't so bad (but for small ones it can be). And it can be fairly fast. A problem is that you can't have GC cycles with the outside world, so you can't interact with the DOM in a normal way. In particular, your objects can't be automatically GC'd if they can be held on to by anything outside of the compiled linear memory. That's why emscripten's C++ <-> JS binding tool has a .destroy() method on each wrapped C++ object, as they need to be manually destroyed by the user. For local variables, they aren't scannable by themselves. You need to emit special inline code that writes them to linear memory. In C++, you can do this with an RAII class for a reference, for example.
- pcwalton 11y agoOne trick you can use (which Chromium+Oilpan uses) is to only GC in between turns of the event loop. In that case, your set of roots is exactly equal to the accessible global variables plus everything accessible from the DOM (including event handlers). In particular, nothing is on the stack, so there is no need to introspect stack frames.
- erichocean 11y agoThat's a really clever idea. Thanks for sharing.
- constexpr 11y agoI considered that but I'm worried that won't work with WebAssembly because it's a more memory-constrained environment. Your app may generate a ton of data in a frame and run off the end of the address space. I guess I'm probably just thinking back to asm.js where you sometimes only have 256mb to work with. I'll try this first at least since it makes stuff easier.
- manyoso 11y agoJust go with pure reference counting. It'll be faster and easier.
- constexpr 11y agoYes. TypeScript doesn't have a sound type system and it comes with a lot of baggage: * Using hashtables in TypeScript relies on the representation of JavaScript objects with strings as properties. Emulating JavaScript's in-memory representation in an ahead-of-time compiled language isn't a good idea for performance reasons. * TypeScript only has a single number type (double) which is pretty slow if you actually need to work with integers. JavaScript VMs do a lot of work to figure out which numbers are integers using information that's only available at runtime. Using explicit integer types means the generated code is a lot tighter. * A lot of existing TypeScript code uses structural typing to model dynamic type contracts present in today's JavaScript code, but this is usually a loosely-typed approximation and not something that a compiler can rely on. It's more just to improve tooling for developers. * TypeScript uses exceptions which are hard to emulate efficiently in native code. * I want to be able to add certain things and extend the language, so I don't want to limit myself to TypeScript. For example, I'm considering a preprocessor for conditional compilation and something similar to C#'s unsafe syntax for pointer manipulation.
- pookeh 11y agoAll these reasons in Typescript are intentionally designed so that it's easy to work with the rest of the JS ecosystem. Good tooling + rapid prototyping is a strength not a weakness.
- freditup 11y agoBut they are weaknesses when designing a languages to compile to wasm. I love TypeScript and the Microsoft team has done a fantastic job with it, but that doesn't mean it's the right tool for this particular job.
- constexpr 11y agoI don't consider the design of TypeScript a weakness at all. TypeScript is really well designed and is great at what it does. The type system they came up with is pretty optimal for modeling real-world JavaScript code. But the tuning they did around the JavaScript ecosystem means it's not a great language to use for generating efficient native code. I started ThinScript in part for exactly that reason. I want good tooling and rapid prototyping, just for native development instead of web development. That requires a different set of trade-offs and design decisions.
- ZenoArrow 11y agoThinscript looks interesting, aside from coding in it directly it could prove to be a useful transpiler target, allowing non-web-languages to make better use of WebAssembly as both WebAssembly and Thinscript mature.
- constexpr 11y agoYes! I considered this and it's an interesting idea. ThinScript may end up being pretty opinionated about memory allocation though (I'm not sure yet if I'm doing pure reference counting, pure garbage collection, or some combination of both) so it could be a useful higher-level target language.
- asb 11y agoI wonder if there's a plan for generics support?
- constexpr 11y agoI plan to do it eventually. I've implemented generics before so that's not the issue. It's just hard to get the design of generics right when the compiler has multiple targets. You want to emit compact JavaScript code and at the same time support the generation of efficient machine code. C++ does generic code through template expansion but that ends up generating a ton of code, which is bad for code delivered in a network environment. It may make sense to make different tradeoffs given the context of this project. I'm planning on putting off generics for a while though until more pieces fall into place.
- constexpr 11y agoOh wow I did not expect this to be up here this soon. Warning: two-week-old project. I've got a lot of plans for this but it'll take at least a few months for this to be anywhere near useful. Right now it's just an experiment!
- dfield 11y ago^ constexpr is the author
- pookeh 11y agoPlease don't add type inference. Coming from Scala it seems such a beautiful concept and a productivity booster when you are writing code but then you come back a few months later / see someone else's code and quickly figure out what a time waste and a productivity drain it really is.
- Drup 11y agoIf I may, that just means that either 1) your tooling is bad 2) Scala's type system is too complex. I don't know scala much, but it's not a problem in other languages with full inference (particularly OCaml, but it's not a huge problem in Haskell either).
- davnn 11y agoJust because type inference exists doesn't mean that you have to use in every case. Better to establish best practices when to use type annotations.
- PeCaN 11y agoI'm glad it did though—this is awesome! Good luck with it, and perhaps I'll contribute something (do you plan for it to be garbage collected?).
- dukoid 11y agoDo you plan to support return type inference? Will classes be accessible before they are declared? Why "int" (opposed to supporting the wasm type names)? (I'm interested because I was planning to add a typescript parsing demo for an expression parser (https://github.com/stefanhaustein/expressionparser https://github.com/stefanhaustein/expressionparser), but typescript turned out to be a bit more tricky than anticipated originally)