Hacker News new | past | comments | ask | show | jobs | submit login

I've been writing Go for 9+ years, but for the last 4 years, I had to write a lot of Dart (for Flutter). I consider these two languages to be on the opposite sides of the complexity stance. Dart tries to add and implement every feature possible, but Go is the opposite.

Two observations:

1) I'm spending a lot of time fighting multiple ways to init stuff in a class (i.e., declare the variable and set the value). Depending on the final/const/static/late prefix, there are multiple ways to init it in the constructor or factory or initState() method of Flutter's StatefulWidget, and god forbid you to refactor any of that – you'll be forced to rehaul all the initialization. Dart's getter feature (which makes functions look like variables) also adds confusion, especially with a new codebase. I constantly find it embarrassing how much time I need to spend on such a straightforward thing as variable/field initialization. I often find myself missing the simplicity of Go.

2) Compared to Go, Dart has all the juicy stuff like maps/streams/whatever for packing all in a single line. It's very tempting to use those for quickly creating singleliners with hard-to-understand complexity. Sometimes I even start feeling that I'm missing those in Go. But when I get to debugging those or, especially, junior developers looking at these write-only singleliners, with an array of ugly hacks like .firstWhereOrNull or optional '(orElse: () => null)' parameters, they are very confused, especially when cryptic null safety or type errors stops them. Rewriting those singleliners as a simple Go-style for loop is such a relief.




Tip about Dart : Don't use initState for stuff that doesn't directly concern UI (setting the hint of a text field, for example).

Most of my Flutter pages rely either on having very few things to do, or having a MyPageController object such that the parent creates a controller, initializes it however it likes and the child page's behavior is dependent on that controller. A typical example of this would be the parent being a page containing a list, and the user wanting to edit a list element. Create a controller, give it the element, and send the controller to a child page where the user does the editing. On return, the parent can look at the element or other variables/callbacks in the controller to decide what should change in the UI.

This also allows finely-controlled interactions between widgets without having to delete with InheritedWidget or the likes. Of course you should use a state management library with this, even though a lot of the time I don't.


Some people joke that state management in Flutter is like http mixers/routes in Go. But I think it's much worse :)

Granted, UI state handling is not an easy task, and it's not directly related to the topic of complexity of the languages. I had an article written a few years ago about a thought experiment of Flutter being implemented with Go. It's a bit naive, but still fun to think about. [1]

[1] https://divan.dev/posts/flutter_go/


I agree, Go’s simplicity is the best thing about it. I think the same thing about ranges, I think I end up typing the same number of characters - but spreading it over three lines makes it feel “longer” than a comprehension like “forEach(f)”. But then I write the range longhand, and it’s no big deal.

Speaking of initialisation though, I do wish Go had an idiomatic way to initialise struct fields to specific values. I don’t care about the lack of constructors; mostly, I just wish I could have bools initialise to true sometimes.


Sure, it's always a tradeoff. Yet my pet peeve is that people rarely talk about the social aspects of the programming language. It's called "language" for a reason. We express our thoughts using this language ("I intend this code to do such and such"), and we expect other people to be able to understand what we intended, and we want to make sure that they understand exactly as we want them to.

I judge languages on their ability to collectively construct mental maps in the brains of the developers who work on the same project. If they all read the same code, will they be able to understand the task and intent of that code without additional explanations? How cognitively hard would it be?

Gottfried Liebnitz was obsessed with finding a Universal Language, which was exactly about this – making communication clear and lacking misunderstanding. I feel like Dart (and most other languages) approach is the opposite of that. Creating multiple ways to express the same intent is a sure go way to introduce misunderstanding and fracture the speakers of that language into dialects and groups. Go's, on the other hand, is really good at making this "reconstructing mental map" part a joy.


I don't know Dart at all, but I used Java from version 1.0, and watched as it morphed and morphed again - from for-loops, to collections with iterators, then "upwards" to list and map comprehensions, closures, function pointers. My younger colleagues were writing code I could barely understand; having left that world several years ago, I still find idiomatic modern Java difficult to mentally map to intent, as you put it. The feature set is undisciplined.

So I completely agree with you. I think it's unfortunate that some people appear to mistake simplicity of construction with simplicity of thought. Go's ingenious simplicity - its elegance - is a virtue. Unfortunately it also reflects what Dijkstra said: "Why has elegance found so little following? ... Elegance has the disadvantage if that's what it is that hard work is needed to achieve it and a good education to appreciate it".


My experience with Go is quite the opposite. Python may be way slower to run, but it maps to my intent extremely well. In Go, every time you try to find an item in a slice, or convert a slice to a map for faster search, or whatever, one piece of intent turns into a whole paragraph of boilerplate or a completely ad-hoc helper function.

Reading Go feels like legalese.


initstate is an override of statefulwidget, its no different than any other frameworks lifecycle events and its a flutter thing, so its not really something you would confuse with a constructor or something. I can understand not knowing if you should create a normal constructor or a factory i guess, but getting confused about initstate is not a reason go is superior.


We should be optimizing for expensive experts’ ability to communicate concisely with each other. Keeping the power tools of syntax out of novice hands just deters them from developing expertise.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: