I think a much bigger downside would be its effect on the price of your insurance. I can't speak for any other country but in the UK insurers have a reputation for being petty about modifications. Even something as minor as a DIY heated seat switch would have to be declared to your insurer who could refuse to cover you or charge a silly premium for cover.
That's a U(k) problem not a me problem. Here people put their cheap base model pick up truck on the highest, cheapest, Chinese lift kit that money can buy with no real effect on the price of their premium. You only pay more when you want to insure the cost of the replacement of your modified parts, which very few people are going to bother doing.
> For the opposite word, "expensive", it all depends on the word before it: "as expensive" or "more expensive".
Frustratingly, I find this isn't always true in practice. Lots of people use "x times as y" and "x times more y" interchangeably. To avoid ambiguity I try to only use the former in any context where precision is useful.
> gojq does not keep the order of object keys. I understand this might cause problems for some scripts but basically, we should not rely on the order of object keys. Due to this limitation, gojq does not have keys_unsorted function and --sort-keys (-S) option. I would implement when ordered map is implemented in the standard library of Go but I'm less motivated.
And later in the same file:
gojq does not support some functions intentionally;
<snip>
--sort-keys, -S (sorts by default because map[string]interface{} does not keep the order),
> "gojq does not keep the order of object keys" is a bit disappointing
with
> “I bet it's an artifact of Go having a randomized iteration order over maps. Getting a deterministic ordering requires extra work.”
But deterministic iteration order doesn’t imply that the order of keys is kept the same. There are map implementations that keep iteration follow insertion order, but the canonical map does not guarantee that. https://en.wikipedia.org/wiki/Associative_array#Hash_table_i...:
“The most frequently used general purpose implementation of an associative array is with a hash table: an array combined with a hash function that separates each key into a separate "bucket" of the array“
Such implementations iterate over maps in order of hash value (and hash collisions may or may not follow (reverse) insertion order)
I don't think the distinction you're trying to make is helpful here if I've understood you correctly. A good faith interpretation of haastad's comment would be that they were thinking of "insertion order" when they said "a deterministic ordering". Even if we were being pedantic, their comment is still correct - for iteration order to be the same as input order then deterministic iteration ordering isn't sufficient (this seems to be the point you're making) but it is necessary.
Their first sentence:
> I bet it's an artifact of Go having a randomized iteration order over maps
is correct per Gojq's author [0]:
> gojq cannot implement keys_unsorted function because it uses map[string]interface{} to represent JSON object so it does not keep the order. Currently there is no plan to implement unordered map so I do not implement this function.
It would of course be possible to work around this limitation of Go's built-in map type but that's not the point. The author makes it clear that this limitation is the cause for Gojq's behaviour.
What you're describing is named the "curb cut effect" [0].
> The curb cut effect is the phenomenon of disability-friendly features being used and appreciated by a larger group than the people they were designed for. For example, many hearing people use closed captioning.
> It has been so energetically hyped. Real standards don't have to be promoted
I find this interesting because it's the first heuristic I use to judge anything new, technical or otherwise (e.g. TV shows or games). Did someone pay to put it in front of me?
It turns out to be a mostly true assumption that you'll hear about good things organically.
That's true when it comes to art, but I have almost the opposite feeling when it comes to things that require a network effect to be worth investing in
I'll readily judge a new programming language or library based on the quality of its presentation, because if no thought is being given to presentation, I can tell already that it's not going to get much traction. And if a PL doesn't get much traction, its ecosystem and even its long-term development will likely suffer.
Although- that's really just a minimum bar, and I agree with the author that Java went way way beyond that, and had more money tied up in that than felt warranted, so I probably would have had the same feelings
What you say about traction is a good point. I think "will it be successful?" is a very different question to "will I like it?".
At one end of the scale for me is Rust. I discovered it through organic hype and I like the language but it's not successful enough for me to have found a job writing Rust.
At the other end is TikTok. I saw many ads for it before anyone I know ever talked about it. It's massively successful but it doesn't appeal to me in the slightest.
The reflog is very helpful but I don't think it counts as an "undo". Some operations (like git add or git push) won't show up in the reflog.
Even the operations which do show will often require more thought to undo than a hypothetical "git undo" would. I know how to use the reflog but I often go out of my way to avoid it because "git branch tmp HEAD; git $POSSIBLE_MISTAKE; git reset ---hard tmp; git branch -D tmp" requires less effort than deciphering the reflog's output.
Git reflog absolutely counts as the first step of undo for several workflows, but you’re right there are other commands needed for some kinds of undo.
Undoing a push does require a different set of commands, but my point, to the question @amelius asked, is that you can undo both push and add, and whatever other mistake you’re thinking of, difficult or not.
> Do I need to know how a gearbox works to drive stick shift?
No, but it helps. If I treat my car's powertrain as a black box then it won't be intuitive that:
* I shouldn't slip the clutch to hold my car on an incline.
* Blipping the throttle gives me smoother downshifts.
* Double clutching lets me shift from 2nd to 1st while rolling.
* I can use the engine to slow my descent on longer hills and avoid brake fade
* I should park the car in gear for safety
* etc.
Whether it's better for a given person to memorise that list of facts or to understand the concepts behind them would depend on how much they drive. As a developer I've found it helpful to gain an understanding of the tools I use daily beyond "here's the commands to copy/paste when you want to do xyz".
It may not have sounded like it but I'm actually going to agree with some of this. We might be on a different part of the gradient so to speak. Maybe you can find a good analogy but at least from my point of view the gearbox analogy is falling short now and we'd need a different one or look at git commands one by one :)
Like you say, you can just remember those things. In fact 4 out of those 6 were taught in driving school and you had to remember them. One I only learned because trucks still needed that (double clutching while shifting - not just your case, just in general) but cars didn't when I learned. I personally don't like copy and pasting commands like that but I see a lot of people doing that even for stuff that should be second nature because you need it all the time. I think - to stay in the analogy - for me this is the difference between knowing that I should engine break and how to do it when I want to slow down vs. having a piece of paper in the glove compartment that I pull out and check for what to do and how every time I approach a red light ;)
I'm also someone that likes to get an understanding of the things that I use and do every day. The thing is that there are so many things we use and do all the time that I think (almost) everyone just has to keep a certain level of abstraction away from many things, because there are just so many rabbit holes out there and it's not beneficial for most people to have explored every single rabbit hole all the way to the end (the 'gradient'). Git commit graphs are a DAG and lots of cool things can be done with DAGs, most of which I totally forgot about since I learned about and enjoyed them in university and have never needed them again at that level. It's good to know they exist and be able to dig in when needed/wanted.
You're absolutely right, there are about a million and one rabbit holes you can go down if you _really_ want to understand the tools you use but in the vast majority of those cases you're better off relying on a higher level abstraction.
The interesting part to me of your analogy is that it can demonstrate how having an understanding of what's going on under your layer of abstraction allows you to generalise.
To wring the last bit of life out of the gearbox analogy: if you tell a mechanically inclined driver that blipping the throttle will make their downshifts smoother, they'd hopefully understand how rev matching can be generalised to upshifts too. If you tell a "black box" driver then they probably wouldn't be able to do the same. Of course, the analogy falls apart a bit because understanding rev-matched upshifts isn't particularly useful :)
I've forgotten most of the "advanced" git knowledge I ever learned but I get a lot of value out of the (admittedly not very advanced) understanding that, as you said, commits are a DAG and that branches are just named pointers to nodes on the DAG. That understanding lets me generalise to, for example, backing up a branch (with git branch/tag) before doing a tricky rebase so I can restore it (with git reset --hard) if I need to undo.
I agree that exploring every rabbit hole to the end isn't beneficial - understanding the DAG is typically the only "advanced" git knowledge I need and I've only very rarely had to peel back more layers. I think this:
> It's good to know they exist and be able to dig in when needed/wanted.
is a good way of putting it. My ideal low-level understanding of most tools is knowing just enough that I know what to search for if I ever need to go deeper.
> That understanding lets me generalise to, for example, backing up a branch (with git branch/tag) before doing a tricky rebase so I can restore it (with git reset --hard) if I need to undo.
You can also do `git reflog` on branches to see what they used to point to :)
It's interesting that you find Go to be Rust-adjacent. Setting aside the USPs of each language (goroutines and borrow checker respectively) and just speaking about the general experience of writing code, I find Go painful for all the reasons that I find Rust pleasant.
The best summary I can give of Rust is that it was designed by people who learned from the mistakes of the programming languages that came before it.
The best summary I can give of Go is to quote Rob Pike's response [0] to a request for syntax highlighting in the Go playground:
> Syntax highlighting is juvenile. When I was a child, I was taught
arithmetic using colored rods
(http://en.wikipedia.org/wiki/Cuisenaire_rods). I grew up and today I
use monochromatic numerals.
It's like my favorite John Quincy Adams quote, "It is what it is, and it ain't what it ain't" Different strokes for different folks you know? At the end of the day if folks code at all, and it makes them happy, that's a good thing.
It is mostly an example of the mindset that I think GP is trying to illustrate.
Go has nil where Rust has Option.
Go has weird not-quite-tuple returns & if err != nil where Rust has Result.
Go has no real enum concept, where rust has its powerful enums and matching constructs.
Go has generics, but only after a decade of pressure from users (and even then, they are much much less useful than Rust's type system).
I like Go and I feel very productive in it, but its commitment to simplicity is dogmatic in many ways and it very much is missing milestone advancements in PLs from the past several decades. It could easily have been made in the 90s.
I would love a language that combined the best aspects of Go and F#: expressive, great type system, fast compilation, native binaries, opinionated formatter, excellent concurrency, comprehensive standard library, consistent documentation, etc.
Throw in great compile to JS capabilities with small bundle sizes and the ability to map Typescript typings into the language so you can seamlessly consume well typed libraries, and man. Killer language, right there.
I feel like Go was built with primary design considerations that are often not considered publicly and often at odds with what programmers want out of a language. I saw one of the first public talks from the creators at Google I/O and they stressed two things: compilation speed and new developers coming up to speed quickly. From what they said, Google had a few C++ projects with multi-hour compilation times that, when profiled, showed about 90% of the time was spent reading header files. So a core Go philosophy was single-pass compilation to cut down compile times as much as possible. Similarly they stressed that the focus on simplicity meant there wasn’t as much variation in style of Go code and new programmers—even those unfamiliar with Go—could quickly come up to speed and contribute to a project.
Viewed through this lens, the resistance on the part of the creators to changes that compromise these values even a little bit makes sense. Generics take time to get used to and any code base that makes extensive use of them will take longer to get up to speed in, even if it enables you to move faster later on.
That talk has really shaped how I look at Go. I think it solves problems that Google has (really large projects built by teams that have a ton of turnover) really well. But as with a lot of things that emerge from Google, it’s a solution to a problem that not too many other companies face. The ones that do will get an awesome tool that’s proven to work. But the ones for whom it’s 90% of what they need are going to get a lot of pushback getting that last 10% accepted because it already does almost exactly what Google needs it to do and any departure from that will be, in their minds, counterproductive.
I agree, I've mostly made peace with what Go is and I still enjoy using it.
It just tantalizes me because of how close it is to my ideal general-purpose programming language. There is a large middle ground between the minutes-long compile times of Rust and the seconds-long compile times of Go.
It doesn't, primarily the way I saw the discussion heading was (warning: strawmen ahead):
> "Go is a good alternative to Rust because it is easy to write performant, concurrent code"
> "Go is not very comparable to Rust. I won't describe why, here's a quote by Rob Pike and I'll strongly imply it's because its creators deliberately avoided complexity, even where useful."
> "You did not explicitly criticize anything about Go, therefore it must not have flaws"
Then I came in and described exactly where I feel Go ignores the state of the art in PLs.
> But what does any of that have to do with (Rust-shaped vomit)
Go doesn't need all those type system gymnastics because it does not have the problem of the borrow checker to deal with and doesn't promise to avoid segfaults for you.
It is a serialization of relative lifetimes, basically. Whenever you write code in any language that doesn't have a GC, you either have to maintain a mental map like this to avoid bugs, or you make the language do it for you like Rust does.
Yeah I don't mean to criticize Go's generics for being less featureful given how late they were introduced, but they do currently prevent me from building any kind of mapping/filtering/pipeline style code because of their limitations (no generic type parameters on methods). A Go implementation of Result or Option could paper over the lack of sum types if we only had that.
The more I think about it, what I really want is something with the ML feeling of Rust, but in the space that Go occupies (good performance GC languages). Go frustrates me because it nails the runtime and tooling side of things but falls far short of it in the other ways I mentioned.
There's no shortage of good-perf languages with a GC: F# would be one prominent example that sounds very similar to what you describe.
The usual objection is that it requires a .NET runtime, whereas Go produces a single self-contained executable. But .NET can produce self-contained executables these days.
Yes, .NET can produce binary executables, but is it a common practice? I’m asking because I think the ecosystem matters a lot. If it’s a common practice, then it’s more tested and more stable and you get more tools and documentation.
It's a relatively recent feature, at least the "pure" implementation (what they had before was, essentially, a self-extracting binary), so it's still gaining popularity. But seems to be fairly common with containers.
As the sibling commentor said, syntax highlighting is only one example meant to illustrate Go's sometimes unnecessarily frustrating design. In case it wasn't clear, the example wasn't that Rob Pike doesn't like syntax highlighting. The example was that Go's playground doesn't have syntax highlighting (even as an option) for a reason as arbitrary as "because I said so".
That is why I find Rust and Go to be dissimilar. Rust is a language full of good ideas, almost all of which didn't originate in Rust. Go feels like it was designed with a very specific brief - "we want C but with GC and easy concurrency" - but whose designers otherwise had an NIH syndrome-like aversion to good ideas and common sense.
I don't agree with your framing. You are stating a 'moral' proposition, i.e. Rust == Good Ideas AND Go == Bad Ideas, and then applying the 'moral' position to the language as a whole. So you end up saying, in brief (and acknowledging that I do not think you are actually making a moral claim about the qualities of these languages) you are saying Rust is Good, Go is Bad and therefore they are dissimilar. I don't think the reasoning your putting forward actually says anything about the language and there similarity/dissimilarity.
I am not saying that Go and Rust are similar or not. I don't really agree with GP's comment where Go should be in the running for a Rust-with-GC/slightly-higher-level-Rust, but the frankly dismissive Rust Good therefore not similar to Go Bad is not justified. Although the conclusion regarding similarity is probably correct.
Also, this is a little off topic, but I have seen multiple people say that Go 'was designed with a very specific brief - "we want C but with GC and easy concurrency"' and then go on to complain about the lack of things like generics, destructuring match syntax, functional concepts, etc. But, all of those discussion, including your comment, start out with what seems to be an acknowledgement that Go's design had a very specific target. I agree that Go is basically the fulfillment of the brief you gave, i.e. C with GC and easy concurrency. So, when the target is C with two unique things, why does everyone then seem confused that Go doesn't have all of these extra 'good ideas and common sense'.
I'm not trying to turn this into a thread on Go's merits or lack thereof. I just don't understand why so many people seem to think that Go somehow didn't do exactly what it set out to do. You don't have to think what they decided to design was a worthwhile language, but to expect a lion to be a shark, or an apple be a steak, is just illogical.
I appreciate your comment. My intention wasn't "Go is dissimilar because it's bad and Rust is good" but I can see why you'd think that. I'll attempt to clarify.
The reason I like and recommend Rust is the number of decisions it gets right which are completely orthogonal to the borrow checker. It's clear that a lot of thought was put into the unexciting parts of the language. That's why I like using it even though I don't particularly need the borrow checker and I'd be happy with GC. Some examples off the top of my head:
- Expression-oriented nature makes code easy to write and nice to read
- Compilation errors are as clear and helpful as possible
- Comprehensive yet skimmable API documentation
In short, Rust is a nice language outside of the borrow checker.
A lot of the things which strike me as nice about Rust can't be said about Go.
For that reason I think Go is a surprising suggestion for someone who likes Rust but doesn't care about ownership and lifetimes.
There are a number of minor but valid frustrations I encounter when writing Go which are completely orthogonal to the brief of "C but with GC and easy concurrency". I'd understand if these problems were a result of the language's goals but often they seem to exist for no particular reason. In that regard I think Go is quite dissimilar to Rust.
You’re comment make your point very well. Honestly, so did the first comment. Sometimes I find myself so tired of just lurking and reading HN that I just text dump some comment onto a totally valid parent comment.
Cheaper economy vehicles will use metallic brake pads that emit lots of dust. More expensive luxury vehicles (SUVs and trucks) use premium ceramic pads that wear much less per mile. EVs and hybrids add regen and don't need brakes to stop unless it's under emergency braking. It's absolutely not apples to apples, and people need to understand that fact.