[HN Gopher] TypeScript as fast as Rust: TypeScript++
       ___________________________________________________________________
        
       TypeScript as fast as Rust: TypeScript++
        
       Author : janpaul123
       Score  : 149 points
       Date   : 2022-04-07 17:29 UTC (5 hours ago)
        
 (HTM) web link (zaplib.com)
 (TXT) w3m dump (zaplib.com)
        
       | chadcmulligan wrote:
       | Years ago I wanted to use Typescript for native development, then
       | Swift came along, try Swift if thats what you're after.
        
         | janpaul123 wrote:
         | If Apple would truly commit to making Swift applications run
         | cross-platform (Windows, Mac, Linux, Android, iPhone, Web/wasm)
         | in a performant way, they could completely take over and become
         | the next stack for performance-intensive applications.
        
       | cromwellian wrote:
       | I wonder if you've looked at AssemblyScript
       | https://www.assemblyscript.org/
        
         | janpaul123 wrote:
         | Yep, but it doesn't really solve any of the problems that I
         | mention in the article, unfortunately.
        
       | huydotnet wrote:
       | Sorry for nitpick, but in the TypeScript example, should it be
       | for (const vec of vecs)
       | 
       | Instead of:                   for (const vec in vecs)
        
         | janpaul123 wrote:
         | Tnx; fixing!
        
       | dudus wrote:
       | I thought WASM was considered slower than JavaScript only for the
       | use cases where heavy usage of DOM is necessary. Since that's not
       | available through WASM it needs to make a call to a JS function
       | to perform the DOM manipulation and that incurs extra overhead.
       | 
       | I think these cases will just never be good for WASM. DOM
       | manipulation heavy Apps (which is a good chunk of JS code out
       | there) may continue to be in JS and only the CPU intensive tasks
       | would be computed in WASM.
       | 
       | Isn't that the best practice for WASM?
        
         | dgb23 wrote:
         | This issue is being worked on:
         | 
         | https://hacks.mozilla.org/2019/08/webassembly-interface-type...
        
         | [deleted]
        
         | janpaul123 wrote:
         | The overhead of going to JS from Wasm these days is very small,
         | and the DOM is relatively slow. So doing DOM operations from
         | Wasm is not much different than from JS; the vast majority of
         | the time is spent in the actual DOM API calls.
        
           | marcosdumay wrote:
           | Add to that the fact that complexity tends to exist in an
           | exponential curve, and even though the DOM is relatively
           | slow, it is still very fast.
           | 
           | So the number of projects where there is enough DOM
           | interaction that WASM will be slow, but not enough that JS is
           | still usable is very small.
        
         | jkelleyrtp wrote:
         | In http://dioxuslabs.com we share our strings (interned) across
         | the JS/Rust boundary and only send primitives back and forth.
         | All diffing stays in Rust with bump memory allocators managing
         | allocations. The JS side is only there to do DOM manipulation.
         | [1] It's about 3-4x faster than React.
         | 
         | I'd say a lot of the ergonomics are there, but not every
         | pattern has been translated cleanly from React into Rust yet.
         | 
         | [1]
         | https://github.com/DioxusLabs/dioxus/blob/master/packages/in...
        
         | meetups323 wrote:
         | Browsers are good enough that if you're careful about it you
         | can just use a WebWorker and write standard JS, no need to
         | worry with the build/compilation/compatibility headaches adding
         | a whole new language to your ecosystem entails. Nice part with
         | this is you can even have a fallback routine that runs the
         | WebWorker code in the main thread to support really old
         | browsers.
         | 
         | I wouldn't recommend dropping to WASM until you've ironed out
         | the ideal data structures/algorithms to use, and have spent
         | some time in the devtools profiler. Hacking on ideas in JS is
         | (IME) much faster than doing the same in a compiled language,
         | and the built in profiling in browsers works far better for JS
         | than any WASM (again IME). Only after you have an optimized
         | algorithm, data structure, and implementation, and still find
         | perf isn't where you want it would I recommend rewriting in a
         | compiled language -- even then I'd wager having the optimized
         | reference implementation around will make this much easier and
         | faster than if you tried to start from 0 in the compiled
         | language.
         | 
         | Bonus points if you can reuse tests and/or have a debug mode
         | that runs both implementations in parallel and throws on any
         | differences in output.
        
           | OtomotO wrote:
           | But I prefer to write other languages, so a compilation
           | target is perfect.
           | 
           | So it's either wasm or something like scala.js or fengari.io
           | (lua on the web)
           | 
           | (Worry not, I am paid to write JS and TS these days... But my
           | rate increased due to the pain it causes ;))
        
       | rob74 wrote:
       | > _Toolchain integration can be daunting. You need to set up Rust
       | in development builds, production builds, local testing,
       | continuous integration, and so on._
       | 
       | Impressive that someone familiar with the usual JS development
       | toolchains can write this and keep a straight face...
        
         | emteycz wrote:
         | What's so hard about JS toolchain?                   yarn
         | create next-app --typescript
         | 
         | ... and I am done
        
           | girvo wrote:
           | For me it's the same                       yarn create react-
           | app my-app --template typescript
        
         | [deleted]
        
         | [deleted]
        
         | janpaul123 wrote:
         | You didn't see my face when I wrote that ;)
        
       | pjmlp wrote:
       | Nice work!
       | 
       | Note that Microsoft actually has a compiler from a Typescript
       | subset into C++, as part of the MakeCode IoT education project.
        
         | janpaul123 wrote:
         | Ah yes; I did see that but forgot to mention it:
         | https://makecode.com/language
        
       | simjnd wrote:
       | Not sure if you're familiar with or heard about AssemblyScript
       | [1]. It sounds like the goal you are trying to achieve, but with
       | a saner approach: create a TypeScript-like language that compiles
       | to WebAssembly. This means it gives you native access to SIMD,
       | and eventually even threads! All while avoiding the overhead of
       | learning a new language (well there are still some gotchas since
       | it is actually a new language, but very close). No need to think
       | about whether you need to optimize X function or manually manage
       | memory somewhere, and still get the awesome performance of Wasm.
       | 
       | [1]: https://www.assemblyscript.org/
        
         | wrnr wrote:
         | I've tried AS for a while but then just learned Rust. The wasm
         | ecosystem is a lot more mature on Rust (probably the best of
         | all languages) so I'm glad i'v learned it. AS syntax looks like
         | TS, but under the hood it's another language with a lot of open
         | problems like testing, sending data back and forth between wasm
         | and js. AS supports operator overloading, but only for for
         | values of the same time, like Vector * Vector, but not BiVector
         | * Vector, and Rust does.
        
         | janpaul123 wrote:
         | Yep, but it doesn't really solve any of the problems that I
         | mention in the article, unfortunately. The Typescript
         | familiarity part is nice, but it doesn't really work well with
         | existing code; you still have to set up Wasm-JS communication;
         | it doesn't work with existing ArrayBuffers / multiple memories;
         | it's garbage collected if you want to use more complex objects;
         | etc. In many ways it's better to use Rust (which looks a bit
         | like Typescript) than AssemblyScript..
        
           | [deleted]
        
       | [deleted]
        
       | rattray wrote:
       | I've never written (or even read) JS code with ArrayBuffers. I
       | wonder how much mileage you might get with better education
       | and/or libs for using them? And perhaps a highly opinionated
       | linter for things like optimal for-loop patterns?
        
       | gigel82 wrote:
       | We briefly toyed with the reverse idea; wanted to share some code
       | between web and native, and TypeScript / C++ already look very
       | similar - what if we invented a subset of TypeScript that can be
       | simply translated into C++ (as long as you stick to static use
       | and types).
       | 
       | Worked ok for a while but broke down real quick once we brought
       | in external npm dependencies.
       | 
       | Now we're just embedding V8 in our native apps and running the TS
       | code through that. Not as interesting, but lets us import any
       | random npm package (which is both good and bad).
        
         | watermelon0 wrote:
         | Are you using V8 heap snapshots to speed up startup time by any
         | chance?
         | 
         | IME this can greatly improve cold starts.
        
         | janpaul123 wrote:
         | Hah, cool! I agree that for your use case V8 makes more sense
         | :)
        
       | janpaul123 wrote:
       | Hi! Author here. Really curious what you all think. It's a pretty
       | crazy idea but maybe there's something to it! Hacker News is
       | always a special place for ideas like this -- you never know what
       | you're gonna get ;) -- so I'm looking forward to discussing this
       | with y'all!
        
         | mattgreenrocks wrote:
         | The TypeScript++ example looks like the type of code that JITs
         | typically like. Python has Numba, where users affix a @jit
         | annotation to functions to request that. It works pretty well
         | in my experience.
         | 
         | However, at this point, I'm mostly of the opinion that langs
         | need some notion of mechanical sympathy if they want to be used
         | for high-performance. JS engines probably have tens of millions
         | of dollars of dev effort poured into them by now, yet they get
         | soundly beaten by WASM, which is much younger. The conceptual
         | foundation matters a lot.
         | 
         | That said, there's probably a nice space for an ergonomic,
         | reasonably fast PL that sits between Rust and JS.
        
           | janpaul123 wrote:
           | Good points. I agree that choosing the abstractions wisely is
           | key here.
        
           | discreteevent wrote:
           | That was the main motivation behind the inventors of dart.
           | They got frustrated with all the hacks they had to put into
           | V8 just because JavaScript was so mechanically unsympathetic.
           | You can hardly blame then because they originally came from a
           | background of developing smalltalk and self VMs.
        
             | emteycz wrote:
             | Isn't JS much more Smalltalk-ish than Dart? I don't have
             | much experience with Dart, but it always seemed like a very
             | OOP language to me (and not in the "message passing"
             | meaning).
        
           | isaacimagine wrote:
           | > JS engines probably have tens of millions of dollars of dev
           | effort poured into them by now
           | 
           | And JS engine JIT codegen modules are put to good use
           | compiling wasm.
        
           | notriddle wrote:
           | > That said, there's probably a nice space for an ergonomic,
           | reasonably fast PL that sits between Rust and JS.
           | 
           | Other than not running natively in web browsers, isn't that
           | language called Ocaml?
        
         | novocantico wrote:
         | The main feedback I have is that I wanted to read this near the
         | end of my lunch break, because I've been interested for years
         | in the idea that a reasonably-restricted subset of TypeScript
         | (who needs all that dynamism) can almost definitely be compiled
         | to machine code and be made _super fast_ , faster than V8 -- so
         | I was looking for a TLDR in this article and spent a couple
         | minutes looking for it and then just reading whole paragraphs
         | and still don't really know what you've got here.
        
           | janpaul123 wrote:
           | Good feedback; I should add a TL;DR. Basically this is a
           | proposal to create a language that sits somewhere between
           | Typescript and Rust, and which you can incrementally adopt if
           | you already use Typescript.
        
           | mattdeboard wrote:
           | dang imagine how much more leisurely you could've read the
           | article if you didn't also take some of your lunch break to
           | write this comment!
        
         | transitivebs wrote:
         | Really interesting article.
         | 
         | I was doing some high-level research on a related question the
         | other day: https://transitivebullsh.it/webassembly-
         | research-9e231b80e6d...
         | 
         | I know you've responded to a few people on here that
         | Assemblyscript doesn't address the main issues you're talking
         | about in the article, but honestly it does have a lot of things
         | going for it.
         | 
         | I'd love to see a more direct breakdown of this space that
         | explains why prior works like assemblyscript, nectarjs, walt,
         | etc all fall short, and where an ideal solution would need to
         | do better.
         | 
         | ^^ this is the type of thing I'd love to chat about if you're
         | interested btw
        
           | janpaul123 wrote:
           | Nectarjs is interesting; I wasn't aware of that. How did it
           | manage to avoid (for example) a garbage collector without
           | making changes to the language?
        
         | pjmlp wrote:
         | Love it, you should check the Typescript compiler used by
         | MakeCode as well.
         | 
         | Maybe there are some ideas there.
        
         | Syzygies wrote:
         | You might want to reconsider the ++ naming convention. Many
         | people capable of a critical appraisal of C++ wouldn't want an
         | association with C++. The prejudice that your name triggers is
         | that you don't understand what others think C++ got wrong, and
         | you're likely to be making the same mistakes.
         | 
         | It doesn't look like you're making the same mistakes, but why
         | trigger that prejudice?
        
         | tomxor wrote:
         | Your example really clicked with me, having written a
         | substantial quantity of JS in a "memory managed" way to avoid
         | GC, and avoiding memcpy by passing buffers in place of
         | pointers.
         | 
         | My initial instinct is that putting such considerations behind
         | a preprocessor syntax has the disadvantage of making them more
         | opaque and magic, and that I personally would continue to do
         | such things more explicitly - which I realise is an ironic
         | thing to say about an untyped, interpreted language, it's
         | probably just the little pseudo "grey beard" on my shoulder
         | which occasionally whispers silly things about "building their
         | own computer out of rocks and twigs".
         | 
         | I guess the point is that there's a balance to the cost vs
         | benefit: making it more convenient (what you call ergonomics),
         | making it more accessible to those that were less likely to
         | manually use that technique, and perhaps resulting in an
         | average of more performant code; but at the cost of more
         | obscurity, and more "magic", perhaps resulting in less educated
         | programmers.
         | 
         | I'm probably overthinking it. Ultimately this argument even
         | applies to for loops, but it's worth being conscious of that
         | cost - it's likely a good idea.
        
           | janpaul123 wrote:
           | Yeah I hear you; and even allude to that in some parts of the
           | article, like this part:
           | 
           | > Another idea to make Typescript-- a bit less restrictive
           | and more ergonomic, would be to use reference-counting of
           | objects, and then try to optimize most away using compile-
           | time reference counting as pioneered by Lobster. This gives
           | most of the advantages of manually managed memory, but makes
           | the ownership model much easier to reason about. It is
           | however slightly less performant, and more importantly, makes
           | performance less predictable, since it becomes more reliant
           | on compiler cleverness.
           | 
           | Even Rust can hide actual performance behind abstractions,
           | and I've already been bitten by that a few times.. Not sure
           | what the right solution is here, but I agree that it's super
           | important to think about this when designing a language like
           | this.
        
           | triyambakam wrote:
           | > having written a substantial quantity of JS in a "memory
           | managed" way to avoid GC, and avoiding memcpy by passing
           | buffers in place of pointers.
           | 
           | What projects were you working on that required that? It
           | sounds interesting
        
             | Jasper_ wrote:
             | I've done this before for plenty of tight loop code.
             | Nothing irks me than staring a profile and seeing "Major
             | GC" multiple times in the middle of a big algorithm.
             | 
             | It's certainly not helped by the latest language fads just
             | completely flooring the GC gas pedal; special mention
             | should go to for...of creating a brand new object for each
             | loop iteration. That's usually the first thing I rip out of
             | tight loops.
             | 
             | A bit of care can make this stuff go 3x fast on PC, and
             | I've gotten completely unusable experiences on mobile (most
             | websites) to be 30-40fps.
        
             | tomxor wrote:
             | Mostly a variety of web based science education
             | simulations. Usually boiling down to some kind of miniature
             | specialist physics engine or procedural animation.
             | 
             | Beyond that, it's more of a personal philosophy than a
             | requirement (I could easily have done all those things more
             | carelessly, but the result wouldn't be so nice, some
             | people's laps would be hotter, and some people would end up
             | with a slow or jerky simulation). I like things to be
             | efficient, I enjoy finding a balance between "efficient"
             | and "minimal". That doesn't mean I avoid GC all over the
             | place adding unnecessary complexity and over optimizing, it
             | just means being considerate where it matters and
             | "idiomatic" where it doesn't - in a physics engine (or any
             | kind of posteriori simulation) it matters because it's
             | running on an interval and will constantly cause
             | perceptible GC hiccups if you don't be considerate with
             | memory.
        
         | mc4ndr3 wrote:
         | Why not write Rust directly, and target WASM for client side
         | environments?
         | 
         | I support efforts to tune existing tech stacks. But there is
         | such a more direct path to performance, reliability, etc etc by
         | dropping (alt)JS entirely now that anything can compile to
         | WASM.
        
           | janpaul123 wrote:
           | I agree; that is what we built the Zaplib framework for. But
           | the reality is that there are tons and tons of existing JS/TS
           | codebases out there, and it'd be nice to have an incremental
           | speedup path for them too.
        
           | michael_j_ward wrote:
           | In the article
           | 
           | https://zaplib.com/docs/blog_ts++.html#best-of-both-worlds
        
           | [deleted]
        
       | freeqaz wrote:
       | Dumb question: Do you mean "Fast" as in speed of execution, or
       | "Fast" as in compile times? (Or maybe you mean both? I haven't
       | used Rust.)
       | 
       | Might be worth clarifying because I immediately got excited about
       | a faster TypeScript compiler!
        
         | johnny22 wrote:
         | Rust isn't known for quick compile time.
        
         | janpaul123 wrote:
         | Yeah I meant speed of execution. Sorry for the letdown! But
         | https://github.com/swc-project/swc is a very fast Typescript
         | compiler written in Rust :)
        
       | triyambakam wrote:
       | > Various articles have been written, comparing the performance
       | of Javascript versus WebAssembly ("Wasm") in the browser.
       | 
       | Nit pick: Every word in this sentence in the article is a link.
       | This way of linking multiple related resources is so hard to keep
       | track of and navigate. I need to hover over or click each word to
       | discover the resource.
        
       ___________________________________________________________________
       (page generated 2022-04-07 23:00 UTC)