Hacker News new | ask | show | jobs
by strongpigeon 1228 days ago
I’m not sure why the Dart hate honestly. It’s a pretty solid language in my opinion and I like the direction they’re taking (non-nullable, record, pattern matching). The ecosystem is weak for sure, but that’s not a gripe on the language itself.

I’m curious what do you dislike about it apart from semi-colons and the constructor syntax (which seem fine to me?).

4 comments

Okay I guess I should provide more details. Constructor syntax fine? Jesus how come you can't use the constructor parameters as the default values but have to either resort to using `late` or that weird `: {}` after constructor like in C++, can't remember how it was. I just added `late` and thought whatever. Probably there are nuances I've missed but how come you had to reinvent that - thought it should be intuitive from the get-go.

While stating itself to be statically typed you can also shoot yourself in the foot by simply using `as Type`, similar to TypeScript. Because that just assigns it to a type and doesn't cast it like you do it in say Rust.

The extreme use of classes with `abstract class` and whatnot feels kinda 90's to me, just a lot of abstractions and for what? Just feels unnecessarily complicated for something seemingly simple.

Maybe it's just little too enterprisey for my taste. Maybe that's it. I'm glad they are taking steps to improve it, I think making it more functional would help it. Even just to distinguish it from the other OOP languages.

And how come simple state management seemed so difficult as well? I tried using my tried and true MobX which is implemented for Dart as well but was disappointed in its complexity and the fact it requires you to run a code generator to wrap your classes with observables. What? Insane.

> Jesus how come you can't use the constructor parameters as the default values but have to either resort to using `late` or that weird `: {}` after constructor like in C++, can't remember how it was.

This is a really good question. The reason is that it ensures that you can never see a field before it's initialized. In Java, you might think that you'll never observe a final field before it's been initialized but not so! In the constructor, you can call a method on `this` even before all fields have been definitely initialized. Inside that method (which might be overridden!), you can then read the field. It will be default initialized.

This means every time you create an object in Java, some extra code is running to default initialize all the fields just in case they get read before they're actually initialized. (I assume in some cases the compiler can prove it's not needed and eliminate it, but not in the general case).

It also means that the type system can't rely on fields being initialized for static safety. That in turn means that the compiler can't optimize based on that fact.

In Dart with the constructor initialization syntax, it's not syntactically possible to access any state on a new instance until after every single one of its initializers has run. That means that, in concert with null safety, if you have a non-nullable field, the compiler knows it will never ever be null and then can generate smaller, faster code based on that guarantee.

I agree the constructor initializer syntax is annoying and I wish we had something better, but it's there for a reason. Also, in practice, you often use `this.` or `super.` on the constructor parameters and avoid the initializers entirely.

> While stating itself to be statically typed you can also shoot yourself in the foot by simply using `as Type`, similar to TypeScript. Because that just assigns it to a type and doesn't cast it like you do it in say Rust.

An "as" expression is fully sound and will throw a runtime exception if the value isn't a valid instance of the cast type.

> The extreme use of classes with `abstract class` and whatnot feels kinda 90's to me, just a lot of abstractions and for what?

You don't have to use classes if you don't want to. You can define functions and variables all at the top level and write in a completely procedural or functional style if that's your jam. Some of the Dart packages I maintain are mostly functions.

> I think making it more functional would help it.

We're getting there. It's always had anonymous functions, closures, and plenty of higher-order functions in the collection API. We're adding pattern mataching and exhaustiveness checking now which should let you program in an algebraic datatype style.

Thanks for the detailed write up!
Exactly, after JVM world I'm especially loving reified generics. Being able to access type information on generics at runtime is very helpful. Plus developer experience for working with DartVM and Flutter is crazy good.
It gets the hate because it comes from Google and it was originally marketed as a JavaScript replacement.

Additionally, the first unoptimized compiler resulted in "hello world" having a gargantuan amount of JavaScript code. That left the language with a hard to shake stigma.

To be fair, around a decade ago, Chrome wanted to add a Dart VM (Dartium) to which many vehemently protested, and I agree it would have been a bad move to have a browser essentially have its own language rather than JS, forcing other browsers to adopt it. From there though, we got a much better cross browser standards-based solution in the form of WASM, which is even more powerful since languages other than Dart could be used. This controversy is where I first saw the Dart hate, but it has grown into a nice language since, especially with Dart 3+ which introduces, records, patterns, and exhaustive pattern matching.
Oh yeah I do remember that. I can see how some of that stigma lingers.
Last I checked you can’t even have enums with payloads/ associated values.

Garbage language

You can since 2.17. Not sure if you’re being sarcastic about this making it a garbage language.
Is that not just string/int/basic types? Last time I looked it was and it was a complete joke.

I want to define

enum UserState {

case loggedOut

case loggedIn(user: User)

}

where User is itself a struct with props like email/id/Etc

Then, I want to be able to switch on said enum, so that my code can take a UserSession state stream and switch over each case to react accordingly. This gives me compiler - enforced case handling completeness everywhere my enum is consumed which is amazing for code reliability.

This is trivial in Swift or any real language, but with Dart and the stupid flutter bloc model you seemingly can’t do this and end up with these huge if cast chains to send messages.

If I’m wrong and things have changed for the better please let me know, it was my biggest issue with dart/flutter

See my sibling comment. That appears to only work with basic types like strings/ints?

I need to add complex objects, sometimes multiple. Swift lets you do this easily.

No, you can add as many fields of whatever types you want to an enum in Dart.