Live data from Hacker News

Programming language comparison by reimplementing the same transit data app

github.com

31–40 of 65 posts

Re: Programming language comparison by reimplementing the same transit data app

#31
post #5
post #4

Earlier quoted context omitted.

It's a shame, too, because until that point (when I was still just following the "getting started" docs and doing the first half of the app, which loads a CSV and parses it and stuff), I was actually really enjoying it! The type-magic style of development is so different from what I'm used to, I have periodic crises of conscience where I wonder if I've been doing programming wrong all these years, or if it's an examp…

And Yesod is one of the worst options in Haskell, at least as far as making me wonder why it's doing so much magic. It's very much trying to build a fully integrated framework instead of being composable Haskell. (To be fair, the underlying parts written to implement it are composable Haskell, and re-used by a lot of other web server projects.)

I think ‘worst’ is very subjective here. It certainly does aim to be an all-encompassing ‘framework’ — but this is hardly unusual amongst web libraries (not just for Haskell!), and I feel Yesod gets the job done pretty well. Of course, Haskell has many alternatives if you don’t like Yesod: amongst other libraries, there’s Servant [0], snap [1], scotty [2], and the lower-level wai [3] and warp [4] if you feel the need for that kind of control.

[0] https://hackage.haskell.org/package/servant

[1] https://hackage.haskell.org/package/snap

[2] https://hackage.haskell.org/package/scotty

[3] https://hackage.haskell.org/package/wai

[4] https://hackage.haskell.org/package/warp

Re: Programming language comparison by reimplementing the same transit data app

#32
> As for the language, C# is... all right, I guess. It kind of reminds me of Dart

That's right because Google's Dart (2010's) was heavily influenced by Microsoft's C# (2000's) which was heavily influenced by Sun's Java (1990's)

I've often wondered if would have been better if the companies had worked together to produce a standard VM language

Re: Programming language comparison by reimplementing the same transit data app

#33
This was fun to read through.

I would need to profile the code, but the startup time being bad for Deno seems like maybe a combination of the code in here being unoptimized:

https://github.com/denoland/deno_std/blob/0ce558fec1a1beeda3...

(Ex. Lots of temporaries)

And usage of the readFileSync+TextDecoder API instead of readTextFile (which is also a docs issue since it suggests the first one). It seems the code loads the 100MB into memory, then converts to another 100MB of utf8, then parses with that inefficient csv parser. The rust and go versions look to be doing stream/incremental processing instead.

Re: Programming language comparison by reimplementing the same transit data app

#34

According to the results, Go and Rust pretty much beat every other language. While Rust is the clear winner, it has a steep learning curve. When it comes to Rust vs Go, I always choose Go, because it still beats all the other languages and at the same time an extremely simple language to learn / read / write. This triplet has a greater weight in my books.

I've been learning Go recently and it's been such a pleasure, particularly for 2D gamedev (with ebitengine.org). I don't think I've gone from reading the spec to being able to read others' programs fluently as quickly as I was able to with Go. Plus it's so fast! Compilation times had me thinking it was interpreted when I first started playing around with it.

Re: Programming language comparison by reimplementing the same transit data app

#35
> It took me longer than I'd like to admit to figure out how to get a dang io.Reader, which is what the CSV parsing package takes.

In Go you want to start with the package examples. CSV has NewReader(). I had the same experience with Java... you know what a function takes, but where do you get one of those?

Re: Programming language comparison by reimplementing the same transit data app

#36

You mention Deno maybe not handling multiple cores “well”. I’m 99.9% sure Deno doesn’t handle multiple cores at all. Everything in the node ecosystem is one big asynchronous single-threaded event loop.

There are indeed threads in some cases. I believe Deno uses libuv, which means that certain calls (iirc the syscall for DNS resolution) are put into separate threads since there are no true non-blocking versions of them provided by the kernel.

Re: Programming language comparison by reimplementing the same transit data app

#37

How do you think Node.js would fare here, similar to Deno?

I’d like to see that, too. I’ve been able to get Node to match Go performance (roughly) when building SQLite-based applications by having all of the writes happen on one thread (passing the work to it via Node IPC), and doing all reads on read-only instances in the workers.

Node really craps the bed when you start pulling in libraries, though. And there are lots of performance surprises such as fetch being quite slow vs the original http client, etc.

Re: Programming language comparison by reimplementing the same transit data app

#38
post #20
post #3

Oh, hey, didn't expect to see this here. Thanks for submitting! I tried a few days ago but didn't really get any traction.[0] Since I submitted it, though, I posted it to /r/rust and got a lot of feedback. At the time, rust and dotnet were comparable and at the top of the list, with ~10k req/sec. Now rust is far and away the most performant at ~20k req/sec! I also was able to improve Go's performance 30% or so. Still…

The elixir implementation seems super slow. The first thing that jumps out to me is that we should be using streams instead of just reading the file. The second would be the `schedule_for_route` which should just be a GenServer lookup instead of reading from ets.

Agreed. I've seen significant performance improvements by using streaming with binary pattern-matching to parse files rather than loading them into memory and using String functions to get at the data.

These Elixir numbers seem suspect to me, based on my company's extensive benchmarking on many of these same languages. Elixir is somewhat slow at some tasks, but serving up web requests isn't one of them.

Re: Programming language comparison by reimplementing the same transit data app

#39
post #3

Oh, hey, didn't expect to see this here. Thanks for submitting! I tried a few days ago but didn't really get any traction.[0] Since I submitted it, though, I posted it to /r/rust and got a lot of feedback. At the time, rust and dotnet were comparable and at the top of the list, with ~10k req/sec. Now rust is far and away the most performant at ~20k req/sec! I also was able to improve Go's performance 30% or so. Still…

Regarding C#:

> The "billion dollar mistake" is important to me, and while C# has non-nullability sugar in its typesystem (i.e. with ? after a number of types), the type system wasn't as rigorous as I was maybe hoping.

I'm genuinely curious if you have any examples? Nullability checks may be bolted on, but once you enable them, they should consistently prevent you from dealing with any null values that you haven't explicitly allowed. And other than that, the only hole in the type system that I can think of is array covariance, which was unfortunately common at the time (Java had it also) as a way to skimp on generics, but which doesn't occur often today because using generic collections is much more common.

> At one point I had a bug because I did a stopWatch.Elapsed / 1000 by accident instead of stopWatch.ElapsedTicks / 1000. The former is a TimeSpan struct instead of a long like ElapsedTicks, so intuitively it feels like I shouldn't be able to divide it, though it did a best effort and did something to it, though I'm not quite sure what.

This particular one doesn't have anything to do with the type system per se, it's just the way TimeSpan itself works. I'm not sure why "intuitively it feels like I shouldn't be able to divide it", since there are fairly obvious definitions of arithmetic operations on spans and numbers - if T is 10 seconds, then surely T*2 is 20 seconds, and T/2 is 5 seconds? Which is exactly what TimeSpan does by overloading the corresponding operators:

https://learn.microsoft.com/en-us/dotnet/api/system.timespan...

Note that the type of (TimeSpan/double) is still TimeSpan, so the type system is still enforcing proper use - it wouldn't have let you assign it to an int or a double. But it looks like you were just printing it, which is legal for any type:

   Console.WriteLine($"loaded stop_times.txt in {watch.ElapsedMilliseconds} ms");
Post reply on HN