Which is really handy when shit's on fire and you need to find the error yesterday. You can just follow what happens instead of trying to figure out the cool tricks the original programmer put in with their super-expressive language.
Yes, the bug is on line 42, but it does two dozen things on the single line...
I think people often get burnt by bad abstractions in expressive languages, but it's not a problem of the language, but the author's unfamiliarity with the tools at their disposal.
If someone starts being clever with abstractions before understanding the fundamentals, it can lead to badly designed abstractions.
So I guess if there's less things to master, you can start designing good abstractions sooner.
So, in my experience, if we invest time to truly understand the tools at our disposal, expressive languages tend to be a great boon to comprehension and maintenance.
But yes, there's definitely been times early in my career where I abstracted before I understood, or had to deal with other bad abstractions
But, on a serious note, I agree with you. Go lacks a lot of power, especially in its type system, that causes a ton of problems (and downtime) that in other languages is trivial to prevent statically.
If you have to share a codebase with a large group of people with varying skill levels, limiting their ability to screw up can definitely be a feature, which a language can have or lack.
As always, it comes with tradeoffs. Would you rather have the ability to use good, expressive abstractions or remove the group’s ability to write bad ones? It probably depends on your situation and goals.
P1: The type and its method vtable
P2: The value
Once I understood that I could intuit how a nil Foo was not a nil Bar and not an untyped nil either
A mate of mine did Comp Sci back in uni when First Years were taught Turbo Pascal showed me some, when I was still doing stuff in ZX Spectrum BASIC and Z80 assembler in high school. It was immediately clear what was going on, even if the syntax was a bit unfamiliar.
By contrast I've had to sit and pick apart things with strings and strings of ternary operators in the same expression, as part of case structures that relied on fallthrough, because someone wanted to show how clever they were.
My Pascal-using mate called stuff like that "Yngwie Malmsteen Programming". It's a phrase that's stuck with me, over 30 years later.
Don't do that "WEEDLYWEEDLYWEEDLY" shit. You're just showing off.
willem-dafoe-head-tap.gif
There is, perhaps, some segment of the developer community who believe that they are infallible and don't need to write tests, but then have the type system exclaim their preconceived notions are wrong, and then come to love the type system for steering them in a better direction, while still remaining oblivious to all the things the incomplete type system is unable to statically assert. But that's a rather bizarre place to be.
But it is hardly ever the weak type system that is at fault, just good use of a stronger type system could have prevented the issue.
Once you start to make "invalid states unpresentable" and enforcing those states at the edges of your type system suddenly a lot of bizarre errors don't happen anymore.
On your own time.
When you're writing code for work, stuff that other people have to eventually read and understand, you be as boring as possible. Skip all the tricks and make code readable, not cute. Someone might have to understand and fix it at 3 in the morning while everything is on fire.
> Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
Go is simple just like assembly is simple.
> The Map type is specialized. Most code should use a plain Go map instead, with separate locking or coordination, for better type safety and to make it easier to maintain other invariants along with the map content.
The documentation basically says that it's optimized for some cases that wouldn't affect the complaint above.
But doesn't change the tests you need to write, and those tests are going to incidentally cover anything the type system is also going to catch, so the type system isn't going to somehow make your software more reliable.
A much more expressive type system can get you there, but you won't find that in any language anyone actually uses on a normal basis.
What I wanted to point towards with my earlier comment is that sync.Map doesn't use resource based mutexes, it uses one mutex for everything which will always be the slowest case.
There's no real borrowing concept in Go, as there would be in Rust for that case, and if you argue that simplicity should be preferred then normal map[] should be threadsafe by default, which, in return, likely will require compile time expansion because of generics.
The core value of Go's "we want simplicity" approach always feels like it's a facade, because there is so many exceptions and footguns along the way. These footguns almost always were conscious decisions where they could have made a decision to break legacy behavior for better simplicity but decided that this is not what they want, which is weird as it's not fitting the initial language design promise.
Anyway his argument was "but the code should be obvious! You shouldn't need comments to explain what the code does!"
Yes Robert, but you need comments to explain what the code expects to do stuff to, and why you want that.
Turns out that removing the "Development Manager" as he styled himself's write access to the Subversion repository causes ripples in the fabric of reality right up to the C suite, but I could back my decision up with solid evidence that he was causing more problems than he was solving.