Readit News logoReadit News
hardwaregeek · 6 years ago
Whenever I write Rust, I have a lot of fun, but I'm still not sold on it for most web dev.

The analogy that comes to mind is that Rust is a really nice sports car with a great engine. It handles like a dream and you can feel the powerful engine humming while driving it. With the right open road, it's a great time. You can really optimize code, make great abstractions and work with data easily.

Unfortunately, web dev generally isn't a wide open road. It's a lot of little turns and alleys and special cases. Driving Rust in web dev is a lot of accelerating only to screech to a halt. I wrote a backend API for a side project in Rust. And true to what I said, Rust handled like a dream. But I didn't need the power. I spent most of my time screeching to a halt worrying about the plumbing between the various immature Rust libraries. And that's on the backend, which is way more mature compared to the frontend Rust libraries.

Judging by this post, OP managed to find a great open road in web dev to use Rust. I only wish I could find one as worthwhile.

aphextron · 6 years ago
This really nails why languages like PHP and Ruby have won out over static typed, compiled ones for application level web development. The web is a massive collection of disjointed, loosely coupled APIs that all (just barely) interoperate to provide a massive array of functionality. Languages that tend to work well with it are those that are highly flexible around the corner cases of these technologies, and allow you to quickly iterate through the process of gluing them together.
jes5199 · 6 years ago
I’ve worked on several large Ruby codebases, and the thing is, the same qualities that make it easy to get a Ruby project up and working quickly make it a complete nightmare to maintain later. Its expressiveness and malleability mean that you can never really be sure that you understand how code is being used, and the complexity that emerges from a few years of that is incredibly overwhelming. Nowadays I would much rather slog through ten times as much Java boilerplate, because later I’d expect that I could still refactor code without fearing that the whole thing would collapse around me
rubber_duck · 6 years ago
Won ? Ruby fell off a cliff once it got to a point where people had to maintain that shit in production - I'm currently working on a large mature RoR codebase and I'm switching jobs ASAP because it's incredibly painful to work with and feels like a dead end career wise - and I like the gig otherwise - good product and a decent team - but the technology is draining so much of my life energy on nonsense it's ridiculous. And the language is built for unmaintainability - standard functions being abbreviated to a single letter, 2 or 3 aliases for a single standard function (map/collect and such), Rails overriding the conventions of the language (! postfix). And then there's the architectural retardation of fat models, fat controllers and using mixins ("concerns") completely break encapsulation - all actively killing code reuse-

PHP has long been a meme and is mostly legacy stuff or bottom tier work.

Dynamic languages are adding static optional static typing because the value provided by tooling as the projects scales is undeniable.

It took ES6/TypeScript to drag JS out of the dump that it was with every library adding its own take on a class system - the maintainability jump from ES5 to TS is incomparable for anything larger than 1k LOC

blub · 6 years ago
They've "won" so far because static types languages were cumbersome and unpleasant to use, but this is changing and dynamic languages are learning some type tricks too.

The issue here is with Rust: its strengths are mostly irrelevant for the web and its weaknesses (particularly slow development compared to the competition because of having to pacify the type checker) are really important.

Op is painstakingly beating around the bush, but what they're getting at is that Rust + webdev = mismatch.

masklinn · 6 years ago
> This really nails why languages like PHP and Ruby have won out over static typed

It really doesn't.

Languages like PHP and Ruby "have won out" over statically typed languages because the representatives of statically typed languages at the time were Java and C++, both of which were bad (they still are, but they were): verbose, difficult (and verbose) to leverage for type-safety, missing a bunch of tremendously useful pieces (type-safe enums to say nothing of full-blown sum types), nulls galore, …

As a result, the gain in expressiveness and terseness (even without trying to code-golf) of dynamically typed languages was huge, the loss in type-safety was very limited given the choice was "avoid leveraging the type system" or "write reams of code because the language is shit", and the fast increase in compute performances more than compensated for the language's loss in efficiency.

And that's before talking about the horror show that Java's web frameworks ecosystem was circa 2006.

> Languages that tend to work well with it are those that are highly flexible around the corner cases of these technologies, and allow you to quickly iterate through the process of gluing them together.

That's really complete hogwash outside of the client, which isn't what we're talking about here since neither php nor ruby run there. On the server you have clear interfaces between "inside" and "outside", and there's no inflexibility to properly taking care of cleaning up your crap at the edges. Quite the opposite, really.

friendzis · 6 years ago
I think you get it backwards. Things are disjointed, loosely coupled because highly dynamic languages have won. The flexibility of dynamic languages, which can be great when working around dynamic corner cases, does not force developers into fixed, well-defined contracts keeping everything loose and disjoint.

PHP is highly to blame. PHP, being a scripting language, is easy to deploy and keeps chugging along at all costs. It may do something nonsensical, but it will try to chug along to completion without aborting. It creates a system where it is easy to write and deploy something that usually works.

pjmlp · 6 years ago
Having ridden the 90's .com startup wave with an in-house application server written in a mix of Apache plugins and Tcl, I learned the hard way to never again rely on anything that doesn't bring a JIT or AOT compiler to the party.
vbezhenar · 6 years ago
Java, .NET, Golang are actively used for web development. PHP is popular, especially for small projects, but it definitely did not win, web development is a contested area.
ThePhysicist · 6 years ago
They are also evolving though. I don't know about Ruby and PHP but in Python gradual typing via type annotations really makes projects much easier to maintain and develop these days. While "mypy" (the semi-official type checker tool) still has a long way to go in terms of library support it works really well and helped me to find many issues by analyzing the code, as opposed to running it and finding the issues via tests (or in production).

So I think typing has its merits and languages like Typescript really make development safer and code easier to understand, while still making it possible to write and interface with untyped code if necessary.

giantDinosaur · 6 years ago
I'm not sure this is really true - the subtleties of HTTP are not best handled with dynamic languages, and the actual HTTP API is fairly simple for most web app development. The areas with the most complexity related to the web, itself, are usually do with servers, concurrency, etc - precisely where these languages tend to fall apart.
entha_saava · 6 years ago
> This really nails why languages like PHP and Ruby have won out over static typed ...

Real reason is lowering the bar of entry, and that explains why web is horribly broken.

The "bootcamp webshit" meme exists for a reason. That's not gatekeeping - lowering the bar to entry below a certain level leads to drastic decrease in quality.

pjmlp · 6 years ago
Depends what one considers application level web development, over here it has been pretty much Java and .NET, with occasional C and C++ written libraries, during the last 20 years.
quickthrower2 · 6 years ago
This is probably true .... but watch out for Node with Typescript. You get that quite iteration, but with a decent amount of type safety most of the time, but with a drop down to the 'any' type for libraries that haven't written type definitions. I also use the existence of type definitions as a guide to how mature the library is :-), so that's a win win.
crimsonalucard9 · 6 years ago
This is a mistaken view point. Every function you can ever write is bounded by a type, thus whether you use Ruby, PHP, or Rust can be described by a bounded type.

Every time you write logic in your code, your brain is aware that the logic is dealing with a specific type. Writing a type signature on top of that is just additional instructions to the compiler about the type you have already specified in your logic. It is a minor inconvenience.

There are many reasons why Ruby and PHP won out. One of the reasons is many people misunderstand the power and flexibility of types. Once they understand this, they will know there is really no trade off between statically typed and dynamically typed. Statically typed languages are infinitely better and the only downside is a minor inconvenience.

First off, note that there is only one function in the universe that can really take every single type in existence and that function is shown below:

  -- haskell
  identity :: x -> x
  identity x = x

  # python
  def identity(x: Any) -> Any:
      return x
This is the only untyped function in existence. Every other function in the universe must be typed whether it is typed dynamically or statically is irrelevant, either way your code will have to specify the type in logic or in the type signature. You can see this happening in the examples below...

The above example have no logic to specify a type... The minute you start to add any logic to your function immediately your function becomes bounded by a type. Let's say I simply want to add one in my identity function.

  -- haskell
  identity :: Int -> Int
  identity x + 1 = x + 1

  # python
  def identity(x: Int) -> Int:
      return x + 1
The very act of adding even the simplest logic binds your function to a type. In this case it binded my function parameter to an integer. Whether you use PHP or Ruby or Rust there is a type signature that describes all functions.

Let's say I want to do garbage code like write a function that handles an Int or a String? That can be typed as well....

  --haskell
  type IntOrString = Number Int | Characters String
  func :: IntOrString -> IntOrString
  func Number n = n + 1
  func Characters n = n ++ "1"

  #python
  IntOrString = Union[str, int]
  def func(n: IntOrString) -> IntOrString:
      if isinstance(n, int):
         return n + 1
      if isinstance(n, str):
         return n + "1"

Let's say I want to handle every possible JSON api in existence? Well it can be typed as well.

   -- haskell
   type JSON = Number Float | Characters String | Array [JSON] | Map String JSON
   func :: JSON -> JSON
   func Array x = x ++ [1.0]
   func x = x

   -- python
   JSON = Union[float, str, List["JSON"], Dict[str, "JSON"]]
   def func(x: JSON) -> JSON:
     if isinstance(x, list):
        return x + [1.0]
     else:
        return x 

  
There really isn't any additional flexibility afforded to you by a dynamically typed language other than the slight overhead of translating the types you already specified dynamically into types that are specified statically.

One caveat to note here (and this is specific to haskell) is lack of interfaces specific to record types. I cannot specify a type that represents every single record that contains at least a property named x with a type of int.

swyx · 6 years ago
this was historically true, but I suspect in the age of the evergreen browser this argument has been seriously dented (but not invalidated)
cs702 · 6 years ago
> The analogy that comes to mind is that Rust is a really nice sports car with a great engine. It handles like a dream and you can feel the powerful engine humming while driving it. With the right open road, it's a great time. You can really optimize code, make great abstractions and work with data easily.

I prefer a different analogy:

Rust is high-end automated industrial equipment for machining high-precision metal parts that will fit perfectly with each other and which you can use to build anything you want, with high confidence that it will work and last a long time. But if you're under pressure to build lots of small, partially documented, constantly changing parts every day, you might be better off using more flexible equipment and materials (balsa wood, bailing wire, masking tape, etc.) to get the job done, even if the result will be messier and more prone to breaking.

mwcampbell · 6 years ago
> with high confidence that it will work and last a long time

And we need more of our software to be like that. Now if we could just do something about the constant pressure to compromise.

otoburb · 6 years ago
>>But if you're under pressure to build lots of small, partially documented, constantly changing parts every day, you might be better off using more flexible equipment and materials (balsa wood, bailing wire, masking tape, etc.) to get the job done, even if the result will be messier and more prone to breaking.

Python & Deno/Node fit the bill for the latter category. Would you consider Julia in the former or latter category for ML use-cases?

csomar · 6 years ago
It's still a significant upgrade over JavaScript. I'm developing a web app with the Backend in Rust and Front-end in Vuejs/JavaScript. Sure Rust was slower to develop, but it doesn't throw errors like 'val in undefined' and then I have to go debugging where I check for the value of val. You do that beforehand on Rust and that avoid a whole class of problems.

JavaScript is cheaper to get started but becomes way more expensive to maintain. My Rust code on the other hand: Once it works it keeps working. If it compile it probably won't bug down the road.

I'd switch to Rust / WebAssembly once the libraries are mature/stable/documented enough. The overhead cost is worth it in the long run.

dgb23 · 6 years ago
> JavaScript is cheaper to get started but becomes way more expensive to maintain.

I think this is assumption is a bit too broad. There is another side of this:

In JS you write less code than in Rust and there is less explicit coupling in a dynamic codebase. So changes tend to be smaller and faster as well.

For example if you pass a top-level data-structure X through A, B... and C but only C cares about some part Z. Then you change how Z is produced in A and consumed in C.

If you are dynamic you just do exactly that, which is actually just fine. In a static language you have to change all the B's. Or you take the time and write a sensible abstraction over Z or X so in the future you don't have to change the B's anymore, which is better, but ultimately less readable and more complex.

Stuff that is well understood and specified in advance suits a language like Rust better. You get all these runtime guarantees and performance. You get all this expressive (but explicit!) power to fine-tune abstractions and performance. It's great.

But the closer you get to a UI (especially GUI) and non-technical, direct(!) users, the more dynamic you want to be. Because in this context you are more of a human to computer translator: requirements get discovered via iterations, interactions need to be tested and evolve etc.

ronanyeah · 6 years ago
You can get that kind of reliability on the front end with Elm, Purescript etc but investing in such niche languages is obviously a nuanced decision.
MaxBarraclough · 6 years ago
You're referring to Rust's static type system. What do you make of TypeScript?

Dead Comment

laurencerowe · 6 years ago
For backend web development I was somewhat disappointed to see that many of the new web frameworks (all async) allocate extensively on the heap (for example lots of Strings in their http request types.)

I mean it works but I don't understand why I would go to the bother of thinking about lifetimes when it seems performance would be similar to Kotlin / Swift / F#.

pas · 6 years ago
The short answer is that because async is not done yet in Rust.

The long answer probably includes GATs (generic associated types), and the even longer answer starts with the amazing work that Nico et al. does to reinvent the internals of the Rust type checker. (Basically - if I remember correctly - the compiler team is currently refactoring big parts of rustc, to librarify the type checker, and replace it with a PROLOG-ish library called "chalk", which is able to prove more things, so it allows better handling of GATs, so it allows better handling of async, where you get "impl Future<Output = T>"-s everywhere.

But also somewhere there is that the ergonomics of async/.await are still not very much in progress too. With better error messages people will be able to forego Box<>-ing and figure out what to use instead, and only heap allocate where they must.

It's possible to write low-level async code with hand rolled-polled Futures, and push/manage as much stuff on the stack as possible. But ... that takes time, and performance is already "good enough". (And/or probably there are bigger gains in performance in other areas, such as scheduling.)

And, finally, boxing helps with compile times. (Because it's basically trivial for the compile to prove that a heap allocated simple trait object behaves well compared to a stack allocated concrete, but usually highly complex (plus unnameable) type.)

codemac · 6 years ago
As a complete noob to rust, I found attempting to manage a memory pool that is handed out per request to cause all kinds of borrow checking headaches.

My bet is people choose to allocate heavily rather than figure out how to share memory correctly with Rust. I need to learn more rust to get a hang of it so I don't allocate so much.

Are there any rust folks who have a great "list of memory management models for rust"?

staticassertion · 6 years ago
I often write my code to allocate at first just to get a feel for the API and business logic and then go through it later to remove them. Given that all of those frameworks are still fairly new it wouldn't shock me to hear that that's the case.
cies · 6 years ago
I'd be hard pressed if a backend in Rust gives the same perf as Kotlin/F#. Especially if you write the Rust with an async stack you will likely come out significantly faster than the other options: small binaries, short startup time, less memory usage, more throughput, slightly shorter request cycles, ...

The only place that the langs you mention probably win is: learning curve (F# maybe not so much) a.k.a. getting language illiterate people up to speed, and compile times.

drewm1980 · 6 years ago
Rust never has to run a garbage collector, because it already figured out the lifetimes of all the values in your program statically, with relatively minor help from the programmer. This may make your code faster or more likely to be correct than code written in some of those languages.

Deleted Comment

lewisjoe · 6 years ago
Nice analogy. Here's somethine new. Rust is not just a sports car, but an eco-friendly electric one at that.

One topic OP hasn't touched upon is the disadvantage of "pushing client side to the server". JS is terrible at handling concurrent processes. The browsers have been able to make do because they typically care about just one user.

In the server though, it's terribly important to handle thousands of users concurrently. JS engines suck at it.

To put it in plain words, if you are into SPAs and want server side rendering, among all the other issues the one sure wall you'd be hitting is scaling issues.

JS will never be able to construct and send HTML over as efficiently as Rust could. This is going to be the reason why Rust(or a similar tech) will eventually win the web.

josephg · 6 years ago
I wish speed mattered more, but JavaScript on Nodejs is performant enough for 95% of websites out there. Most websites are in the long tail, and never need to handle more than about 10 requests per second. For most websites, team velocity matters more than the AWS bill.

A clean static rendering system with caching, built on top of react / svelte / whatever performs well enough for almost everyone. And every year cpu costs drop, V8 gets faster and JS libraries get a little bit more mature.

I love rust, but I don’t see it displacing nodejs any time soon. Maybe when websites can be 100% wasm and the rust web framework ecosystem matures some more. Fingers crossed, but I’m not holding my breath.

nicolodavis · 6 years ago
Yep, I don't think Rust is quite there yet for web dev. I didn't use Rust for any frontend interactions. The web app is an SPA written in Svelte. I only used it for the core state update logic, which benefits from the typing and performance boost.
hardwaregeek · 6 years ago
Yep! You found a really great open road to drive Rust. I'm jealous :D. If I had an app with as interesting requirements, I'd certainly consider your approach
rkwz · 6 years ago
Love the analogy!

I think there's value in mixing Rust with languages with mature libraries like JS/Python/etc to optimize performance critical code paths - basically for things we've been using C/C++ so far.

There's also a lot of progress in Rust community, I believe it'll get mature libraries very soon in future.

EugeneOZ · 6 years ago
I use Rust for web not for performance, but for strict typing + smart compiler, safe refactoring, errors handling and many other language features - Rust is an amazing language even when you don't need performance.

Deleted Comment

yachtman · 6 years ago
You might enjoy this blog post I wrote: http://kyleprifogle.com/churn-based-programming/
mkesper · 6 years ago
It would be even more enjoyable if the text was black, had to use reader mode.
Dowwie · 6 years ago
The first exposure is the hardest part. It's not the kind of language that one can just pick up and use effectively without first understanding the fundamentals, especially if using an async runtime. The investment is worthwhile, though.

Deleted Comment

Deleted Comment

chjj · 6 years ago
> webassembly is faster than javascript

Everyone says this, but I would dispute it as misleading in a lot of cases. I've been experimenting a lot with wasm lately. Yes, it is faster than javascript, but not by all that much.

It's the speed of generic 32 bit C. It leaves a lot to be desired in the way of performance. My crypto library, when compiled to web assembly, is maybe 2-3x the speed of the equivalent javascript code. Keep in mind this library is doing integer arithmetic, and fast integer arithmetic does not explicitly exist in javascript -- JS is at a _huge_ disadvantage here and is still producing comparable numbers to WASM.

This same library is maybe 15 or 16 times faster than JS when compiled natively, as it is able to utilize 128 bit arithmetic, SIMD, inline asm, and so on.

Maybe once WASM implementations are optimized more the situation will be different, but I am completely unimpressed with the speed of WASM at the moment.

daninet · 6 years ago
I also have a WASM crypto library, focused on hashing algorithms: https://www.npmjs.com/package/hash-wasm#benchmark

I was able to archive 10x-60x speedups compared to the performance of most popular JS-only implementations.

You can make your own measurements here: https://csb-9b6mf.daninet.now.sh/

chjj · 6 years ago
Yeah, hashing in WASM seems to be fine in terms of speed, though 60x faster does still sound surprising to me. Hashes with 32 bit words (e.g. sha256) can be optimized fairly well in javascript due to the SMI optimization in engines like v8. I should play around with hashing more.

I was in particular benchmarking ECC, which is much harder to optimize in JS (and in general).

Code is here:

JS: https://github.com/bcoin-org/bcrypto/tree/master/lib/js

C: https://github.com/bcoin-org/libtorsion

To benchmark:

    $ git clone https://github.com/bcoin-org/bcrypto
    $ cd bcrypto
    $ npm install
    $ node bench/ec.js -f 'secp256k1 verify' -B js

    $ git clone https://github.com/bcoin-org/libtorsion
    $ cd libtorsion
    $ cmake . && make
    $ ./torsion_bench
    $ make -f Makefile.wasi SDK=/path/to/wasi-sdk
    $ ./scripts/run-wasi.sh torsion_bench.wasm ecdsa

Shorel · 6 years ago
I think he doesn't complain at all about WASM speed vs JS.

He wants WASM to be closer to C performance. I.e. to move further along this line:

    |JS|========>|WASM|=========>=========>========>|C|

Matthias247 · 6 years ago
>> webassembly is faster than javascript

> Everyone says this, but I would dispute it as misleading in a lot of cases. I've been experimenting a lot with wasm lately. Yes, it is faster than javascript, but not by all that much.

I think even if it is faster in general, you might lose all that advantage as soon as you have to cross the WASM <-> JS boundary and have to create new object instances (and associated garbage) that you never would have needed to create if you had used only one language.

Therefore moving to WASM for performance reasons on a project which crosses the language boundaries very often due to browser API access doesn't seem too promising to me.

loxs · 6 years ago
I am writing an app that needs worker threads both on the backend and also on the frontend (because of some heavy processing of large amounts of "objects") and my experience with TS so far is very poor. JS runtimes are just not suitable for heavy concurrent/parallel processing. Serialization/deserialization overhead between threads is probably (much) worse than it would be if the worker threads were in Rust.

It's not a matter of speed here. It's a matter of enabling certain types of programs which are borderline impossible with pure JS runtimes.

So I will probably move most of the logic to Rust

kbenson · 6 years ago
> Yes, it is faster than javascript, but not by all that much. ... My crypto library, when compiled to web assembly, is maybe 2-3x the speed of the equivalent javascript code.

2-3x may not be the 15-16x you see in native code, but it's still a massive speedup in already optimized code, and is likely enough to make a bunch of applications that weren't quite feasible to do in on the web now feasible.

penagwin · 6 years ago
I think the point is only certain use cases (usually related to number crunching like crypto, but undoubtedly games too) may see substantial improvements, they still aren't close to "native" speed, and nearly all other use cases won't see much if any benefit, especially compared to the additional complexity of another language, compiling to was, etc.

Plus things like competitive games and what I'll call "pretty" games have to squeeze out as much performance as possible, and no hitching is acceptable to competitive games, which IMO means WASM is still a no-go for those types of games(although games that don't have this requirement undoubtedly benefit)

nikki93 · 6 years ago
Another consideration here is that you can use languages that offer control over data layout as a natural feature, which can matter a lot for good cache utilization etc. In many cases the data layout matters a lot for performance.

You can do this in JS too with TypedArray and whatnot but the key word here is 'natural.'

I've been working on a game engine as a side project with C++ and WASM -- and there are already many improvements over what I was getting with JS due to less GC, better data layout (the data layout thing is also esp. helpful for managing buffers that you drop into the GPU). I don't think it was about 'pure compute' as much as these things. C++ and Rust give you tools to manage deterministic resource utilization automatically which really helps.

A bonus is that the game runs with the same code on native desktop and mobile.

pjmlp · 6 years ago
Chrome already has experimental support for SIMD, have you tried that as well?

Otherwise, eventually I expect WebAssembly to match what Flash Crossfire and PNaCL were capable of 10 years ago.

chjj · 6 years ago
No, but I've been meaning to test this. I did notice it was available in node.js with --experimental-wasm-simd. I hope this proves me wrong about wasm, but I'll have to try it.
ben-schaaf · 6 years ago
Have you tried with firefox? Last I heard they've got far and away the fastest wasm implementation.
chjj · 6 years ago
No. I've just been building with the WASI SDK and running the resulting binary with a small node.js wrapper script. So, I've only tested v8's WASM implementation so far.

Does firefox have a headless mode, a standalone implementation, or some CLI tool I can use to run a WASM binary? Running stuff in the browser is cumbersome.

CryZe · 6 years ago
On algorithmic code, idiomatic Rust + WASM is often about 10 to 40 times faster than idiomatic JS. The problem however is that each call between WASM and JS has a hefty cost of about 750ns. So your algorithm needs to be doing a significant amount of independent calculations before you will see these performance differences.
MaxBarraclough · 6 years ago
> each call between WASM and JS has a hefty cost of about 750ns

Why is this the case? Can we expect it to go away as browsers mature?

flohofwoe · 6 years ago
But 2-3x speedup over a well written Javascript version running in a modern Javascript engine is quite impressive, isn't it?

One thing that's often overlooked is that even though "idiomatic Javascript" using lots of objects and properties is fairly slow, it can be made fast (within 2x of native code compiled from 'generic' C code) by using the same tricks as asm.js (basically, use numbers and typed arrays for everything). But the resulting Javascript code will be much less readable and maintainable than cross-platform C code that's compiled to WASM.

jfkebwjsbx · 6 years ago
> maybe 2-3x the speed of the equivalent javascript code.

That is an insane difference even if nowhere close to native code.

Some engineering fields would be crazy with a 20% gain... 200% is huge!

chjj · 6 years ago
I agree it still is signficant, but this is not how wasm is being touted. Look at wikipedia: https://en.wikipedia.org/wiki/WebAssembly#History

They even say asm.js is supposed to be "near-native code execution speeds". In my experience, it is no where close to native speed. People should avoid this kind of deceptive marketing.

k__ · 6 years ago
WebAssembly with Rust is sometimes bigger and "just as fast as JS".

But it's way more predictable, no more crazy 95th percentiles.

MaxBarraclough · 6 years ago
I'd be interested to see how current-day WASM stacks up against current-day Java. Don't suppose you've ported your crypto code to Java? Other than the maturity of the JIT compilers, are there reasons we should expect WASM to be any slower?
_bxg1 · 6 years ago
In some ways it should be faster because it isn't garbage-collected. But I agree that would be a much better benchmark for what should be possible.
amitport · 6 years ago
Hi Nicolo,

Here are my two (or more) cents:

1 - Javascript is fast enough for your use case. No one will notice the difference in a board game website.

2 - AI should probably be implemented in python anyway. As ugly as python can be, you shouldn't fight the world; there are too many free advanced AI algo implementations in python out there.

3 - Regarding "Limitations of TypeScript" (strict typing / data validation / error handling): first of all arguable claims, but moreover, even if you think rust is better in these concerns, they are not important enough to justify reimplementation, disregarding away typescript's advantages and taking the risk involved in a new language and toolset. Yes, I can see the appeal as a programmer to learn new stuff, but seriously you should have much better reasons to rewrite existing code.

BTW, also, if I would think of a rewrite, I would have gone with scala or python, both are slower on the web, but seriously, it will not amount to anything meaningful in your use-case. Scala has better typing, and contextual abstraction is a killer feature for DSLs like game mechanics specification. Python is the lingua franca of AI, and pypy has greenlets [1]! Which is much cooler than people seem to realize. Specifically, it should allow writing immutable redux-like command pattern operations, as regular code, without the weird switches everywhere.

BTW2, I've contributed to boardgame.io, please consider staying with open source. We can build something like boardgame-lab together.

[1] https://greenlet.readthedocs.io/en/latest/

nicolodavis · 6 years ago
Hey Amit, good to hear from you!

> Javascript is fast enough for your use case. No one will notice the difference in a board game website.

No, actually. Have you seen how long boardgame.io's MCTS bot takes to make a Tic-Tac-Toe move? Not the end of the world, but certainly in need of improvement.

amitport · 6 years ago
Yes, but AI search algorithms like MCTS are slow in general. Even with C, it will be very slow when you want the AI to be smart and consider many actions. IMO, you should train using python libs like [1] and move it to the browser with something like [2] OR run AI in the server. YES definitely writing an AI lib for the browser is a great goal, and as a programmer, it is super interesting. Still, it is tough, and time-to-market is much more crucial, as the entire codebase will change once it will interact with actual people.

[1] https://github.com/datamllab/rlcard

[2] https://onnx.ai/

Shorel · 6 years ago
Please ignore him whole hearty.

Some people want to write profitable apps in the shortest amount of time possible, while others want to advance the state of the art in technology.

IMO we always need more people in the second group. And sometimes, you can hit the jackpot and do both things at the same time!

spion · 6 years ago
For a lot of code, if you write JS like you write C (avoid allocations by avoiding the creation of objects, arrays or closures) you should get very comparable performance i.e. within 30% to 50% of C performance
XCSme · 6 years ago
I don't know about JS being slow, while working on https://curvefever.pro it was not too hard to make the game run at 4k, 60FPS for a 6 player multi-player game that renders dynamic geometry with collisions which changes multiple times per tick.

JS is pretty fast if you use TypedArrays, are careful with WebGL calls and pool objects (reduce memory allocations).

lacker · 6 years ago
[TypeScript] does not actually ensure that the data you are manipulating corresponds to the type that you have declared to represent it. For example, the data might contain additional fields or even incorrect values for declared types.

This is only a problem if you are mixing untyped code with typed code, isn't it? Like when you are parsing JSON, you need to do typechecking right then, rather than just using an "any" type. The only other situation I have run into this in practice with TypeScript is when I'm using a library that has slightly misdefined types.

filleduchaos · 6 years ago
> This is only a problem if you are mixing untyped code with typed code, isn't it?

I find it a bit strange that people talk about this as "only a problem", as though it was some weird niche edge case and not an ever-present issue. The written-in-plain-JS ecosystem completely dwarfs the written-in-TypeScript one; unless you're doing something rather trivial you're quite likely to end up depending on a library that barely had the shape of its objects in mind during development, with typings (if they're even present) that were contributed by someone that's almost definitely not the actual library author.

Of course, if you're competent enough you can correct typings and always remember to run runtime checks on data that doesn't come from you and so on. But it's too easy for a beginner to fall into traps like mishandling data that comes from a dependency (especially when it's buggy/ostensibly has typings) - in my opinion, there should be a first-party compiler/linter option to enforce checks on any `any`.

lacker · 6 years ago
You don't have to depend on badly-written untyped third-party libraries, just because there are a lot of them out there. Many projects and companies will avoid doing so. This is especially reasonable if your comparison is switching to a language like Rust; there are probably fewer third-party libraries available in Rust overall than there are libraries with accurate TypeScript definitions available.
tigershark · 6 years ago
No, nominal types are extremely useful to ensure the correctness of your software. You can define a function to receive a FirstName and LastName instead of passing strings so you cannot accidentally mix up the parameters for example. There are several techniques to approximate nominal typing in typescript (https://medium.com/better-programming/nominal-typescript-eee... for example) and there is an open issue https://github.com/Microsoft/Typescript/issues/202 but it’s still not being considered for implementation as far as I remember.
nicolodavis · 6 years ago
That's correct. You have to insert validation code at all the entry points, which was the case for me.

Moving to Rust doesn't eliminate validation altogether, but you don't have to do any type related validation which is nice.

mcny · 6 years ago
Not sure if this is a place to ask this but if someone does not have experience working with Javascript, they might have trouble reasoning about this code:

https://codesandbox.io/s/is849

edit: complete code

```typescript

class Person { id: number; name: string; yearOfBirth: number;

    constructor(id: number, name: string, yearOfBirth: number) {
        this.id  = id;
        this.name = name;
        if (yearOfBirth < 1900 || yearOfBirth > 2020) {
            throw new Error("I don't understand you. Go back to your time machine.");
        } else {
            this.yearOfBirth = yearOfBirth;
        }
    }

    getAge(): number {
        const currentDate: number = new Date().getUTCFullYear();
        return currentDate - this.yearOfBirth;
    }
}

class Dog { id: number; name: string; yearOfBirth: number;

    constructor(id: number, name: string, yearOfBirth: number) {
        this.id  = id;
        this.name = name;
        if (yearOfBirth < 1947 || yearOfBirth > 2020) {
            throw new Error("I don't understand you. Go back to your time machine.");
        } else {
            this.yearOfBirth = yearOfBirth;
        }
    }

    getAge(): number {
        const currentDate: number = new Date().getUTCFullYear();
        return (currentDate - this.yearOfBirth) * 7;
    }
}

const buzz: Person = new Person(1, `Buzz`, 1987);

const airbud: Dog = buzz;

console.log(`Buzz is ${buzz.getAge()} years old.`);

console.log(`Airbud is ${airbud.getAge()} years old in human years.`);

```

benschulz · 6 years ago
No[1], TypeScript is unsound in many ways. Most of them are intentional trade-offs to catch as many bugs as possible while not being too restrictive/allowing most JavaScript code to be annotated.

[1]: https://codesandbox.io/s/te0pn?file=/index.ts

Edit: Apparently TypeScript playground links cannot be shared :( Edit2: Published on codesandbox.io, hopefully that works

lmm · 6 years ago
> The only other situation I have run into this in practice with TypeScript is when I'm using a library that has slightly misdefined types.

Unfortunately there's no way to know which libraries have defined their types correctly, so you end up having to check the types you get back from every library you use.

hebrox · 6 years ago
When getting external data, it always good to do a combination of casting and validating. There are a lot of good libraries to help you with this: https://github.com/moltar/typescript-runtime-type-benchmarks
melling · 6 years ago
I don’t know Rust and haven’t done JavaScript for years but isn’t JavaScript a bit more of a higher level language, which would make a developer more productive?

Rust being closer to the hardware should require more code, and effort, to accomplish the same task.

echelon · 6 years ago
> isn’t JavaScript a bit more of a higher level language

Rust has zero-cost abstractions that feel like using Ruby and a rich type system that makes it incredibly expressive. Working in other languages feels like going back to assembly.

I wouldn't want to design state machines in any other language. Rust's enums make it feel smooth as butter. They're a killer app. (The whole ecosystem is. Cargo. Package naming. Traits. So much good stuff.)

Rust is my most productive language now, and I work in Python, Java, and Typescript codebases frequently.

Edit: I'm being downvoted for expressing preference? What's with all the Rust hate? Learn it instead of being a hater. It's a wonderful tool, and it's silly to dismiss because you think people are being hipsters or something. There's a reason people love it.

shpongled · 6 years ago
I'm a big Rust fan too. I have experience in all of the languages you've mentioned, and I'm most productive in Rust as well.

It's funny you mention enums, there was just another thread last week where I brought up how crazy it is that sum types (Rust enums) and pattern matching have been around since the 70s but have largely been limited to the FP languages. After extensively using Rust for ~3 years now, I don't ever want to use a language without sum types - you can write incredibly expressive and concise code with them.

The other major productivity boost for me is the ability to compose and chain Iterators and mix those with collection types.

zenhack · 6 years ago
I think a lot of the best the best things in Rust don't really have anything to do with low level programming per-se. And I find that for most applications, even with all of the extra goodness, the lack of a GC totally craters productivity. Its not because I'm fighting the borrow checker -- I got the hang of it pretty quick. But it means that every API is complicated by the need to think about lifetimes and ownership, having to think about different types of smart pointer, etc. It means you have to manage all of these silly little details which for most applications are pretty irrelevant.

This isn't a criticism of Rust; it's specifically designed for applications where those things do matter. But for the overwhelming majority of apps they don't, and I'd reach for a different tool.

I've found that once I get into a rhythm and I've been working on something in Rust for a bit, it doesn't feel that hard to deal with all that. And a few times I've thought to myself "hey maybe the GC isn't actually buying you all that much?" But then I go back to a GC'd language and watch just how much faster stuff gets done. It's not even close. I think it's one of these things where your brain doesn't notice the time that goes by when you're doing what is essentially mindless busywork.

Part of this is also having come from doing a fair bit of stuff in Haskell, Elm, and a bit of OCaml; the best "high-level" language features are inspired by that language family (including enums) and so it feels like a better control for the difference a GC makes vs. js and friends. It makes a big difference.

hombre_fatal · 6 years ago
When you're writing synchronous, single-threaded code like, say, a binary file parser or even an HTML scraper with blocking APIs, Rust is 1:1 with high level languages, and usually better.

Where Rust diverges is when you're doing async or multithreaded things with complicate lifetimes.

Getting things right from the start instead of solving them JIT as runtime issues pop up in production over the course of the year is Rust's wheelhouse. But even after using Rust for three years, I sometimes feel like I'm one requirement-change away from a problem I can't solve myself in Rust where I could solve it in a couple hours in another language.

jfkebwjsbx · 6 years ago
You are probably being downvoted because of this sentence:

> Working in other languages feels like going back to assembly

This is not a preference, it is an exaggeration and an attack on all other languages.

It is also quite ironic given Rust is intended for low level programming.

Scarbutt · 6 years ago
I have seen this being asked many times in /r/rust and 90% of the answers disagree with you. A common theme is to explore in Python then rewrite in Rust.
blub · 6 years ago
There's the hype and there's the reality. Some people don't appreciate the former much and reach for the down arrow...

Rust is nowhere near the productivity of Ruby or Python. If that's the case for you maybe your projects have some peculiarities or it's a personal thing.

Dead Comment

bluejekyll · 6 years ago
This is complicated. I’m no expert with WASM, but I’m fairly familiar with Rust and have toyed around with Rust and WASM.

With Rust and WASM you pay an expense of FFI between the languages. There are tools that minimize this, but there’s still a cost. Transferring data is limited to very primitive data types today, which adds a cost to translation between Rust and JS. I expect this to reduce in cost as WASM gains abilities to access the DOM and such, but it is overhead. This generally means that for many things Rust is not much faster than JS, but it is for very hot loops over CPU bound computations.

As to productivity. This debate between languages will never end. JS like Python and other interpreted languages give the impression that tasks are being accomplished, but until all code paths are tested, knowing if it is correct is not obvious.

Rust like many other typesafe languages (and it’s definitely on the further end of type safe) allow the compiler to detect errors in usage at compile time, well before testing and production usage. Some of us consider this to be more “productive” as it reduces the overall maintenance of the program after it’s released, but YMMV.

azakai · 6 years ago
This is an important point.

Languages compiled to wasm have an FFI cost, and we will never fully remove it because it just uses different types than Web APIs do. This isn't a Rust problem or a C problem, it's just how wasm is.

Wasm also can't use the JS standard library, and usually ends up shipping some runtime support, like malloc or string handling, which increases download size.

Both of those limitations are why wasm won't make sense for the great majority of web dev work. But wasm shines for "engine" type code, like in this post - pure computation, without lots of links to the outside JS/DOM world.

jevgeni · 6 years ago
Best comment in this thread. To the point and factual.
satvikpendem · 6 years ago
Rust actually can be a higher language. It has true generics, static algebraic data types, functional programming features, and so on, even as it is closer to the metal. It is closer to Haskell or OCaml, but more pragmatic.
sweeneyrod · 6 years ago
In what ways is Rust more pragmatic than OCaml?
genuine_smiles · 6 years ago
Rust’s type system is sound, unlike TypeScript, and Rust provides a lot more performance by default. You can get good performance out of JavaScript, but it can be difficult, and the code can end up being difficult to maintain.

If you’re trying to right very fast, very correct code in JavaScript/TypeScript then Rust may be more productive.

phailhaus · 6 years ago
Depends on what you're optimizing for. If you want memory efficiency and near-native speeds, then you need WebAssembly. And Rust is a fantastic source language to compile to WebAssembly because of its memory safety.
iMuzz · 6 years ago
Mind explaining a bit more here why Rust is a particularly good language to compile to wasm? Why does memory safety help here?

Asking out of ignorance!

lmm · 6 years ago
ML family languages are so much more productive that that probably outweighs the costs of manual memory management. Rust will always be less productive than Haskell or Scala, but a language with a decent type system is going to have a huge advantage over JavaScript.
tigershark · 6 years ago
...Haskell and scala are not part of the ML family. OCAML and F# are languages belonging to the ML family.
Dowwie · 6 years ago
An experienced Rust programmer will write generally better solutions in roughly the same amount of time as what is taken to write a solution in NodeJS, where the work is familiar. There is absolutely more code to write for a language where you can have fine control over practically everything, as long as it's within the constraints governing the compiler. However, web development consists of well-treaded paths using familiar patterns of data access and manipulation. If a new project does not benefit by code re-use, the experienced Rust programmer is going to have to use more tools and techniques to accomplish something similar in functionality to that created in other languages, but with far more guarantees and control. Who cares about guarantees and control? The team that is going to have to share the burden of maintaining the code you write.

With the patterns and libraries used in just this example, you can write a very high performance, memory efficient web server that can handle a large volume of concurrent requests that involve database interactions: https://github.com/actix/examples/tree/master/async_pg

All of the work has been consolidated down to a single file for illustration purposes, and it would usually be spread across files. Does it seem like a ridiculous amount of additional work, compared to other languages? I am misleading you some as there is actually a lot more to write the moment we move beyond plain vanilla workflows but this example proves what is possible.

yarg · 6 years ago
JavaScript's a sloppier language.
empath75 · 6 years ago
It’s not that bad once you get used to it.
harikb · 6 years ago
Alon Zakai[1] gave a good talk[2] on the current state of WebAssembly, particularly on the current state of performance

1. https://twitter.com/kripken

2. https://youtu.be/4ZMY3QE5t9o

apatheticonion · 6 years ago
I'm not certain exactly how LLVM works so I am not sure this is the right question to ask but - How does Web Assembly relate/compare to LLVM? Does LLVM solve the problem of a single binary that can be run portably?
zenhack · 6 years ago
They're trying to solve different problems. LLVM is trying to take care of most of the language-independent bits of writing a compiler, while wasm is a format for delivering code to browsers, with an eye towards being a good target for languages like C and making use of the existing JIT compilers in modern browsers.

LLVM as a toolchain provides backends for many target machines, so as a compiler author you can just emit LLVM IR and (mostly)automatically be able to compile for x86, arm, mips, etc... And they have a wasm backend too, so the technologies are complementary -- you can use LLVM to compile to wasm. LLVM will do a fair bit of optimization too. The intent with LLVM is not to provide a portable binary distribution format, but to allow different compiler frontends to all share the same compiler backend logic.

By contrast, with WASM the assumption is that by the time it gets to the browser the ahead-of-time compiler has already done a fair bit of optimization, so what a wasm compiler has to do is much simpler.

WASM is also designed for space efficiency, since the code will be shipped over the network, and safety -- LLVM has a C-like notion of undefined behavior (which the optimizer makes use of), but this would be wildly inappropriate for WASM due to security (and portability) concerns.

harikb · 6 years ago
There are not comparable afaik. WASM is also more ambitious, along with WASI (system interface) creating a portable final executable (compare to JVM), whereas LLVM is only a set of intermediate language and tools.

When this transition period goes away, LLVM should hopefully compile to WASM binary as a target. The current path described in the video of WASM -> C -> clang -> llvm -> native-binary is a temporary workaround afaik.

Longwelwind · 6 years ago
I spent the last 2 years making an online adaptation of a board game. I chose Typescript mainly because I was comfortable enough in this language and I don't regret this choice.

Typescript is, for me, the right balance between the strictness required to manage a mid-size codebase, and the looseness necessary to be productive (I definitely don't want to manage low-level things like memory when coding the gameplay of the board game).

On top of that, if your project is open-source, using JS/TS makes it more likely that someone can contribute to the project, compared to Rust, which has a higher learning curve.

Being able to easily share code between the client and the server is a big bonus too. The article points that with WebAssembly, it's possible to do it with any language, but I'm not sure it's stable enough to be used yet.

I'm thinking of making a library similar to boardgame.io (because I think there are some parts that could be done better), and I'll most probably keep Typescript for it.

Curious to see how using Rust for this will play out!

v_pragma · 6 years ago
Keep in mind that WebAssembly is not a silver bullet for performance, and carefully crafted JS application (written in engine-friendly way) will perform roughly the same or even better than its WA equivalent. I've rewritten chunk of my math-intensive app in AssemblyScript half a year ago - it took me about a month to fight through all the compiler bugs, I used every optimization possible (used floats everywhere, disabled array boundary checks, disabled GC for 70% of classes) and still end up with a binary that is 30% slower than the original JS code. It was mostly AssemblyScript's GC, which was extremely slow (and probably still is), and with GC completely disabled (which is an unfair advantage for WA) performance was almost the same.
brabel · 6 years ago
You can't judge the performance of WASM solely based on experiments you made using AssemblyScript (a TypeScript subset that compiles directly to WASM). As WASM is meant to be a low level compiler target, a proper comparison would be with binaries produced by the Rust or C compilers that don't rely on a specific GC implementation.
v_pragma · 6 years ago
GC aside, I've inspected assembly code (.wast files) for top 10 hottest methods in my code, and it was pretty much perfect, Rust and C will probably end up with something similar. However, there was no performance improvements whatsoever, those methods performed similarly to their JS equivalents.

UPD: modern JS engines are extremely capable of optimizing stuff and they can probably come up with machine code similar to what Rust or C will produce given that you keep your code predictable and optimization-friendly.

maxgraey · 6 years ago
That's pretty interesting. Could you share you project?

There are benchmark which compare JavaScript and AssemblyScript: https://github.com/nischayv/as-benchmarkshttps://github.com/nischayv/as-benchmarks/issues/3#issuecomm...

benjamin-lee · 6 years ago
I'm not the OP but I can confirm in my own project, we found about a 10x performance gap between AssemblyScript and TypeScript. In essence, we're working on a rewrite of DNAVisualization.org[1][2], a serverless web tool for the interactive inspection of raw DNA sequences. We hoped that WASM would give us a performance boost but have been generally disappointed with both the performance and the amount of complexity involved in getting the tooling to work.

We did do a benchmark[3] and, unless we made an error (likely, given that all of us are new to WASM), found that JS was much faster for our simple algorithms. WASM had the approximate performance of our original pure Python implementation[4], so not great.

[1]: https://dnavisualization.org [2]: https://academic.oup.com/nar/article/47/W1/W20/5512090 [3]: https://github.com/Lab41/dnaviz/tree/benchmarks/benchmarks/a.... [4]: https://github.com/Lab41/squiggle

Deleted Comment

v_pragma · 6 years ago
Unfortunately, no, it's a commercial closed-source project. I profiled both JS and WA versions, the hottest methods took basically the same amount of time in both versions, except that WA build additionally spend ~25% of all time in __retain or something like that.