Hacker News new | past | comments | ask | show | jobs | submit login
Green vs. Brown Programming Languages (earthly.dev)
438 points by muglug on April 22, 2021 | hide | past | favorite | 486 comments



I think there's a lot of truth to this, but I'm going to make an additional suggestion that I'll readily admit is biased by my own feelings:

I think Go is in a honeymoon phase and people will hate it in 10 years; I think Rust will continue to be liked even when it's a legacy language (perhaps no language can continue being loved once it becomes "brown", but I think Rust will be a lot less dreaded than others).

Go, like Ruby (mentioned at the end of the article), is optimized for building. You can do things quickly and easily with minimal ceremony. Some people love that. But that's exactly the trait that's starting to weigh on Ruby, and it's exactly the trait that has put PHP and Perl in the "dread" category over time (remember when people were in love with those?).

Rust on the other hand is optimized for maintaining (it's right there in the name: software should be allowed to become old and "collect rust"). Rust APIs are very hard to misuse, everything is constrained and specified very explicitly. Documentation and testing live inline with your code. You know exactly what a piece of code can and can't do - you even know whether it's allowed to mutate an object you're passing it. And of course certain mistakes are impossible to make at all without (again, explicitly) dipping into unsafe { }.

This kind of forethought is what makes a language that survives the honeymoon phase.


> Rust on the other hand is optimized for maintaining (it's right there in the name: software should be allowed to become old and "collect rust"). Rust APIs are very hard to misuse, everything is constrained and specified very explicitly. Documentation and testing live inline with your code. You know exactly what a piece of code can and can't do - you even know whether it's allowed to mutate an object you're passing it. And of course certain mistakes are impossible to make at all without (again, explicitly) dipping into unsafe { }.

A language that is touted as "difficult to learn" and "difficult to onboard" is by definition not built for maintaining. You could maybe make the argument that the guarantees provided by the language and compiler reduce the maintenance burden of software built in Rust, but I don't even really think that statement has been tested (via Rust being so young).

It is tiresome the frequency that legitimate language discussions for some reason turn into Rust vs. Go trash talking. It is almost certain that in 10 years, both will be used more than they are now by several x's. I think pretending you can predict what'll happen with either (and the industry) over that time is pretty silly. There will be legacy apps that people hate working with in all programming languages, and there's nothing that can save you.


My intention wasn't to trash-talk, and I admitted my bias up front. I'm just speculating, and I think that speculation is legitimate and relevant to the subject at hand.

It's my belief that whatever difficulty there is around onboarding people into Rust (setting aside the question of exactly how much of a problem that actually is or isn't) is "constant", where the difficulty of onboarding people into a legacy codebase is, shall we say, "polynomial" over time. Rust adds some constant overhead in exchange for reducing that polynomial growth, and my belief is that at some point the larger polynomials outpace it, ending up with more total difficulty for newcomers to a given legacy codebase. Of course time will tell.


> constant vs polynomial

This is an interesting way to look at it, but I actually think this perspective favors Go considering that there is less variety across Go projects than other ecosystems, including Rust. Of course no programming language can hold constant the business domain, but there are things like which “error handling framework”, “for loops vs iterators”, “sync vs async”, “prefer owned vs borrowed by default”, etc that apply to Rust and not to Go. And of course, Rust lets you build some gnarly abstractions which simply don’t exist in Go.

Go gives you less choice, and thus projects are more similar, and thus I suspect legacy Go code adds will be easier to maintain.

Of course this property may not endure once Go acquires generics.

It should be said that I’m a big fan of both languages, and I am especially enthusiastic about Rust in that it fits my compulsion to have code that is both very abstract and very performant.


> Go gives you less choice, and thus projects are more similar, and thus I suspect legacy Go code adds will be easier to maintain.

Side note, Go gives you less tools - but not often less choice. Eg if you need to iterate and map, you still need to iterate and map. Go didn't change your application needs simply because it inhibited your ability to execute. Instead, you do what you need despite Go. Which often amounts to repeated functions, loops of loops, functions in loops to use defers, etcetc - you reinvent wheels. Go didn't reduce the application complexity, it just gave you less tools to solve it.

While some argue less tools is easier. I argue less tools often results in poor, messy abstractions. Those are traits that fight maintenance more than ease it, in my mind.

By the end of my Go tour, i was tired and wanted off the simplicity ride. The language was a burden, to me.


Ultimately you’re expressing an anti-simplicity sentiment, which is well aligned with the parent post. Clever abstractions may appear to reduce the “burden”, but they are often fashionable and add cognitive overhead. Go does indeed often force you to do things the “dumb” way (see your own examples) but the thesis is that this is easier to understand and maintain over time.


> Ultimately you’re expressing an anti-simplicity sentiment

I disagree. First, making a language simple doesn’t make programs simpler, and often does the opposite.

I’m also not sure I buy the idea that Go is actually simple. It lacks a lot of features, but that’s not the same as being simple. I mean, it supports runtime reflection, which seems more complicated than features like traits or generics. And code using reflection is never simple.


I'm sure somebody said something like that when all those kids started to the clever abstractions that were functions instead of doing things manually in assembly.

Simplicity!


This is just vapid snark. Of course some abstraction is helpful, but there's also a point at which abstraction impedes understanding. Ergo, we're debating where the "sweet spot" is. Note also that we can say "Go is the sweet spot for most applications" while also acknowledging that it makes certain kinds of programming difficult (e.g., writing a compiler). It's okay to recognize tradeoffs; there's no need to oversimplify or otherwise engage dogmatically.


Some developers don't want to use the ternary operator because it's "too complex".

I believe there's a middle ground to be found where further abstractions add complexity rather than reduce it. Where that middle ground is, I don't know.


That’s a strange definition of complexity. I can see people avoiding the ternary operator because the syntax is hard to read, but it’s no more complex than `if`.


Exactly, people advocate that there are those shipping stuff in Go, naturally there is the case.

Anyone that had to work with Assembly in production was happy to have any kind of high level language to start with.


> error handling framework

Not sure what's meant by this; Rust has a standardized Result type, with dedicated syntax for early-returning errors and type checks that make sure you handle them (or at least explicitly ignore them). Go, on the other hand, has a shaky error story and from what I've heard it's a constant problem due to enforcement-by-convention.

> prefer owned vs borrowed by default

Not really sure what this means either... the owner of a value generally falls out naturally from how you're trying to use it. It's not really an either/or option. It needs to live where it will be around long enough for everything that's done with it, and everything other than the owner should get a reference to it. Maybe you're talking about passing by reference vs implementing Copy? If so, that's mostly a performance concern.

> Of course this property may not endure once Go acquires generics

Yeah- one of the few things I like about Go is that it doesn't have generics (yet). I've seen generics make TypeScript codebases impenetrable, and I think there's a decent case to be made for not having them at all.


> Not sure what's meant by this; Rust has a standardized Result type, with dedicated syntax for early-returning errors and type checks that make sure you handle them (or at least explicitly ignore them). Go, on the other hand, has a shaky error story and from what I've heard it's a constant problem due to enforcement-by-convention.

You may not like Go's convention (indeed, I don't love it although I think it works fine in practice), but the only error handling mechanism in Go is `if err != nil { ... }`. On the other hand Rust has many. This is not incompatible with your observation of "a standardized Result type". Here is a survey of the error handling landscape circa 2019: https://blog.yoshuawuyts.com/error-handling-survey/

> Not really sure what this means either... the owner of a value generally falls out naturally from how you're trying to use it. It's not really an either/or option

Or you have code which clones gratuitously out of convenience, often because some API unnecessarily asks for ownership of its arguments. Cloning is often just easier than battling the borrow checker, so in the real world with its deadlines, we tend to see a lot of clones because it's more convenient and performance is rarely a concern.

> I've seen generics make TypeScript codebases impenetrable, and I think there's a decent case to be made for not having them at all.

In fairness to TypeScript, I suspect much of this 'impenetrability' is because type annotations were added to existing JavaScript. I suspect the gratuitously complex types were already present in the original JavaScript, but the type annotations brought the pain to the surface. Similarly, I suspect TypeScript has a massive amount of developers who have only ever developed in JavaScript, many of whom are trying to shoehorn their bad JS habits into a statically typed language. You see this in other statically typed languages as well, but never on a scale that leaves a mark on the overall ecosystem.

That said, I think everyone should learn pre-generics Go if only to experience the value of an ecosystem that doesn't value egregious abstraction (again, I say this as someone who personally values egregious abstraction). And no, I don't think Java 1.0 counts (wherein people tried to shoehorn everything into implementation inheritance rather than generics).


> You may not like Go's convention (indeed, I don't love it although I think it works fine in practice), but the only error handling mechanism in Go is `if err != nil { ... }`. On the other hand Rust has many. This is not incompatible with your observation of "a standardized Result type". Here is a survey of the error handling landscape circa 2019: https://blog.yoshuawuyts.com/error-handling-survey/

By this definition, Go has many too. Go has lots of libraries to wrap error types, combine errors, preserve error data, etcetc.

Errors are one of the more similar things between Rust and Go, honestly.


That’s a fair point. I forgot about the various errors packages in Go. I’ve been writing more Rust lately.


> Here is a survey of the error handling landscape circa 2019

All of this is helper functions built on the same identical core that your parent was talking about.

Not that that isn't its own kind of thing, but I think that the problems are different than "standard" vs "not standard"; this problem is only possible because there is a standard, and they all interoperate well with each other.


Indeed, Rust has a very well thought-out core which enables variability (read: "complexity") of all kinds. Variability is a fine thing, but it is at odds with onboarding users from one project to another. I wasn't trying to overstate error handling in particular--I mentioned it briefly in a longer list of examples which in-aggregate affect one's ability to onboard to a new project. I also don't mean to convey that going between Rust projects is harder than in other languages on average--I don't think this is the case at all, only moreso than Go in particular.


> My intention wasn't to trash-talk, and I admitted my bias up front.

I apologize if my statement came off aggressive - I wasn't necessarily trying to say that you're shit talking specifically, just that it seems like lots of/most programming language discussions on HN devolve into some form of "Rust Good Go Bad" or "Go Good Rust Bad", which I think is usually just inflammatory.

Your prediction is 100% bias-based. There are equal (probably more) developers that would say the same thing you said, but with Go being the language that sticks and Rust being the language that's hated. The bias is the entire answer. An unbiased answer is "Who knows" and "Probably both will be loved and hated".


> Your prediction is 100% bias-based. There are equal (probably more) developers that would say the same thing you said, but with Go being the language that sticks and Rust being the language that's hated.

It actually sounds like your answer is more bias-based, because your intuition is more wrong here. There is data from the 2020 Stack Overflow survey[0] indicating a significant lead for devs who use Rust and continue to want to develop in it, vs. Go. 86.1% Rust vs. 62.3% Go.

[0]https://insights.stackoverflow.com/survey/2020#most-popular-...


In the context of the article, I think that can be attributed to age (go is older than rust, so trending towards the "brown field." See for example Scala, which is a little bit older, and ended up in both loved and hated lists. I'd speculate that Go will be in the same camp in 4 years or so based on polarized sentiment I've observed.

That being said, there may be something about strict/complicated languages like scala and haskell that tends to polarize developer sentiment. Rust seems like it could fall into that same pattern based on the "up front" work that it demands.


Those numbers aren’t comparable.

Go and Rust don’t have similar numbers of developers. My intuition is that Go has an order of magnitude more. It’s like comparing product reviews on a shopping website - 4.7 based on 20 reviews vs 4.3 based based on 200 reviews. It’s hard to say which is better. You’d have to go deeper into each of those reviews to learn if the pros and cons apply to your use case.

Another important metric, as OP pointed out, is the age of the code base these devs are working on. Rust devs are probably working on code bases they started and Go devs are maintaining someone else’s code base.

That said, I agree with the current top comment on the thread - Rust code based may prove easier to maintain when we look back 10 years from now.


> It actually sounds like your answer is more bias-based, because your intuition is more wrong here. There is data from the 2020 Stack Overflow survey[0] indicating a significant lead for devs who use Rust and continue to want to develop in it, vs. Go. 86.1% Rust vs. 62.3% Go.

That's great to hear. Unfortunately, language popularity in enterprise/production environments isn't really based around how much a developer loves or hates something.

There are more Go programs/programmers now than Rust, was the basis of my post that you're objecting to, which can be verified if you scroll up on the link you posted.


> A language that is touted as "difficult to learn" and "difficult to onboard" is by definition not built for maintaining.

I'm not so sure about that. (Or perhaps the definition itself needs scrutiny?) Most the languages I've seen get a reputation for being easy to learn have also subsequently earned a reputation for being a maintenance hassle: perl, ruby, python, php, javascript, etc.


I think this is probably selection effects rather than language features. Easier languages disproportionately attract weaker programmers.


Likely both. Duct tape is easy to learn, but it's not a good tool to use when building a house. Due to properties of the tool, not because it attracts bad carpenters preferring to use duct tape.

Combine both these factors and you have a real amplified problem on your hands.


Easier languages tend to get popular easier as well, which lends itself to companies being able to hire more.


Language nitpick in the parent’s comment: “touted” is definitely the wrong word here, to tout is to solicit.


"touted" has a positive connotation to me, so it doesn't sound right to tout negative aspects of something. But the meaning seems clear.


> “touted” is definitely the wrong word here,

Uh, no. In Merriam Webster, that's meaning #2. Meaning #1 is

> to make much of : promote, talk up

> touted as the summer's blockbuster movie

> the college's much touted women's studies program

https://www.merriam-webster.com/dictionary/tout


Realistically, that first definition is slightly ambiguous; it may or may not mean to imply that the talk is supposed to be promotional and not derisive in order for the definition to apply. I am guessing that they probably did mean to imply that connotation, though, based on other information on the page.

I'd argue, though, that the reality is that the word's meaning is in the process of shifting from being a synonym for "promote" to being a synonym for "make out to be"; that reflects much common usage, and dictionaries always lag behind a bit in cases like this. They have to - they're a descriptive artifact, not a prescriptive one.


Which is also positive in its tone. It’s the wrong word.


The sense here is

1 : to make much of : PROMOTE, TALK UP

as opposed to

2 : to solicit, peddle, or persuade importunately

https://www.merriam-webster.com/dictionary/tout

Edit: uups! Didn't reload the page and see yesenadam's comment before posting. Sorry about that!


It was promoted as hard to learn? What. Neither definition fits.


> It is almost certain that in 10 years, both will be used more than they are now by several x's.

That's why so many threads end up being about Rust vs. Go. They are the new(ish) languages that appear most likely to be real factors in the industry for a very long time, so they bear more discussion.

I wasn't really around for it, but I'm sure there were lots of discussions about Java vs. C++ earlier in their lifespans, for this same reason.


> I'm sure there were lots of discussions about Java vs. C++ earlier in their lifespans

Rewind to 1996. I’m at the Networld/Interop conference in Las Vegas. The steel skeleton of the Ballagio looms over desert mirages, and Java is all things to all people: a wide-open utopia to be populated by new and perfect code, a new world without concern for memory management, an abstraction from everything freeing us all from needing to know anything.


> A language that is touted as "difficult to learn" and "difficult to onboard" is by definition not built for maintaining.

I disagree. The things that make for good maintenance correlate with both difficulty to learn and difficulty to onboard. (The converse is not true.) Things that are easily to learn tend to be easy to start with, but end up tacking on, via frameworks or coding standards, pieces that raise both difficulty to learn and to onboard as complex projects exist.

Specifically, maintenance requires thinking like the person or people who initially created the code. The more your thinking aligns with them, the easier it is to maintain. And that act of changing to think like them is learning and onboarding.


I can learn any language in a day or two. And become proficient in it in a week.

Big part of mastering is less about knowing the language and knowing its plumbing. Quirks, unique behavior, library, tooling, etc.

Dynamism is a constant source of pain. Because it makes tooling and thus exploring language harder.

In Rust there is little such dynamism. Actual problems understanding are macros and proc macros. And finding the right Trait.

Tooling around Rust is standarized. You have cargo, rustc and they bring in the rest.

While there is some chance of Rust going nuts and adding some bizzare thing like inheritance, HKT++, the chance that it will reach cognitive complexity of Scala or C++ is lesser.


I program in Python by day. Racket is probably the language I know best after Python, then maybe Groovy. I've had exposure to R, C, C++, D, Java, Common Lisp etc, and I find it easier to pick up new languages due to my familiarity.

While Rust has all the constructs that I'm used to from these other programming languages, I find Rust to be the most difficult one for me to learn in recent memory. The documentation is great, the book is great, the tooling with Cargo is great, but after getting through the first 15 chapters in the Book I struggled to write a program that had any sort of complexity. Sure I can add a dependency super easily to my project, but figuring out what errors everything in the library throws takes a lot of work. Sometimes I get confused about using panic!, expect, unwrap, or ? when I'm writing my own functions or interfacing with others. Swimming through the myriad of traits on different structs is confusing, and I sometimes get tripped up passing closures. And don't get me started on Macros, with great shame, they still have not clicked for me, in Lisp, or in Rust. The language just feels very different from what I'm used to, and I've never had such a hard time getting code I've written to compile correctly. I'd be totally lost without all the help from the subreddit and the book, and I appreciate everyone who has helped me.

I know this will get easier... and it has. But it will take longer for me to get comfortably with Rust then it has for other programmings languages in the same time period. This is not to say that it's a bad language. I remember one day after having debugged a Python issue that ended up being a stupid logic error on my part I exclaimed "I wish I knew a programming language that would save me from myself". I think... Or rather I hope Rust is that language in the long term for me


I think you missed some Haskell (or some other functional / category-theorish language) in your baggage of languages.

Coming from Haskell, Rust felt like a weird C-like home.

It's a weird marriage, but it makes for a language which make very predictable software imho


> The language just feels very different from what I'm used to

The reason it feels very different is... because it is very different. Then why does it feel off? Because, while it is very different, it doesn't look very different. Then why doesn't it look very different, when it is very different?

That's because, Rust developers spent conscious effort to make Rust look similar. So feeling something is off with Rust is the result of intentional design of Rust developers. In a sense this is dishonest and deceiving, but Rust without similarity engineering would be considerably less popular and hence less successful.

Rust's ambition was to change the world, not simply to discover a way to change the world and leaving actual changing to others. (Although changing the world requires discovery first.) So Rust chose to "lie".

As an example, Rust's assignment(=) looks similar, but works very different. In fact, since it is very different, it was originally written <-. It was changed to = specifically to make it look similar.


Another example is std::mem::swap. In the world of affine type system which Rust uses, swap is a primitive on an equal footing with assignment (which is actually called move). So naturally, move was written <-, and swap was written <->.

But <-> weirded people out, and people complained why Rust has so many special and strange operators. So Rust developers made it look similar to a library function. But it still is a primitive: it is impossible to implement swap yourself in safe code.

The result is that people use swap much less than they should, either because they are not aware of it, or because they think it is a specialized library function for special cases. This is significant and large cost. But it is still less than cost of looking weird. All because people won't even try languages with <->. Alas.


One of the side-effects of this is that, Reading Rust code is painful.. it is a bit like reading old perl or haskell code you haven't looked at. Especially when rust is not the day job it gets complicated/painful to remember the distinctions between "=" in say python(that's what i use most) vs "=" in rust. This is not necessarily a bad thing, but it does contribute to that previous posters' point out finding errors or bugs from libraries being used hard to find or fix. Once again, I don't care much for go, but rust is one of the languages that excite me, but trying to level up in rust(beyond the trivial tutorial code/projects) seems to need a dedicated "maker time' schedule rather than spending 30 mins- 1 hour spare time in between distractions from children.


> it was originally written <-. It was changed to = specifically to make it look similar.

That's actually kinda disappointing, I use <- in my pseudocode.

(I don't know Rust though, so I can't comment on their choice for the language)


I program in Python at my job and Rust in a hobby project. It surprised me how easy and productive actually Rust is, and I was really very sceptical initially. I know it is very subjective, and possibly a result of my longer exposure to statically typed languages, but simply Rust felt quite natural to me, while Python still feels very quirky, irregular and sometimes outright annoying, despite me spending more time with Python than Rust.


I use neither Go nor Rust and don’t have an opinion, but it’s worth pointing out that “difficult to learn” is highly contextual, e.g. Python or Ruby were probably relatively easy to learn if you already knew Perl or PHP. I found Haskell quite difficult to learn. Subsequently PureScript was very easy. Widely shared knowledge and concepts change over time and they will affect ease of adoption.


I wouldn't call Rust difficult to learn. The syntax quirks (Knowing where to put `&` etc takes time, and traits are abstract, but used all over Rust codebases). For example: Look at Python which is typically considered easy to learn. In Rust, I know that I can create a project using official tooling; specify dependencies cleanly in `Cargo.toml`; use the built-in linter, and formatter. Check the Rust docs page for any dependencies, including type signatures for all functions, and a list of struct fields. Look in the `examples` folder of a dependency's repo for code snippets.

In Python, I'm likely to find a comparative mess of sparingly-documented documented third-party tools, dependency docs, and Stack Overflow posts.

Or, look at embedded, where C is considered a simple language. In C, it's not obvious how I'd start. Use something like Cube-MX or Keil? GCC? All the options are messy and tough to learn. In Rust, I clone a template repo, cargo-install 2 or 3 tools and targets, and `cargo run` to compile and flash.


> I wouldn't call Rust difficult to learn

I agree with this too.

This is because you know what Rust brings you compared to what you used in the past that cause you pain.

Unfortunately, some people that have difficulty learning Rust (or hear about it) focus solely on the learning process and not what they gain by learning it.

Learning a low-level language is inherently hard because there are more at stake, it is simply more complex. For people that work where dangling pointer, data-races, is never a problem, they are learning about the problem the same time they are learning about the solution (Rust's ownership concept), and I came from that place too.


> Or, look at embedded, where C is considered a simple language. In C, it's not obvious how I'd start. Use something like Cube-MX or Keil? GCC? All the options are messy and tough to learn. In Rust, I clone a template repo, cargo-install 2 or 3 tools and targets, and `cargo run` to compile and flash.

Keil is a company that builds an IDE, compiler and debuging tools for microcontrollers. CubeMx is a configuration tool/code generator for STM microcontrollers. You comment makes no sense in regards to C language, unless you are saying that rust/cargo automagically does everything that Keil products and CubeMx do?


Correct:

- `cargo install probe-run`

- `rustup add `thumbv8m.main-none-eabihf`

- `git clone some-template`

- `cargo run`


Wait, these 4 commands create an IDE with with JTAG debugging support, tracer and a profiler and than configure all the chip's peripherals, add low level drivers (UART, SPI, USB, FS, I2C, ETHERNET,...), setup clocking and power settings and add RTOS? I took Keil probably decades and STM years to write all that complex tooling. I'm mean it probably takes an engineer a month to bring new HW to life with the help of all those tools before they can start writing application firmware. Are you really saying 4 lines of rust tooling do the same in couple of seconds? That would be some amazing AI behind those 4 lines.


Those lines let you compile, flash, and debug. For IDE, I prefer the IntelliJ Rust plugin. Some people prefer VsCode instead. The point here is that you choose an editor suitable to the language, with the code-editing and project-management features you like.

Low level drivers are usually handled using libraries of 2 general categories: Peripheral access crates (PAC) (mostly) auto-generated from SVD files; HALs that provide an abstraction over the PAC.

A month to get started sounds... intense, depending on the project. What drove (drives?) that? Let's say I want to do a simple project using STM32. Something simple that reads sensors, has a few buttons, and outputs to a display. I'd choose parts, put together a layout in a PCB design software, and order the boards, which arrive within 2 weeks. In the meanwhile, use a dev board as required. Find a driver for the sensor, screen etc if it exists. If not, write them using the datasheet. Use a HAL to take configure clocks and peripherals, write the control flow logic (Perhaps based on interrupts). For anything the HAL doesn't support, use the Reference Manual and the PAC to set the appropriate fields.

Setting up I2C might be something like this, using a HAL:

    let mut scl = gpiob.new_pin(PinNum::P6, PinMode::Alt(AltFn::Af4));
    scl.output_type(OutputType::OpenDrain, &mut gpiob.regs);

    let mut sda = gpiob.new_pin(PinNum::P7, PinMode::Alt(AltFn::Af4));
    sda.output_type(OutputType::OpenDrain, &mut gpiob.regs);

    let i2c = I2c::new(dp.I2C1, I2cDevice::One, 100_000, &clock_cfg, &mut dp.RCC);


The only thing that I did for STM32 was writing drivers for dual FLASH quad SPI external memory. Since I didn't know much about STM32 and there was no sample driver for the flash chip I was using, CubeMX helped quite a lot. It still took me a good week to get it working.

Usually when developing a new platform for our products, I/we need to bring to life: SDRAM, LCD, touch controller, external flash for code and data, SD card + FAT32, USB, ETH, plus a bunch of other components (ADC, DAC, BT, other uC, latches,...) using the usual peripherals (UART, SPI, I2C, timers,...). Keil provides a good compiler and linker, fast JTAG debugger, RTOS and a bunch of middleware libraries (some are quality, some are lacking). While I dislike its IDE for writing code, it is a lot better than VS code for debugging purposes. It also supports flashing and erasing MCUs with internal and external memory, which sometimes requires special programming algorithms.

For us stability, tooling and good library support is the most important part of doing our job. Language follows from there. C and C++ have the advantage of the GNU/Linux ecosystem of open source to draw from and they map to the hardware almost perfectly. On higher level systems (Android, Linux) we use higher languages (with GC) which have even nicer tooling and better libraries for writing application code.


Nice. It sounds like the time sink there is writing drivers for a range of peripherals. The silver lining is next time you use that periph, it's easier.


C/C++ and Rust are both hard IMHO. D is way easier, one gets productive quite fast and there are also more advanced language features once you get proficient in it, unlike Go.


> A language that is touted as "difficult to learn" and "difficult to onboard" is by definition not built for maintaining.

Rust is not more "difficult to learn" or "difficult to onboard" than C++. And C++ is certainly a language with plenty of legacy, enough that you could reasonably call it "brown". Go is a rather different language that's perhaps best compared with Java as its closest "brown" counterpart.


> Rust is not more "difficult to learn" or "difficult to onboard" than C++.

Saying Rust isn't more difficult than possibly the most difficult thing is not a good argument in favor of Rust not being difficult, no?

People dread maintaining legacy C++ systems. People dread maintaining legacy systems. Rust will be no different.


The problem with C++ is that the various standards have encouraged changing idioms. Pre-standard, 98, 11, and 17 are significantly different when the new language features are fully leveraged. Legacy code creates inconvenient barriers when interoperating with modern stuff. Rust may be able to escape this problem.


I mean eventually there's going to be rust 2 etc...


Rust, unlike other languages I know of, has a well defined process to make breaking changes to the language. These changes are opt-in on a crate level so you don’t need to migrate an entire code base in an instant. The team also ships tools to auto fix code out there to make the migration easier.

The 2018 edition had a few small breaking changes, the 2021 edition will have none. Personally I hope the 2024 edition makes some breaking changes to make IDE development easier.


C++ is backwards compatible the same way and there was never any need to migrate your code. What happened was that c++11 brought in a major set of new features, changing the best practices of how to use the language, almost to the point of making it a new language. Mainly smart pointers, initializers, type inference, threading and lambdas, and removing tons of other small rocks in the shoe.

So that someone familiar with c++11 or newer opening up a legacy code would maybe not have a hard time understanding it but they would go "wtf is this verbose shit" and be tempted to rewrite it. Vice versa an old schooler would need to relearn these new features when opening a new code base.


Not from the Rust project; someone else would have to come along and build it.


I mean there will be more and more changes to Rust, just like how C++ has had many changes over the years. Rust 2020, .. 2025, 2026 etc..


I cannot write a program from scratch in Haskell. I just can't wrap my brain around it. However, every time I've needed a new feature in a program I use written in Haskell, it's been easy and a pleasure to implement.


I doubt Go will be used in the future more by several times than it is now. Looking at Google Trends, we're past peak Go, it's now on the decline:

https://trends.google.com/trends/explore?date=all&geo=US&q=%...

I haven't seen anything that would indicate anything else than Go slowly declining much like Ruby has. In other words, it's still around and getting new updates, but losing mindshare.


By that metric, doesn't Rust have an even bleaker future? https://trends.google.com/trends/explore?date=today%205-y&q=...


My response was more doubting that Go is going to be used many times more than it is currently 10 years down the line, but the trend on Rust is upwards:

https://trends.google.com/trends/explore?date=all&q=%2Fm%2F0...

That doesn't mean it will ever achieve popularity, and could also go away.

However, with the Go developers' insistence on changing the language as little as possible (not good or bad, it just is), it seems unlikely that Go will see a resurgence that brings it to multiple times usage than it has now.


But, they are working toward Go2. Generics, which are the biggest talking point whenever Go is discussed, is already added in a branch and is supposed to come in a year or so. It'll be interesting to see how it'll affect the trends data after that.


Do they actually have people who are experienced with type theory working on the type system, or is it the same core team?



Not really because the difference is that the overall trend on Rust is still upwards (it's hard to see with the two languages on the same axis). I've been investigating Rust and it looks like it's going to cure the pain points I've had around C++ on a project I'm working on and I'm quite happy with it so far.


The funny is if you use "golang" as the term it peaked at a different time (2019-2020), but then there was a very sharp drop at the beginning of this year. I wonder what the reason is?

https://trends.google.com/trends/explore?q=golang&date=all&g...


Google is not perfect at distinguishing which queries for the word "Go" are actually about the Go programming language.

Referring to the language as golang is a secondary name, popularity driven by Google's own performance surfacing go (language) related results for the word go.

Go (programming language) has the same january drop as golang, clearer when both are viewed together:

https://trends.google.com/trends/explore?date=all&geo=US&q=g...

I don't think Go actually is substantially less popular in Febuary 2021 than November 2021 (January/December, maybe due to people/student vacation time), but the google trends anomaly is not a go vs golang naming distinction.


That’s quite interesting. I’ve added Typescript and Ruby to the chart - apparently they are all declining in popularity. But I wonder, which language is the one currently rising then?


On the other hand, searches for "golang" matched their all-time high in July 2020.


Not sure what you mean. This chart shows the peak as being in 2019, and declining since then:

https://trends.google.com/trends/explore?date=all&geo=US&q=g...


You're looking at US, the Worldwide view matches July 2020.


> A language that is touted as "difficult to learn" and "difficult to onboard" is by definition not built for maintaining.

Disagree. First, difficult to learn is not difficult to onboard. Second, unless you think Ocaml is not hard to learn, i think this is a great counterexample.


It is almost certain that in 10 years, both will be used more than they are now by several x's. I think pretending you can predict what'll happen with either (and the industry) over that time is pretty silly.

You contradict yourself.


I think the "difficult to learn" and "difficult to onboard" is important to keeping rust a "Most Loved Programming Language". If only those who make it through the "difficult to onboard" phase use the language extensively, then only they will be responding to the "most loved"/"most dreaded" question.

I taught a university seminar that looked at rust and another emerging language a couple of years ago and only 2 students out of 30 said they would use rust again after the class. So the rest will never get a chance to answer the survey question about rust.


> A language that is touted as "difficult to learn" and "difficult to onboard" is by definition not built for maintaining.

Strong disagreement here.

It could be difficult because it's built for maintaining.

People who are unable to understand Rust are the people you don't want anywhere near your C/C++/Rust project.


> A language that is touted as "difficult to learn" and "difficult to onboard" is by definition not built for maintaining

PL learnability alone is not significant as a factor for a PL to be chosen for a certain task, unless it is impossibly hard. Rust, looking at the growing community, is not a PL that is impossibly hard to learn.

A PL is chosen for a certain task for its features. The same as any other class of tool, "A is chosen for X because of A's feature".

The learning curve is simply the side-effect of the PL's minimum features need to be learnt for it to work. Rust being a low-level language + an extra layer of protection is inherently hard.

But let's see how it fares in 10 years. There have been successful projects built on Rust, firecracker, figma, discord, and many more, despite it being so young.


> A language that is touted as "difficult to learn" and "difficult to onboard" is by definition not built for maintaining.

I think this presumes that you have to teach people the language. But most maintenance programming is done by hiring people already familiar with the language the existing codebase is written in, and then bringing them on to work on the existing project.

Rust isn’t hard to onboard for an individual project, in the same way that a macro-laden Lisp codebase is. Once you know Rust, you know Rust. It takes more effort to “know Rust” because you have to learn all the ecosystem stuff expected of someone who “knows Rust”; but from the perspective of an employer, you can just hire “someone who knows Rust”, and they’ll come with all that knowledge.

And, in fact, an experienced Rust dev may be able to start work on a novel-to-them existing Rust project, a lot faster than (for example) an experienced C dev would on a novel-to-them existing C project, as a large stdlib / conventional ecosystem of foundational libraries (as in the case of Rust) tends to translate well to experienced developers coming into a codebase and quickly recalling everything, because it’s a bunch of the same batteries/libraries they’ve already used in the past.

The difference between a design pattern and a language feature, is that you can recall language features, while you have to recognize design patterns (i.e. grok the code in order to identify what pattern(s) it’s trying to reify.) Languages with more formalisms (either built into the language, or in common use in the ecosystem) increase the amount of recall that new maintenance programmers can do (or rather, decrease the amount of recognizing they have to do to get up-to-speed), and thus make switching a maintenance programmer between codebases “cheaper.”

—————

I bring this up not from the perspective of a Rust programmer, but from the perspective of an Erlang programmer... who also doesn’t like Go very much (though I do write quite a lot of Go! As a maintenance programmer!)

IMHO Erlang and Go aren’t all that fundamentally different runtime-wise. Presuming you’re using them for the same thing — writing highly-concurrent, fault-tolerant network servers — the main difference between the experiences of coding in Go and in Erlang, comes down to the fact that Go provides you with a bunch of concurrency primitives that you have to put together as design patterns — and where maintenance programmers then have to recognize those patterns; while Erlang actually has universal concurrency formalisms that everyone takes advantage of, and so those formalisms can simply be recalled on new projects.

I advise anyone who thinks that “recognizing design patterns” is a cheap-and-easy thing to do, to tell me what’s going on in this file: https://github.com/ethereum/go-ethereum/blob/master/eth/down... . I’ve stared at this code on-and-off for two years, and I still don’t have a mental model for it. If this code was made out of cleanly-separated named/opaque formalisms, rather than fifty design-patterns tied into a knot, I can’t even imagine how much more productive I would have been working on it.


> A language that is touted as "difficult to learn" and "difficult to onboard"

Does anyone know if there have been studies about how long it takes to learn different programming languages? I hypothesize that it would take a beginner programmer longer to learn Rust than C, but probably a similar amount of time as learning C++ (which I think is the closest “traditional” programming language to Rust).


Have you ever maintained a piece of Rust code?


Yep!

edit I am amused at this downvote. I was asked a yes or no question, and responded with a yes. What could possibly make this response downvote-worthy?


It seems reasonable to argue the exact opposite: (edit: for clarification, I think this argument is roughly equal in strength to the parent. My bias is definitely showing, but my main point is that knowing which will be true is hard.)

Go was built explicitly to solve the real everyday problems of working in a large code base, largely driven directly by experience of several industry titans. It mostly remixes what has proven to work into a cohesive package. It's only as large as it absolutely needs to be (so new devs can learn it quickly), and has a strong focus on developer UX (gofmt, build speed, godoc).

Rust on the other hand is a far more ambitious language. It's trying to statically solve many types of problems which are typically solved through testing and experience. Using Rust productively requires much more Rust specific learning. With how Rust is changing and having multiple approaches to things as the language is defined, long living code bases are going to accrue different methodologies from whatever was popular when each component was written.

I think in 10 years a few experienced devs will do to Rust what Go did to C: Take the bits that obviously worked well, add a few ideas from other languages to soften some rough corners, and present it is a smaller, easy to use package. Though I also in general hope old languages are being replaced by new languages, as that must happen if as an industry we are getting better at building software. But also because I'm making a programming language and I have to believe I've found room for improvement for that to be a good idea.


>Go was built explicitly to solve the real everyday problems of working in a large code base, largely driven directly by experience of several industry titans.

Several quite opinionated industry titans who appeared to ignore most things they didn't themselves invent in AT&T for UNIX or in Plan 9, and based on their own preconceptions of "programming at scale" as a pet project (not based some formal Google-initiated research on its practical needs).

Algol and ADA were indeed created by "experience of several industry titans", in a process examining the field of applications and use cases for the languages.

Go was not really that, whatever the story says.


> and based on their own preconceptions of "programming at scale" as a pet project

Based on their experience working at Google. It wasn't just "preconceptions". (True, it also wasn't an examination of the field of the form that led to Algol and Ada, but it wasn't just preconceptions, either.)


>Based on their experience working at Google.

Yes, but that's their experience working at Google as 30+ years industry veterans and thought leaders (one would guess, mostly left to do their own thing, as prestige hires).

Not as regular developers doing everyday Google grunt-work...


Well, the founding myth of go says that it started from a conversation during a 45 minute C++ compile. I doubt that that was Rob Pike's personal "thing" project - he hadn't been there long enough to have a personal project that size. That was some big multi-person multi-year thing.


They had the limbo language in plan9, which has similar features and quirks. It seems most probable that the outcome of the 45 minute conversation wasn't "let's build a language from scratch", but rather "let's iterate on limbo".


You can get the details here,

"Creating the Go programming language featuring Rob Pike & Robert Griesemer"

https://changelog.com/gotime/100

There are other sources as well, this was just the one that quickest came to mind.


Actually it was, and they had a manager that covered up for them, allowing them to keep working on the project.

"Creating the Go programming language featuring Rob Pike & Robert Griesemer"

https://changelog.com/gotime/100

Had not been for him and Go would never gone beyond a prototype side project.


That isn't what I was claiming, though. I was claiming that the impetus for creating go was the issues raised by working with Google's regular code, not issues raised by working on Rob Pike's pet project at Google. Whether go became their pet project was outside the scope of my claim.


The only issue was waiting for builds and having to deal with C++ code, something that Pike shares the same opinion as Linus.


> Go was built explicitly to solve the real everyday problems of working in a large code base, largely driven directly by experience of several industry titans

This claim keeps getting repeated with absolutely nothing to back it up, other than repeating what the golang authors claimed.

I work on a large golang code base, and it's quite horrid. The IDE experience is terrible. It's hard to navigate the code base, due to things like types unintentionally implementing interfaces because they happen to match on some of their function declarations. No proper visibility rules (only "public" and "package private"). interface{} everywhere because of no generics (I'm aware that's being worked on). Single character variable names are popular because the golang authors write code that way and it's seen as "smart". No reserved "this" or "self" keyword to declare methods means that every type will have its own single letter self variable which you have to look up every time. Error handling is terrible, and I've seen many insidious cases of mishandled errors. Null pointers are still a thing. The list goes on.

Edit: not to mention things like the language is against quick prototyping (heavy friction due to things like unnused imports or variables, and a very verbose language), as well as the lack of mature libraries such as JDBI or Dapper.


> No reserved "this" or "self" keyword to declare methods means that every type will have its own single letter self variable which you have to look up every time.

Python lacks a reserved keyword for this use, and I can count the ones not using “self” in instance methods and “cls” in class methods that I’ve encountered on the fingers of my left foot.

But, yeah, weak convention plus no keyword promotes needless chaos.


This sounds like really bad code was allowed to be checked in, not the fault of the language. You can make terrible code in almost any language.

The above does not match my experience in maintaining large go codebases because of proper code reviews and expectation of writing maintainable code.


Nope, we have a very rigorous linting and review process. It's the shortcomings of the language.


how are your complaints about your bad variable names shortcomings of the language and not the code you accept?


Because it's literally in the standard library of golang, and everyone copies its style.


There is no law that requires the use of the same variable naming style as std. Also,

> interface{} everywhere because of no generics

It would be good to know the domain here. Looking at my own fair share of Go code in productive systems (probably around 100-200 KLOC, written over the last 6 years), interface{} is really really rare. It appears in some library functions which genuinely accept basically any type, in the same way as json.Marshal(), fmt.Printf() or sql.Stmt.Execute() in std.

Other than that, I don't think I've ever had a case where I used interface{} instead of defining a more specific interface (plus adapter types to implement that interface on foreign types if necessary).

The only big mess that I've come across in Go land is kubernetes/client-go. I can't wait for generics to replace this metastasizing heap of autogenerated code.


> There is no law that requires the use of the same variable naming style as std. Also,

While that's technically true, it doesn't work out in practice because people look to the standard library as "the way" to write golang. It's basically an implied rule and I haven't seen anyone not folllow it so far.

> It would be good to know the domain here

Both infrastructure level work as well as CRUD type work.

> interface{} is really really rare

We have to use them everywhere for things like JSON parsing, config file handling, and pagerduty integration. Not to mention wrappers around SQL handling (e.g. batch inserts, pagination, etc.)

Generics will fix some things in the language, but not all. There are too many issues with it like the ones I already mentioned. It's still a very cludgy language to work with.


> JSON parsing, config file handling

I assume you're not referring to things like json.Marshal(), where the function argument is legitimately of type interface{} since it really accepts any value.

Hence I'm going to assume that you're referring to situations where a value can have one of multiple types (e.g. a float value that sometimes gets provided as a string). It's true that people sometimes unmarshal into interface{} and then type-assert in those scenarios, but that use of interface{} is a code smell that should be flagged in review. The proper way is to unmarshal into a custom type with a json.Unmarshaler implementation that accepts all possible input formats (and vice versa for json.Marshaler if encoding is required). This is a real-world example from one of my codebases: https://github.com/sapcc/limes/blob/d833228e976ac1ddc4b95779...


Algebraic types would solve the issue in the example you're giving. However, those don't exist in golang either.


Having worked with the people doing those standard libraries, you're pulling justifications out of your butt for bad practices.

Just as a start: variables names should always be clear by context. You only see the one letter ones if its literally the next line or similar use case. Also, bare interface{} should basically never be the case for a function signature.

None of the code you've described thus far would pass a proper review.


Code bases in reality still do what I'm describing, and they pass code reviews. Kubernetes is one example of the atrocities caused by the language.


>Go was built explicitly to solve the real everyday problems of working in a large code base, largely driven directly by experience of several industry titans.

So have all languages, with wildly different philosophies about how to do that. We collectively just don't have any idea what we are doing. Clearly nobody has stumbled on a big win or one particular language would start dominating the industry due to the productivity bump.


I actually don't think this is true, which is kind of nuts. Programming languages generally fall into two categories:

1) They were either designed by one or two eccentrics, and thus contain a few great guiding principles and many questionable ideas, which invariably come back to bite large projects; or,

2) They were designed by a committee who tried to make the Final Universal Language that would solve every possible problem, resulting in a kitchen-sink mess of a language with a 400-page specification that no one reads.

Most mainstream languages made some attempt to serve software-at-scale; for example, OO used to be the obvious thing that would make software more maintainable, so most languages support it at least in part. But if you look at a language like C++, it's obvious that many of its features were added simply because they were cool or increased expressiveness (e.g. operator overloading) without regard for long-term maintainability. Even things as mundane as "implicit 'this'" are clearly harmful to readability, with specious benefit.

AFAIK, Go is the only language that really takes engineering seriously: https://talks.golang.org/2012/splash.article If there are similar articles for other mainstream languages, I'm certainly curious to read them and see how they hold up today!


> AFAIK, Go is the only language that really takes engineering seriously:

Ada is the consummate engineer's programming language. And with Spark, even more so. Unfortunately, the compilers were super expensive at a critical stage in its evolution. And the DoD thing.

And I've never used Rust professionally (unlike Go), but it has all the applicable points in the article you list (obviously no garbage collection). But in Rust, these features are often implemented in a more robust manner than in Go (eg, like Go, Rust avoids exceptions and uses error values, but instead of returning a special-cased interface, it returns a regular sum type, which allows for proper type checking of the error handling, and which is also composable since it's also a monad). And unlike Go, Rust got package management down from the start. Go's package management has gotten better, but it's still not as good as Rust's through Cargo (to be fair, Cargo is best of class).


I think what is actually going on is that Rob Pike's ideas about how software engineering should work resonate strongly with you, while Anders Hejlsberg, Don Syme, James Gosling, Christ Lattner, and Rich Hinkey does not resonate with you.

I think it would be a difficult argument to suggest that those other people do not have similar engineering chops, or haven't been around a long time.

But if you are right we should see Go winning in the marketplace more and more in the future in a way unprecedented for programming languages.


I don't mean to suggest that at all -- I have great respect for those people, particularly Rich Hickey, whose framing of "simple" vs "easy" is vital to these discussions. But it's clear that a language like Clojure is not a good fit for million-line, decades-old codebases. Java wasn't explicitly designed for large-scale engineering either; it's north star was Write Once, Run Anywhere. In short, I think there are very few languages that prioritize engineering to the exclusion of other features, and Go is one of them.

Ada is another; it was explicitly designed for large-scale engineering, but hasn't seen nearly as much success as Go. I'd like to learn more about why it failed. Perhaps it was the language itself, or maybe it was merely a timing issue, or the fact that it was backed by the government. This comment has some good info: https://news.ycombinator.com/item?id=7825008


Why Ada failed has been discussed ad nauseum including on here. Early compilers were $$,$$$ per seat and proprietary, they're still easily $,$$$ per seat. Good open source compilers came later, there's still a strong disparity between the FOSS and commercial compilers and tooling.

The language was a mandate from US DOD which rubbed a lot of people the wrong way. It largely sat in the same space as Fortran and C, C was free (or much less expensive) and more readily available even when it did cost.

Cosmetic: People strongly dislike the verbosity of Ada. Some parts are reasonable to consider changing (but really are just cosmetic) like begin/end versus {/}. Other verbose portions are hard to change without fundamentally altering the language. You want to print integers and strings and you don't want to have to use Integer'Image(X) all over the place?

  with Text_IO;
  use Text_IO;
  with Ada.Integer_Text_IO;
  use Ada.Integer_Text_IO;
Now Put and Put_Line can be used with both strings and integers. Oh, you want to print more types? More withing for you. I don't mind it, you don't need to print in every package, but it is very cumbersome.

If you want to write a quick CLI tool, Ada is not your language (though I've done it), go for Perl, Python, Ruby, sh/bash, or even Go. C and C++ can be easier for that purpose. But once you start scaling it's a very good language.

The only way to get Ada in the mainstream now is to make it much cheaper and greatly improve the FOSS compilers and tooling, and have SPARK/Ada support an increasingly large subset including approaching feature parity with respect to memory safety as Rust. That's being worked on, but it's a non-trivial problem.


> https://talks.golang.org/2012/splash.article

The shortcomings listed in that talk are mainly against C and C++. Other serious languages and platforms like Java, C#, and also Rust have solved these issues.


>So have all languages, with wildly different philosophies about how to do that.

I think what you refer to as differing philosophies are in fact differing goals, and the goal of Golang is very different from pretty much all other modern languages: simplicity.

I think boiling everything down to 'they are all trying to do it better' misses the fact that the 'it' they are trying to do better is very different in some cases.


> simplicity

This has to be quantified. Simplicity in the language, perhaps. It definitely does not translate into simplicity of resulting programs, and the ease of being able to reason about them, or write them.


Having spent about 3 years each in Java, C++ and Golang, and getting a good amount of time with Python, I have to disagree with your final few points. Golang's simplicity in the spec itself DEFINITELY gives down stream benefits, simplifying a lot more beyond itself. That includes writing and reasoning about code.


Having worked on several large golang code bases, its verbosity is tedious to deal with. It doesn't lend well to IDEs (e.g. it's so easy for a struct to accidentally implement interfaces it doesn't mean to because of structural typing). Error handling is always a mess, it doesn't have enums, and so many issues to list here that Java doesn't have.

The golang authors' weird obsession with not having any methods on strings for example, makes it horrendous to work with them (e.g. can't chain someString.trim().toUpper().endsWith("...")).

Don't get me started on the supposed fast compile times. Parsing is fast (but so almost any other language that is not C++ or Scala), but linking is horrendously slow. Modifying and re-running individual unit tests takes seconds at a time due to relinking. In Java, it's in a blink of an eye because there is no linking.


Having to use functions on built in types like strings.HasSuffix(strings.ToUpper(...)) isn't that bad to me. If I'm chaining a bunch of function calls on a single string, I'll want to separate them on different lines for readability anyway. It'll be creating and destroying a few implicit copies either way, so I have never really felt any pain from that.

Java has no linking, but you have to go through the JVM. Golang produces native binaries. Not really a fair comparison. That being said, my brain is normally a way larger bottle neck than linking time for unit tests.

I'll cede the gripes with enums and error handling (although I hated the way Java exceptions always ended up way too overloaded way more), but I find the typing a really good balance between strong and weak. It's strong enough that you have to be doing something really weird to mess up, but weak enough to be flexible.


It is your position that Go is the only language aiming for simplicity? Are you relatively young?


No, I don't think it is the only language aiming for simplicity. I do, however, believe it has been the must successful at it.

Young at heart :)


> Clearly nobody has stumbled on a big win or one particular language would start dominating the industry due to the productivity bump.

This is what happened with Python. It provided a distinct productivity advantage over C & C++, and now no one writes web apps in C++ anymore. Granted, it's not just Python anymore, but newer languages learned from Python's success.


First we had web apps written in Java, then Perl, PHP.

Python's popularity for web app development came way later (django was released in 2005)


Python was originally written as a reaction to C & C++. It didn't really hit the mainstream for web apps until much later, granted, but when we compare it to the languages it was originally competing against, the difference is pretty clear.


Garbage collection got a clear productivity gain over not garbage collection. But it isn't clear that the various takes on GC languages, Python, Java, C#, Go etc have led to any one clear winner.


> Python, Java, C#,

Notably, we've had garbage collection for nearly as long as we've had programming languages - so this has been going on much longer than the examples you give would suggest.


I'd argue that Java ultimately failed to innovate over C++ in the way that Python did. It added GC, but it's still clunky and hard to work with. In that sense, it's more of a pre-Python language, even though it's a few years younger than Python.


I don't think you mean that, or you misunderstand how Javascript or PHP came to be.


If I didn't understand how javascript came to be, I would be suggesting that javascript must be the best language!


From my experience having to debug and fix up / change things in old go codebases, it's an absolute nightmare.

The lack of abstractions often force you to read a lot of code you don't care about.

The language is so simple that reading complex code is actually hard.


When Ruby was "hot", it was bringing a lot of new things to the table, things new developers take for granted now.

If you start a new project in typescript, or even C#, you'll get almost all of the things that made Ruby great in 2006.

When I introduce a new developer to Ruby, all I've got to argue in favour of it is that it's a beautifully designed and powerfully expressive language with a library ecosystem chock full of de-facto standardised gems. Relatively vague things, and any newbie can hit me back with its downsides: mediocre performance, no type definitions, and no evented I/O baked into the language.

I do dread the day that I can't start a new project in Ruby, simply because my hiring pool would turn into a mire of people dreading to work on it.


> mediocre performance, no type definitions, and no evented I/O baked into the language

Ruby 3 addresses each of those issues.

https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-rele...


Definitely interesting new features, and Ruby is putting up a good fight. But if it was really a ruby feature, and not just something tacked on to stay relevant, that code example would've looked like this:

    require 'async'
    require 'net/http'
    require 'uri'

    ["ruby", "rails", "async"].each.parallel do |topic|
      Net::HTTP.get(URI "https://www.google.com/search?q=#{topic}")
    end
I can't tell someone Ruby is beautiful, and then in the next sentence explain how you need to type Async twice just to get something to run asynchronously.

Same of course for Ruby types, we're just not yet on the point for a truly new way of writing Ruby for Ruby 3. Maybe we'll finally get something like this could be in Ruby 4, but I fear the spectre of backwards incompatibility is going to stand in the way of something that's both truly Ruby and truly in the 2020's.


Amen. As a massive ruby fan, I couldn’t put a finger on why I disliked ruby async, but you’ve got it exactly right.


I think the main problem with ruby is that JS has Google v8's performance behind it. Good luck matching that.

Then, if we're talking rails (which is a significant part of the ruby projects out there), there is way too much magic going on.

Magic you have to manually un-peel when something goes wrong.


Actually no.

The way Ruby looks like, it was done in Smalltalk first, with performance, good graphical tooling and developer experience.

If you mean Rails, Zope, AOLServer and Vignette did it first.


I'm sorry, no. Everyone knows that before Rails there were only three ways to make a web application. You could do it in either PHP, in Java servlets or in ASP.Net. Ok and maybe ColdFusion MX.


Only for souls that only started to do web development after 2002, and never learned about what the world was about between 1994 and 2002.

I can gladly educate you on how Rails did not improve on the stacks already available, rather bring the concepts to a younger generation that never learned about them in first place, starting with ActiveRecord.


Could you go back and tell 17yr old me know that there's something better than ASP.Net out there? I was doing .Net trying to dodge the Microsoft stack running early versions of Mono and everything, anything to dodge PHP and Java.

I'll gladly receive that education, I have a hard time believing any of those frameworks are as sophisticated today as Rails 2.0 was back in the day.


You didn't look hard enough, companies like https://www.altitude.com and https://www.outsystems.com were built out of my and others experience with those frameworks.

I could tell how they looked like from startup rooms in little offices spaces in Lisbon back in the early days of .com wave in late 90's, how AOLServer influenced the creation of Intervento's Safelayer framework, or how it got us to be approached by MSFT Portugal for adapting the same ideas to then still alpha version of .NET, however I am the right person to fully tell the story, better let that to the key persons, in case they feel like jumping in.

In any case, here is some education material for yourself,

https://zope.readthedocs.io/en/latest/zopebook/index.html

https://docs.huihoo.com/aolserver/intro/features.html

https://www.linuxjournal.com/article/6164

https://github.com/aolserver/aolserver


I think you have this backwards. Go is explicitly optimized for software engineering; in fact, it's the only language I'm aware of that makes large-scale engineering its north star. Here's Rob Pike discussing how Go's design decisions make building and maintaining large programs easier: https://talks.golang.org/2012/splash.article (AFAICT, Rust was not named after "collecting Rust," and long-term maintenance is not one of its primary design goals.)

As an example, one celebrated feature of Go is that "all Go programs looks familiar," i.e. it's easier to get oriented in an unfamiliar Go codebase than just about any other mainstream language. Partly this is due to `gofmt`, but also the fact that the language itself is relatively spartan, with few dark corners. It's an "unsophisticated" language, which obviously cuts both ways.

Rust, by comparison, is a highly complex language. It allows for very powerful abstractions -- as well as very bespoke and "clever" constructs. I think Rust will develop a solid reputation for correctness, much like Haskell; Rust programs will run for many years without bugs or performance issues. But, again like Haskell, Rust will also have a reputation for allowing clever programmers to write too-clever code. That's why Go will prove to be the more maintainable language: because it intentionally limits expressiveness (a highly unpopular decision, unsurprisingly) and thereby limits the amount of "damage" any given programmer can do.


Go inevitably results in a very large codebase for a given piece of functionality, especially if it’s used alongside Google’s companion projects such as protobufs and grpc. Lack of generics means that it is impossible to generalize over related types, leading to duplicated code, and in some cases, crazy hacks like serializing a struct, passing it through the generic part of the code and then deserializing it again when you need to use it.

Other choices such as structs being initialized with “zero values” in their fields (instead of having a compile error when you forget a field), and the complicated sometimes equivalence of zero values and null create a lot of footguns when refactoring.

Go’s strength is a batteries included stdlib and its looseness can make prototyping faster. But it feels very much like an old school scripting language like php or js, where you have to use countless trivial unit tests to have any confidence about what your code is doing.


> [Go]'s the only language I'm aware of that makes large-scale engineering its north star.

Ada, Eiffel, Java, Pascal and derivatives, C#, Rust. Probably many others but I'd argue outside of tooling (which Go is particularly good at and has done an incredible job of standardizing, Rust being a peer in that regard with cargo) these languages are as good or better than Go for software engineering.


By "north star" I mean the guiding principle that other aspects are sacrificed for. A heuristic might be: "[Lang] would not be [lang] without [aspect]."

I'm sure that the Rust team wants Rust to be a good language for large-scale engineering, but it's not their north star; "fearless concurrency" is probably the closest. For example, Rust is willing to sacrifice simple syntax and fast compile times to achieve more safety; Go is not.

I don't know enough about the other languages to speak confidently about them, but if you can point me to any source materials (i.e. articles or talks by the language creators) that discuss large-scale engineering, I'd be interested to read them!


https://www.amazon.com/Eiffel-Language-PRENTICE-HALL-OBJECT-...

> Quickly emerging as the language of choice for developers of quality software, this guide explains how the Eiffel language combines rigorous software engineering principles with advanced object-oriented techniques. It reveals the simplicity, consistency, and blend of various powerful mechanisms in Eiffel, including: an object-oriented structure based on classes ; multiple and repeated inheritance information hiding assertions to guarantee, document, and test the correctness of software components; strong typing backed by support for generic classes; dynamic binding a highly dynamic run-time model supporting garbage collection renaming and redefinition facilities . . . disciplined exception handling and support for persistent objects. As both an implementation language and a high-level notation for analysis and design, Eiffel emphasizes the industrial production of reusable software components. Written for software designers, analysts, and programmers.

https://www.eiffel.com/


> it's not their north star; "fearless concurrency" is probably the closest.

That's just a more recent slogan to succinctly express what their real north star means. Their real north star is "safety and correctness", and like all languages, they push to make the most important thing to them easy and approachable.

Here's the thing, I'm not sure as a project saying your focus is large scale engineering and pushing towards that actually gets you closer to the desired result in the end than pushing for safety and correctness instead. I could fully see a language that pushes for safety and correctness eventually being a much better and easier to use choice when evaluating with respect to large scale engineering, because those are extremely important to large scale engineering.


Safety and correctness certainly are important -- but they're also orthogonal to maintainability (among other values)!

It's good to have most of the core values in common, but a language's guiding principle manifests in many small ways that can be very compelling in aggregate. Go's weird capital-letter namespace visibility rule is a great example of this: it has nothing to do with safety or correctness, but it's enormously helpful for getting your bearings in unfamiliar code, because it localizes an important piece of information, saving you a context-switch. Sure, another language might hit upon this feature incidentally (Rust has conventions around capitalization, and IIRC Haskell enforces it to some degree), but how many languages will chance upon all of the little things that make for a great engineering language?


I keep writing poor tutorials (due to space) of Ada here. Check out https://learn.adacore.com/ for more.

Overall I like Go, but for software engineering in the large Ada, in contrast to Go, has:

Explicit separation of specification and implementation of packages and types making it easier to shard the work out to numerous individuals and teams.

What a package exports is explicit, not the result of case conventions.

  package Foo is
    procedure Bar(N : in Integer); -- exported
  private
    procedure Baz(N : out Integer); -- unexported
  end Foo;

  package body Foo is
    -- implementations of the above
  end Foo;
Generics from day 1, which enabled a set of collection packages similar to C++'s STL in Ada 2005 among other things.

Tasks, similar to Go's goroutines, but have a lot of additional guarantees and behaviors that have to be made explicit in Go.

Protected objects and protected types which permit you to write code without explicitly acquiring/releases mutexes and using condition variables.

Design-by-contract with SPARK/Ada becoming a proper subset of Ada in Ada 2012.


> but they're also orthogonal to maintainability

Not entirely. Some amount of maintainability is fixing mistakes that result in less correct or safe programs. By reducing occurrences of these classes of problems later, you're reducing the maintainability burden.

It's the same thing that makes a language with a type system more maintainable in the long run. Eliminating classes of errors pays dividends later. The decision to make is whether the extra effort at the time of creation is worth that reduction. Depending on the type of software, it's expected lifetime, and how many people are expected to use it, that may differ. For large scale engineering, I imagine the extra effort required up front is almost always worth it.


Rust was explicitly designed from the beginning for creating maintainable large-scale software.

Here's the original elevator pitch from 2010:

https://github.com/rust-lang/rust/blob/d6b7c96c3eb29b9244ece...

Note the text about "programming in the large".


Eiffel might be another.


I don't know much about Eiffel; do you know of any articles or talks that discuss its design tradeoffs?


Eiffel's bigger contributions are probably:

Design-by-contract. The contracts aren't just comments, they aren't haphazardly enforced by adding asserts to the code. They're explicit parts of the language which allows for a lot of interesting consequences when utilized. Testing can be semi-automated directly from the code, some elements of the program design can be proved to be satisfied statically without the need for compilation and execution. The ability to encode your specification into the language is incredibly useful.

Command-query separation. If methods return a value (queries) they should be referentially transparent, having no side effects. This is a principle so not an explicit language feature, but it can be enforced using DbC.


> Go is explicitly optimized for software engineering;

There's nothing to back up this claim. Using golang in practice shows otherwise. The mess resulting in large code bases is much more difficult to deal with compared to Java for instance.


I predict exactly the opposite.

Baking ownership into the type system makes API design and refactoring hard, while having GC makes memory management entirely orthogonal and easy to change. Go is already over 10 years old and designed by people who have worked on software for 30, sometimes 40, years. Go changes slowly and Rust is still evolving.


> and refactoring hard

The opposite, it makes refactoring really easy, because it's so hard to screw up mechanical changes.

The memory management aspect of refactoring is slightly more tedius in rust (compared to go), because you have to update lifetime annotations sometimes. This is a mechanical process and not hard. The trade off is that the existence of lifetimes and ownerships means that many of the rest of refactoring tasks (getting locks right, not introducing data races, making sure you're not doing something dumb like accessing a freed fd, etc) are much simpler.

Rust is also better than go at refactoring because go's ducktyping (and reflection) means that there is frequently action at a distance that is hard to track down. Changing the name of a field of a struct can change behavior in another file that never mentions the field by name.

Go is in the middle of adding generics to the language, I don't think Rust has made a change of that magnitude since it hit 1.0...


> The memory management aspect of refactoring is slightly more tedius in rust (compared to go), because you have to update lifetime annotations sometimes.

It is much more complicated. You sometimes have to implement clone, pin/project, box etc to satisfy new trait bounds for example. Also, build times can make refactoring and iterating really painful.

I like and use both languages; I think they are complimentary, and I think things need to be weighted more honestly than what I see in this discussion.


I am by no means a Golang developer, so don't construe my OP to be a particular endorsement of Go. But after 25 years writing C/C++, Java, Javascript, and working on language implementations, garbage collectors, JITs, VMs--what most people consider "system software"--I feel strongly that requiring programmers to reason about ownership for memory management is a complete waste of everyone's time. It's more mental load than programmers should not be burdened with, no matter how good the tools for it are. The performance costs of GC are routinely overstated by C/C++/Rust advocates to the point that GC implementation experts have pretty much become cut off from the conversation. No one really measures properly, anyway.

My honest opinion is that it is 2021 and it's about time we let computers manage memory already.

Rust can have their ownership for race conditions if they want, but I am so tired of being gaslighted about how important it is that I be hounded to track every solitary byte of memory when I am busy thinking about more important things.


> I feel strongly that requiring programmers to reason about ownership for memory management is a complete waste of everyone's time. It's more mental load than programmers should not be burdened with, no matter how good the tools for it are.

On the contrary, ownership tracking is important for general code correctness, not just memory management. It's practically impossible to audit and assess correctness of a program with pervasive confusion in the overall patterns of what code owns what data. Memory safety is also important of course, but it's mere table stakes.


I agree, ownership is an important idea on its own. So I wish more mainstream gc languages would expose some kind of optional ownership idea. Such as ability to "give" a collection to another collection contructor, which then would not have to do a boilerplatey/inefficient "safe-copy" in the contructor. Maybe that opens a can of worms and can't be easily retrofitted into existing languages, I don't know, but I'd like to see it tried.


This is why this subject is hard to talk about. I fully agree that humans shouldn't have to care about memory management! That's why Rust is so important: the compiler thinks about it so that I don't have to. People can even agree on the main points and completely disagree on the conclusions.


Unfortunately the space is littered with confounding variables. For example, just measuring the impact of GC overhead is bound to be tricky, because a trashy program (one that allocates a lot of garbage) is going to make GC look bad in comparison to a program that is careful to reuse data structures. And that's mostly because of the second-order effects of the memory hierarchy, and not so much about the raw cost of allocation or deallocation! A lot of language library choices contribute to trashiness; e.g. in Java it is very difficult to avoid making lots garbage if you use essentially any of the JDK. You can't even parse integers or strings effectively without multiple copies. I really don't know how Go's libraries look in that regard, but the truism generally holds that the more bullet-proof you try to make APIs, the more defensive copies you end up making.

Is the antidote to those inefficiencies an ownership model that forces you to reason about mutability? I don't know. I kind of think no, primarily that it is a performance consideration that infects the API and spreads everywhere; it's a distraction. Is it instead to have all immutable data structures and an insanely smart compiler that replaces copying with in-place mutation, so that pure functional languages compete with highly tuned, pervasively mutable code? I kind of also think, no. And primarily that's because performance cliffs get worse and harder to predict, the smarter your compiler is.

The mutability/ownership question is confounded with allocation and deallocation. The latter really should never be on any programmer's mind, IMHO. In Rust, it seems there isn't much support for decoupling the two, e.g. by having an automatic garbage collector. That's also an unfortunate reality forced on language implementers by the fact that LLVM has steadfastly refused to support stackmaps as a first class concept for more than 15 years. Many, many projects have died because of LLVM's stackmap support being lacking or broken. That's unfortunate because precise stackmaps are a key enabler for many GC techniques, and without them, you end up with some form of conservatism that make certain optimizations impossible, and forces a particular design for nurseries.


Yeah, you have to get into all of these details to have a productive conversation. Likewise, I don't actually think a lot of this inherently has to do with performance, basically, I could make a similarly lengthy comment about how

> I kind of think no, primarily that it is a performance consideration that infects the API and spreads everywhere; it's a distraction.

is something I fundamentally disagree with; unfortunately, I don't really have the time at this moment to even get it into the level that you have here, but it's a good conversation to have, and a needed level of details to even have a good conversation.


Seconding the disagreement with the idea that mutability tracking is a distraction. I would give anything to have true deep-immutability enforced by TypeScript, but unfortunately the language semantics make it virtually impossible. In Rust, it might be my favorite feature.


Interesting. We definitely should have this conversation in the proper detail, because my estimates of Rust's language design priorities must be off.


>For example, just measuring the impact of GC overhead is bound to be tricky, because a trashy program (one that allocates a lot of garbage) is going to make GC look bad in comparison to a program that is careful to reuse data structures.

This is completely irrelevant because stop the world pauses are global and affect your entire application no matter how careful you write your code. Every library you use has to be carefully written, every single line of code you write has to be carefully written regardless of whether it is time critical or not, this is a complete dead weight for the entire application.

With isolated GC heaps your time critical code will be isolated from non critical code. In practice the easiest way to do this is to just launch a separate application. This hurts a lot with the JVM because it wants to own your entire server (mostly RAM) for some inexplicable reason and you might as well write that part in C++ if you do inter process communication anyway.


Thing is, in order to have pervasive reuse of data structures (mitigating the overhead of GC) while maintaining safety and correctness, you have to track uniqueness and mutability throughout the program. At that point, you've got something that's practically indistinguishable from borrowck.

The real use case for GC is managing data where there's no well-defined "ownership" pattern, such as when dealing with general graphs (e.g. in a symbolic computing or GOFAI application). That's a remarkably niche domain.


I don't write software at fang scale and I've been bitten by GC pauses in other languages. Even when it doesn't cause issues, you can see it in the response times charts.

Not having to worry about that is very nice. Using less memory, I agree it's not terribly important but it is a nice bonus - which comes in handy when working on embedded, videogames or in constrained conditions (like when you can put a lower limit to your containers and run more containers on the same machine).


My main objection to this take is that ownership is about far more than just memory management.

Garbage collection lets you avoid memory leaks, double-free, use-after-free, and that's it. In Go, it's up to you to correctly handle every other type of resource correctly, as the compiler won't offer you any help.

An ownership system like Rust's is a general-purpose tool that handles all kinds of resource management. File descriptors, database transactions, session types, locks, etc.

People praise Go's channels, but Go channels are way more complicated to use correctly, and part of that is due to ambient ownership (the other part is due to bad error handling). You need to manually keep separate track of how many outstanding writers there are are, and then explicitly close the channel. In Rust, the channel is closed when all senders or all receivers are dropped. I don't have to do anything, and it's always as correct as what I'd have to implement and maintain myself in Go.

Another great example is how Rust's mutex can own the guarded value. In most languages, a mutex is a separate object, and it's up to you to be careful to make sure you never access it without acquiring the mutex first, to always release after the last use of the guarded value, and to never keep a reference to the guarded value after releasing the mutex.

With Rust, the ownership system is used to handle and verify all of that, so I do less work, have less to think about it, and can't make those mistakes. The Mutex owns the value. Mutex::lock() and ::try_lock() return a guard that you dereference to access the protected value. The mutex is released when the guard is dropped. The guard borrows from the mutex, so any attempt to keep it around longer than you have access to the mutex is flagged by the compiler.

My honest opinion is that it is 2021 and it's about time we let computers manage all of our resources, instead of only memory.

Addressing the last part of your comment, that doesn't sound like my experiences writing Rust at all. Regarding memory management and ownership, the majority of the code I write in Rust, I just type the obvious thing and it just works. The majority of the remainder, the compiler points out that I've done something dumb, and it's a trivial fix. The rest of the time, I'm trying to do something genuinely complicated, and the compiler helps me figure out and verify the work in pieces, rather than trying to cram the whole thing in my head at once, and then convince myself that it's correct. When I'm finished, I feel confident that the compiler will catch errors introduced by future maintenance and refactoring, rather than having to cram it all back into my brain at once every time I touch the code.

To me, in both Rust and Go, the trivial cases are trivial. For more-interesting cases, Rust lets me just do the thing and focus on thinking about my problem at a higher level while trusting that the compiler will handle the details. For more-interesting cases with Go, I have to keep track of a bunch of little details and make sure I explicitly clean up every little resource I ever interact with.


Having said all of that, I do agree that there are many programs where Rust's defaults don't add a lot of value, and it would be nice to have access to shared garbage-collected data without the syntax overhead of Arc<Mutex<T>> or crossbeam_epoch.

I really like the discussion on resource types vs data types in this essay on higher-level rust-inspired languages: https://without.boats/blog/revisiting-a-smaller-rust/


This has been solved since Common Lisp using resource managment macros and similar approaches used by modern lacks.

What Go defer lacks, is the ability like e.g. .NET with IDispose, where I can make of Roslyn Analyzers to break builds when I forget to call using on such resources.

Rust is a good option for kernel code and drivers, beyond that there is no point in throwing away the productivity of having a GC around.


You could have your cake and eat it too if languages with multiple GC heaps had become popular, as it is right now 99% of programming languages have one global heap and that means global pauses from which you cannot escape from. A lot of the time when someone wants to write real time code they just want that tiny little nugget to run without the GC, usually it can be confined to a single thread or maybe a separate pool of threads each with their own heaps while the rest of the application happily uses a global heap.

The fact that you haven't mentioned these low hanging fruit makes me feel like you haven't thought your argument through. You're advocating for a half baked solution even though there is a perfect solution that almost nobody tapped into that would make the GC superior almost everywhere. That's why you are wrong and why nobody should listen to you and people should listen to the creators of Erlang and Ponylang instead.


> My honest opinion is that it is 2021 and it's about time we let computers manage memory already.

In the field where I am working (realtime audio), that is just not possible. I don't want to have a garbage collector pause in the audio thread. In fact, I can't do any dynamic memory allocations at all (without a special realtime memory allocator). Other fields, like medical devices, flight control, embedded systems, etc. have even tighter constraints.

Manual memory management is not only about performance, but also about predictability. This kind of low level control is one of the main reasons why people use C/C++ in the first place.


> Changing the name of a field of a struct can change behavior in another file that never mentions the field by name.

I don’t code in go so this looked surprising to me. TypeScript has a similar feature regarding types, and it will tell you if you change a field in a record, and that record is actually used in a place where another record with the same fields is asked for.

Kind of surprised go has this problem.


Difference cause of a similar issue. A fair bit of go code relies on reflection to list the fields of a struct and decide what to do, so e.g. if you change the name of a field in a struct and you happened to be serializing the struct somewhere else the serialization will change even though nothing near to the name change suggested that the struct was ever being serialized in the first place.

Apart from serialization I've also seen this with ORMs, and some of internal code for metrics. I imagine there are other cases too... but while I currently work in go I'm not really that much of an expert in the language.


And in what aspect is Go a better than the million other language with GC? Like, it is C level bad at expressivity, way too verbose because hardly any abstraction can be made there. Concurrency is the only thing going for it.

But how is it any better than Java or C#?

And Rust is a low level language, so it has to get away with rare cases where a GC is not applicable. And being low level of course imposes the memory layout of the program on APIs as well, but that is a known trade off when one goes low level.


If your opinion is as simple as “Go will be more better than Rust”, or the opposite, it is far too simple to be correct.

Rust is unbeatable for services you want to deploy, stabilize, and forget about forever.

Go is pretty darn good for building out complicated/messy services in an iterative process.


Go is the optimal language for a company that wants one (or more) microservice per engineer. It's a great language for padding out bulletpoints for a promo packet.


> Rust is unbeatable for services you want to deploy, stabilize, and forget about forever.

Erlang.


More expensive, and not always necessary. But great point.


You will never have a stabilized system unless you are multinode. Hardware will fail. Rust is not good at this.


GC and tracking ownership are orthogonal; the lifetimes of GC references and normal references would be different, but rust could perfectly well have a GC by default


It could, but it won't. If we're talking about real-world use, this makes all the difference.

C or C++ could have a GC as well (in fact, they do - you can use Boehm for any C or C++ program), but there are approximately 0 programs that do.


C++/CLI, C++/CX and Unreal C++ are example of C++ programs that do use some form of GC, just not Boehm.


I didn't know about Unreal C++ using a GC, but the others have extremely little use. So little, that C++/CLR (at the time) had a bug for at least 2 years where doing something like initializing a CLR List (CLR, not std::) with an initializer list (I have forgotten the exact syntax, but it is similar to `auto lst = new List<int>{a, b}`) would allocate millions of elements on the heap (if I remember correctly, it would create a List of size 0xC0FFEE, or maybe it was 0xDEADBEEF - either way, obvious debug code, then set list[0]=a and list[1]=b).


> I think Go is in a honeymoon phase and people will hate it in 10 years; ..

I wrote some Go code for talking LDAPs and doing some CRUD Ops. Do I love this code? Nope. Do I love the product that I built? Very Much.

I think love of language is somehow very much a Rust thing at least compared to Go.

> Rust on the other hand is optimized for maintaining

This seems to be a tall claim. So often in Rust some or other library, web framework goes defunct or abandoned. And they are not exactly in finished state so no maintenance is required. Same thing happens with other languages too. But Rust is quite young, even then we have abandoned projects. In 10 years I am not sure how Rust codebases will be more maintained not less. Now one can say maintenance point is about commercial projects where people are paid to maintain. Still then not sure how loved it would be by maintainers when original developers are long gone.


I have to disagree with this. I'd even argue that the direct opposite is the case: Go is so conservative in it's decisions, it's hard to find a project from years ago which doesn't "just work" with `go run`. The syntax and semantics are very simple and tend not to change much/haven't really changed since the initial release, which is definitely not the case with Rust, where stuff moves really quickly (not a bad thing by definition, but IMHO not the best for maintaining an already existing project)


> it's hard to find a project from years ago which doesn't "just work" with `go run`

That's not been my experience. On a team I was on, even code from six months prior would sometimes be difficult to compile. They keep changing how GOPRIVATE works, or how modules work, or how vendoring works with modules.


Rust takes backwards compatibility very seriously; if you ever come across a Rust project that doesn't build with the latest compiler, please file a bug.


I think that is true regarding language popularity—but not their viability for intended purpose.

Perl is a great example because although it has its quirks and the ecosystem shows some age, there really isn’t anything like Perl. It is a very good language for interacting in the console and with data of many types. It’s $_ variable which is based on implied context (much like in language we short-form speech when context is implied). Those are features something like rust (or go) simply isn’t designed for.

Hell, people still use and enjoy programming in C or Basic or Pascal. They just aren’t “popular” because developers are eager to put their comp-sci to use and invent more languages :)


Go thinks that having a simple language, one way to do a thing, standard formatting, low boilerplate, and coupling minimised using interfaces and explicit exports all adds up to maintainability. Time will tell if it's right.


Two of those in particular are what the overwhelming majority of detractors find issue with.

A “simple” language frequently offloads more work onto its users. In my experience with golang, this is true. Meaningful abstraction is punished or impossible, so every solution to every problem—no matter how many times it’s been solved before—becomes a computer science exercise where every detail has to be dealt with and remains on full display. Reading golang is a chore because you can’t zoom out and look at the high-level flow, it’s only low-level minutiae at every level of the code. It’d be like an architect having to write the molecular layout of a skyscraper into the blueprints. Chemical formulae everywhere but no picture of walls, floors, or a building anywhere to be found.

Second, claiming golang has “low boilerplate” is the programming language equivalent of Stockholm syndrome. Look up any popular project. Something like fifty percent is

    if res, err := func(…); err != nil {
        return nil, fmt.Errorf(“Look ma, I’m a human exception handler: %w”, err)
    }
That’s not an exaggeration. 50% seems to be the trend from the projects I’ve sampled. It actually makes it frustratingly difficult to follow what a function is supposed to do because the logic is lost in a sea of nearly-identical error handling. Spotting a bug in one stanza of code that’s in a sequence of nearly-identical visual blocks is hard because your brain starts glossing over the details that are repeated.


I wish there was a standard one-liner pattern to handle errors, that would improve it a bit visually.

Go has a LOT of boilerplate. And that is why I love it. No magic. No implicit behavior. No weird stuff that will bite me if I don't know that something in a completely unrelated file is changing the behavior of my code.

It allows me to write high quality code and care about all the millions of details I should be thinking about.

Yes, 50% of go code is about handling specific cases and errors. And that's a good thing, because unexpected cases and error handling is 50% of the work that a developer should be doing. But often it is just neglected or difficult to spot in other languages (until it bites you).


I guess I should explain why I think Go has low boilerplate. It does have "explicit everything" and I love that too. Also no "spooky action at a distance", like redefined operators. Things do what they say and say what they mean.

What it doesn't have is a lot of noise basically intended to keep the compiler happy, or implement common indirection patterns. Types are generally simple and can often be omitted. It's not traditional OO, so a lot of needless abstraction can be skipped. Complying with interfaces just means providing the required methods. Go code compared with the equivalent C or Java is denser.

For what it's worth there was an attempt at improving errors, which would have added a keyword that means "do this, or if it fails return the error result in this function's error result". I liked that idea. I'm not sure why it wasn't well received, but they evidently have that on their to-do list.


There was this wonderful 6-8 year period after every thread on programming stopped being dominated by Ruby advocacy and before it started up with Rust.

Why cram a Rust advocacy soundbite into a thread about maintenance vs. prototyping?


Coincidentally it's all those Ruby people who are high profile Rust people.


I don’t know that people love ada and it was designed with the same goals in mind.


I can confidently predict that both Go and Rust will be seen as the "old brown stuff" in not so many years and some hot new thing will have come along that everyone wants to build in.

Rust's main claim to fame - safe manual memory - is already being re-examined. There is definitely interest in and pursuit of a lower-boilerplate means of getting the same, and there are some candidates out there already.

Further, a language being successfully used by experts and popularized tends to precede an accumulation of low quality contributions that negate base improvements to maintenance. In due course, a popular Rust will become "enterprised" with an accretion of tooling and frameworks - although it might not look the same as "enterprise Java", it will have the same kinds of effects in creating barriers to entry and sucking the sense of "fun" out of the day-to-day workflow.

Lastly, the application categories will change. There will be demand for "glue" again, applications that are just frontends to library code(perhaps code written in Go or Rust). The new language will be something not systems-focused, and perhaps aim to be mostly focused on content and presentation (as HTML was in inception).


> There is definitely interest in and pursuit of a lower-boilerplate means of getting the same, and there are some candidates out there already.

What are some of those candidates?


Oh my, here we go again: The first post on a general language thread is bashing Go and hyping Rust ... that in itself is a very sad and problematic story as some inexperienced devs fall into the trap of this kind of promotion that Rust is the silver bullet for all kind of applications / projects. Rust has it's place. Go has it's place. Java has it's place. There's so much more than pure language feature for successful projects. The language is not even in the top 3.

But more importantly I disagree to your actual assessment:

Go code is very easy to read and understand. You're at the core of the problem at hand at once. No over abstractions or complex syntax or complex language features. Go has very few quirks (every language has them, people thinking "their" language is free of them are just being ignorant). I found very few real world issues caused by language quirks in Go production code (just as with Java or .NET).

Much more important for quality code are engineering decisions, structure and processes. As Go is easy to write, read and understand it leaves more mental capacity to those often underrated areas.

Go is a memory managed language. That alone makes it much easier to understand and maintain than every other language where you need to do it yourself. Again, more room for engineering decisions.

As Go has a very large and extremely useful standard lib you have much less issues with unmaintained third party libs. Imaging a large Rust codebase and all it's dependencies to one-person-maintained libs. A maintenance nightmare thinking 10 years ahead.

Just look at some good quality Go code, e.g. Hugo https://github.com/gohugoio/hugo/blob/master/navigation/menu... I've picked an arbitrary file. There might be issues in it, but look how easy to read and understand it is.

Regarding Rust: I have no general interest in talking bad about it, but need to make a point. Just as a real world reminder think of the Actix story. One part is the unsafe issue. How many people in the world would be able to understand the actual code and could have cleaned it up? Maybe 50? Fortunately there was a happy end. But how much time and energy did it take to get it on track again? What if Actix had not been the most popular and known framework?

All our companies Go servers (still mostly Java apps) are build with the standard lib. One thing less to worry about in the long run.


I feel the opposite way about Go. Reading other people's code is relatively easy but the tedium of writing it can be draining.


this sounds entirely like personal preference based on the projects you’ve worked with. all languages are capable of producing maintainable software. it’s much more about the authors skill than the language itself. yes statically typed languages scale better, but ide support on dynamic languages is still good. i don’t buy the “rust solves all problems” idea. that is the hype curve


For projects with a large number of contributors and long development time there will inevitably be some less maintainable code and that is where the quality of the language itself will become important.

No language solves all problems obviously, but clearly some are better than others in nthat regard. I have no experience in Rust but many years with Perl and Java (and others). Perl in the hands of a small, very experienced team had the highest productivity and quality I have seen - but I would not want use Perl in a project with higher developer churn and lots of inexperienced coders.


> Perl in the hands of a small, very experienced team had the highest productivity and quality I have seen - but I would not want use Perl in a project with higher developer churn and lots of inexperienced coders.

This has been my experience as well.

I think that's why "medium powered" languages such as Python and Java tend to get the widest adoption over time. They are less expressive but also have fewer gotchas, and in a team of 100s or 1000s of good-but-not-stellar developers who come and go, they end up being the least painful for the organization.


In discussions about programming languages, you have to always remember to add "equally"/"to the same degree" to statements such as this one:

> all languages are capable of producing maintainable software

Once you add that, you understand what the original poster actually meant.


I agree that it is possible to write maintainable code in any language and it is possible to make a mess in any language too. But some languages to some extent trying to force this, which may move an average project, even if only a little, to more maintainable shape.

Examples of such languages are Go and Python: both to some extent enforce code formatting - Python with indentation being part of the syntax, Go with gofmt being almost universally used tool. Both try to maintain one preferred way to do things - opposite to "There's more than one way to do it" in Perl.


Rust doesn't add anything that increases maintainability beyond memory safety. This is nice, but it's not even 1% of what maintenance work looks like. Maintaining a decades old code base means adding features without blowing up the beast. This involves: (1) digging through the code to find the area that does something close to the new feature, (2) trying to understand what is going on, (3) figuring out the style of it for conformity, and (4) slapping that bad boy in.

Of these, (4) is by far the easiest part and the only one Rust will help you in. The digging for understanding is far more time consuming. The other parts require art, discipline, and linters.


Yes, for example this week I had to uncover a bug why a backend was occasionally delivering duplicated database rows to a frontend, in code I hadn't written. I couldn't replicate the problem in test, or in dev, it was only in prod and stage (because the data in stage and prod was the right shape to trigger a UB wontfix in the postgres query optimizer).

Rust would not be friendly towards producing a RCA on this issue.


I'm going to be the heretic and predict the opposite about Go and Rust. The reason is that Rust is overengineered, allows for macros, and is getting more and more complicated all the time. It's going to be as complicated as C++ in 10 years from now. Go is kept simple, the team is reluctant to introduce large changes, and it was from the beginning planned as an "easier C" with automatic memory management.

I'd also like to challenge the idea that Rust is optimized for maintaining. It's optimized for backwards compatibility. IMHO Ada is way better for long-term maintainability and in that respect beats every other language I know.


That's actually a great point about macros. I have extremely mixed feelings about Rust's macros, but one of those feelings is that if anything is going to compromise its status as "the maintainable language" down the line, macros are the most likely.


That's also my impression about CommonLisp, which I otherwise like a lot. Macros are really handy but in the long run they force new programmers to learn DSLs forever. The same for templates, of course. They increase programmer comfort but decrease long-term maintainability. It's always a trade-off.


> in the long run they force new programmers to learn DSLs forever.

but... that's a good thing. programs should be built as a collection of small DSLs tailored to the specific tasks of that program


You think macros are overly complicated? Have you looked at how people use C++ templates?


He just presented C++ as being another over-complicated language :-)


> it's right there in the name: software should be allowed to become old and "collect rust"

Of course, names or intentions of things don’t really determine their quality, or we’d all be running our software on the alpha processor, namely the DEC Alpha. My pedantic comment is worth about as much, but might be interesting to some:

Rust isn’t named after iron oxide, it’s named after fungus[0][1][2].

[0] https://stackoverflow.com/questions/16494822/why-is-it-calle...

[1] https://en.wikipedia.org/wiki/Rust_(fungus)

[2] https://www.reddit.com/r/rust/comments/27jvdt/internet_archa...


Go is great for maintenance. It's actually annoying sometimes to build.


>> I think Go is in a honeymoon phase and people will hate it in 10 years;

>> Rust on the other hand is optimized for maintaining

How come this post isn't flagged? Crazy ... How can someone more aggressively start a language flame war?

These kind of posts of an individual are the reason for the bad reputation of the Rust community.

Looking at the facts regarding the industrial usage and growth of Go and Rust in the real world one can only conclude that Go's honeymoon hasn't started yet.

There are so many reason why Go is much more likely to be maintainable 10 years from now:

- easier language

- massive standard lib

- professional maintainers at google

- garbage collector

- much, much more devs available

- very sensible maintainers to keep Go stable

- much more mature despite being not that much older

- ...


It doesn't seem to me that Rust and Go are really trying to solve the same problems and they don't appeal to the same demographic. The Rust vs Go conversation is tired and pretty much pointless, and I've avoided Rust simply because of the Rust community, which emanates a vibe that turns me off. I think the weight of software that is written in Go means it's going to be around a while (K8s / Docker / Terraform / etc) and I hope it stays because it feels like a breath of fresh air to me and I enjoy working with it.


Yes.

The Rust users seem to be spending all their time making Rust vs Go posts on the internet instead of making something killer enough to get people to use Rust.


I don’t know, of course, but I have a different sense of where Go will be if it survives generics. The lack of change will mean it’s reliable, it was never as pretty as some other things, and it doesn’t go too far out of its niche. A lot of languages that suffer past the honeymoon, it isn’t survival of the fittest, it’s just evolving bloat or ending up with vestigial organs - this is hard to get on board with for new developers.


Go was in the honeymoon phase between 2013-2016. Considering how much unnecessary attention Rust gets in this forum despite being a terrible language to learn would suggest that Rust is the language currently in the honeymoon phase.

It's Rust that carries Ruby's and Scala's legacy of putting everything into the language. There's no forethought if it's a kitchen sink


I don't know about Ruby, but saying Scala and Rust put everything into the language is just totally incorrect. Both are designed with philosophy of building minimal set of features with very strong expressivity. For example Scala 3 removed a lot from the language and unified many features.

As for Rust. Is there inheritance in Rust? No. Overloading? No. Global or static (like Java static) variables? No. GC? No. Exceptions as the main error handling feature? No. N ways of casting to a different type? No. 5 or 6 ways of building dataclasses like in Python? No. 20 ways of packaging / building a project? Again - nope. I think this is already enough to say they didn't put everything into the language, and they are actually very careful not to introduce unnecessary features.

Actually I find Rust quite small, compared to e.g. Java or C++, but it has much better expressivity.


I've lost count of the number of times people have said that about a new language that has since fallen out of favour.


>Rust on the other hand is optimized for maintaining (it's right there in the name: software should be allowed to become old and "collect rust").

I think the name Rust is rather a pun because it was designed to be "close to the metal".


It's had various adjacent meanings over the years (and I may have embellished a little bit in my original interpretation), but here's one explanation which isn't far off: https://tim.dreamwidth.org/1784423.html

> Also, calling Rust a research language is funny to me because -- as its name reflects -- we've tried hard to avoid incorporating new technology into it. We haven't always succeeded at failing to be novel, but we have a rule of thumb of not including any ideas in the language that are new as of the past ten years of programming language research. The field of programming language is full of old technology that hasn't been put to use in solving problems that it's exactly suited for. The goals with Rust were to avoid reinventing wheels, and see what the past had to teach us.


> Rust on the other hand is optimized for maintaining

I completely DISAGREE with this statement!

I have already seen many year-old Rust projects fail to build due to changes to language, compiler and core libraries.


Out of curiosity, would you be able to provide concrete examples of those build failures?


Just try random project from github without using nightly, alternatively try a project from 2018 with a current rustc.

Specially the debian/Ubuntu Rust packages have hard time compiling many recent projects.


These two issues sound totally different, a 2018 project that doesn’t use nightly should absolutely compile today, unless there was a soundness issue. (And the vast majority of projects don’t use nightly features.)

The latter bit is the opposite, that is, old compilers can’t possibly know about new features, and that’s not a compatibility issue. That’s an older tool chain issue, or maybe a “community prefers newer tool chains than distros do” issue.


But how in gods name can you call a language "maintainable" if just compiling it after certain time requires some detective work to find the right rustc/cargo versions?

And that's only the first problem with maintaining old Rust projects. There are so many other issues, specially with projects created in very early Rust days.

Tell me, have you ever seen a go project failing due to similar issues? Python had this problem once (2 to 3) and they are still apologising for it.

(Not trying to start a language flame war. I like Rust and want it to succeed. But right now things are a bit chaotic)


I mean, it shouldn't! After some time, you'd be using a newer version. You want to be using an old rustc to compile a project created later in time. There are very very few languages that do not add new features over time. Even Go adds new standard library functionality or toolchain features in new releases.

The Python 2 to 3 situation is very different, that is about new versions not compiling old code. We go to great lengths to make sure that that works well in Rust.


That's some honeymoon! The wife is gonna be mad at me for taking the moon bit literally. It's been more than a decade now for Go. What honeymoon is this?

When I first saw Rust 1.0 spec, I made a mental note that "this will end in tears". (Do tears rust metal?) I made a similar prediction during Scala's honeymoon days: "This will be the JVM's C++".

Go will have a Java-lite career trajectory: it has a pretty wide sweet spot (in various dimensions) that more than compensate for its shortcomings.

The actual issue in this industry has been, and remains, the fact that it requires workers with above average intelligence that are tasked with building repetitive glorified book keeping applications. And in every programmer with a heart-beat's career, there comes a time when job boredom unconsciously lends a seductive glimmer to the shiny new thing. Java, Ruby, and Go all were in fact adopted because of the ambitious, smart, but bored, geeks decided they needed a brand new toy. (So taking your honeymoon metaphor, these trends are like mid-life crisis for programmers.)

And, compounding the issue is the fact that those minding the programmers were and remain (in the best cases) mostly behind the curve -- they're in meetings all day, after all -- and are simply not in a position to authoritatively smack down "let's use X!" enthusiasms. (In the general case, they are entirely clueless.)

Rust, like Scala, and Haskell, add an additional hook in that they offer the programming world's version of 'intellectual virtue signaling'. Case in point being your bon mot of "optimized for building".

Seriously, that's the actual job description for 99% of worker bees in this field: building things!

So, I'll make the prediction that Rust will go the way of Scala and Haskell, and there will come a brand new shiny and intellectually satisfying new thing and we'll have HN (in a typically forgetful fashion) dissing Rust and heaping praise on the new comer. This too shall pass.

[p.s. I have a self-contract to only post 1 message in a 24 hour period on the entire internet and this was it for tonight. /over & out]


> And, compounding the issue is the fact that those minding the programmers were and remain (in the best cases) mostly behind the curve -- they're in meetings all day, after all -- and are simply not in a position to authoritatively smack down "let's use X!" enthusiasms. (In the general case, they are entirely clueless.)

I don't think them smacking the "let's use x" is a good idea since it's the Devs who'll be writing the code.

The org needs a framework that answers: 1. How easy is it to train someone to use this stack? How long would it take for someone to start writing good code 2. How much time would it save us when building something new? 3. How easy is it for someone completely new to the codebase to start contributing?

1 and 2 can be easily measured within the org

You can use OSS as a proxy for 3


A big problem and reason why "brown" languages come to be dreaded is because very few software houses take code UX seriously.

I've worked on codebases built with UX in mind and codebases without, and it's a world of difference.

Code with UX has descriptive names, functions whose names intuitively describe what they do, using parameters that can't be accidentally misused. APIs are clearly delineated, domain edges clearly defined. Reading such code feels almost like reading a high level recipe, with the nitty gritty details available on demand using CMD-click. Weird edge case code is documented with a block comment explaining why it was done in this unexpected way. Nesting is minimal. Aptly named temp variables that only exist to aid readability are common.

And the irony of it all is that by eschewing code UX, you're mortgaging your future: making it progressively harder to maintain your codebase, and harder to bring new people up to speed. Changes take longer, and testing is more difficult as fewer and fewer people understand what it's doing.


Tenure in this field is short enough that most devs are renters, not owners, so the mortgage isn't your problem.

I suspect that drives a lot of the problems.


Everywhere I have worked has about the same average engineer tenure (between 1.5-2 years), but had massive differences in code quality.

Also, super-long-tenured engineers can be detrimental. There can be a tendency to not document anything when you can always just ask one of the oracles of knowledge that originally built it.

The wrong type of super-long-tenured engineer is just going to be defensive and full of excuses about why something was built one way, even when the pain of using what they built is dragging down the whole organization.

They will push back on anything new and choose to add incremental blobs of crap code to their existing pile of crap instead of breaking things down and using their learnings to help design the new system


> The wrong type of super-long-tenured engineer

Once you start thinking about the code in terms of memorization you’re a hazard to your coworkers. It’s one of the reasons I like to try to move about on projects.

When you built the code you had to think about two or three concepts at once. Then new functionality added another concern, and another, and another. For you, each addition was one more thing on a pile you already knew.

For someone new looking at that code, they have to now juggle ten things at once, so they either run away, or they learn by breaking things. Which the frustrated tenured person may use as confirmation bias about how all the new hires are worthless and we should only trust senior people. When really the entire situation is your fucking fault.


That's an interesting take- how long do you think it takes before an average tenure becomes detrimental? Honestly, I haven't worked in environments where you have people there for 10 years, and even 5 is a real rarity in my experience (I am getting close to doing this for 20 years now as well). Its much more common to have the average turnover be about 2 years, and in most places I have worked, it takes about that long before you start to get really good- at least to the point where someone asks you to make a change, and you can more or less visualize what changes need to be made in what places and have a very good idea of how long it will take.


> The wrong type of super-long-tenured engineer is just going to be defensive and full of excuses about why something was built one way, even when the pain of using what they built is dragging down the whole organization.

I'm pretty guilty of this. The way I see it, I can either tell someone now why things are, or I can let them waste time figuring it out for themselves.

If you stick around long enough, eventually you become partially responsible for a collection of projects built by people who came, did a passable job, then left. I'm not keen on spending months rewriting a system just because the current one has some issues. And if it needs a new feature/update, I have no problem tossing a turd on the pile of crap.

Granted, I see the appeal of rewriting things. You get to spend 12-18 months building a new project the way that you want it, then leave once it is built and the maintenance responsibilities kick in. These people have never had to actually maintain software before, so they have no idea how to even write maintainable software.


I get the problem with the guy who was there 20 years, but every project I have worked on has not made it to the end with the same engineers as those who started on the team.

They don't need to stay 20 years, but at least someone should still be there from beginning to end of a 5 year or even 2 year project.


> The wrong type of super-long-tenured engineer is just going to be defensive and full of excuses about why something was built one way, even when the pain of using what they built is dragging down the whole organization.

Haha. So true. Isn’t the adage you’re either changing or dying?


Not just developers but managers.

I still maintain that most of the legacy of the dot com boom bust cycle was not developers learning bad habits, but managers figuring out enough lines of bullshit they can tell people to string them along for 18-24 months and getting promoted or a new job after everyone figures out everything you said is empty (lies).

That’s IMO the root of the tech debt problem. Devs ate it up, but they were coached as well.


Yep. It was insane to me how often leadership of projects turned over when I graduated. I thought one person would shepherd it from start to completion (within reason) and that companies would incentivize this close management.

Not even close. Can easily have three people manage the same project in a two year period.


And you can't automatically assume that when the new person feeds you the same line as the last guy, that they're lying too.

That would be somewhere between stereotyping and pernicious pessimism, and at your tender age you don't want to think about yourself in either of those ways, so we'll wait to see if this person will actually deliver or not. Great route to burnout.


I don't understand it. It takes months to get even minimally productive and years to decades to grok your code base. You would think that companies would be dying to retain programmers and blacklisting anyone who leaves any company in less than five years.


Blacklisting sounds extreme.

Wouldn’t we also need to blacklist a company that loses a programmer before the five year mark?


You are right that blacklisting is too strong of a word. It would be enough to just look at early leaving like a resume gap. It won't stop you, but you will be asked about it. Have enough to show a pattern and you are essentially out.


Technically true, but quality control must be part of the leadership and culture if it is to mean anything. People come and go, but culture endures.


Can culture survive everyone being replaced?


Ever since I first started working as a developer, I've wanted to preach the idea that code UX is important.

Some issues I found: 1) It took me years to clearly specify what clean code is. 2) I still haven't learned to effectively articulate its importance. 3) Except maybe onboarding time, I don't know how to measure its importance. 4) Cleaning up code is not rewarded. 5) Writing dirty code is often rewarded with promotions.


> code UX

Agreed, the usability of tooling is important. Code is not just a tool to do a task, it is at once the tool and the communication to future developers.

Programmers, like anyone else passing through an educational system, self-select for strengths and avoid their weaknesses. Thinking is prized among programmers; thinking about how others think is most manifestly not prized.

There is also a demographic phenomenon. Each group rebels against something. (Parentheses, compilation time, memory management.) If the rebellion makes sense, it may result in progress. But to be well-designed, a rebellion must be consistent in its principles.

Safe code that still compiles and runs unchanged after decades is a measure of the real value of the design. Tooling that is partially or completely broken, or chasing faddish delights, is a sign of profoundly indifferent design.


I take this _very_ seriously but didn't have a name for it until now.

I totally agree that many/most software organizations don't take it seriously. But I don't think that it's because of a lack of desire, I think it's a lack of even knowing it's a thing.

I put my skills in writing clean code in my most recent performance review but I didn't do a good job of describing it. It's also not something that is apparent to higher ups, but is readily apparent to colleagues who describe the code as a "joy" to work with.

I think we need to get better as an industry at measuring "Code UX" in a quantified way, and then that can start to be a meaningful area of progress that engineers can use in their career, which will motivate them to improve on that metric.


I think the term that has been coined already is DevEx. We have definitely needed to think of it as a first class concern for a very long time.


1) Yes

2) Unfortunately solving the problem isn't as straightforward as it sounds, because notions like "intuitive" and "clear" are hard to define objectively. Explicitness, constraints, and simplicity are pretty objective. But intuitiveness has to be considered in relation to the current and future team (languages/idioms they're likely to have in their head, domain concepts and background knowledge they're likely to have, etc) and will always be imperfect. Of course we should still try, and as you point out, many people don't.


Here’s the thing. You don’t have to solve this stuff objectively. That’s a lovely long term goal but what you need right now is for the coworkers you already have to understand what a new bit of code is doing. And you can investigate that by running 1:1 usability studies. By pairing with them on using the new code.

Instead of jumping in every time they get stuck, make notes while they struggle a little bit. If they still don’t get it then intervene, acknowledge this seems to be more opaque than you hoped, bail them out, then take more notes about the interaction.

Maybe all you need is to switch to a synonym you mentioned in your explanation, or to homogenize argument order between some functions, or pluralize an argument as an affordance. Maybe you used jargon from a problem domain (eg, graph theory, linear algebra) and you need to think about whether you really expect everyone on the team to learn that jargon on top of everything else or maybe you should instead use terms from the requirements or application domain and leave the theoretical terms as comments in the code, or local variable names.

Or maybe your whole theory of organization is inside out and backward and you need a very different API that hides or telegraphs implementation details.


Could you recommend any open source projects which demonstrate good code UX as you describe? I would like to read through some such source code.


Not OP, but I would recommend backboneJS[1] or underscore[2]:

  [1]https://backbonejs.org/docs/backbone.html
  [2]https://underscorejs.org/docs/underscore-esm.html


The .NET framework is fantastic at this, you don't even need the underlying code, usually just the function signatures and Visual Studio autocompletion allows you to guess your way into finding the right classes and functions. Everything has long descriptive names (without the AbstractProxyFactory bloat from Java), follows conventions, arranged in a logical hierarchy and ample documentation available in intellisense.


I’m willing to bet that descriptive names is a red herring, and the real difference in code quality were engineers who cared enough to review for such things.


Having worked on a pre-Fortran77 code base, names are a big fucking deal. Half the code was written before variable names could be longer than six characters.

The pendulum is swinging back from the overreaction to that, Java's famous AbstractSingletonProxyFactoryBean. As awful as that name is, I will take it any day over L(IH+GV).


The author seems to completely ignore the possibility that language designers get better at designing languages over time, and people simply prefer to develop new projects in well-designed over poorly designed languages.

This to me seems to be the null-hypothesis, and I see no evidence on the page that use in "greenfield projects" vs "brownfield projects" provides any more indication than a simple underlying "well designed" vs "poorly designed" metric.

For instance: why do people dislike Objective-C but like Swift? Could it be simply that Swift was expressly designed to ease pain points of Objective-C? Or is it, as this author claims, that Objective-C is in more legacy projects and if Swift were to have been invented first then replaced with Objective-C, people would suddenly love Objective-C and hate Swift? Same reasoning holds for C/Rust, VBA/Python&TS, Assembly/LiterallyAnythingElse [1], Java/C# [2], and R/Julia.

[1] I imagine if this author were to have been around to write this in 1980, they'd make a claim something like "People say the enjoy C projects more then Assembly ones, but in this essay I describe how this is actually just because Assembly is more likely to be used in existing codebases, and if Assembly had come around after C people would certainly prefer Assembly and detest C"

[2] Note C# is incredibly enterprise/legacy, yet well-designed. This supports the null hypothesis perhaps the most.


I'm the author. Its not as if I've never heard anyone say how amazing new language X is. That seems to be about the only thing I do hear.

I love programming languages and play around with them all the time and have interviewed creators of programming languages. Clearly there is progress being made in the field of programming language design.

The article was saying that you can't necessarily take people opinions in the SO survey at face-value when considering programming languages that are still in a honeymoon phase. There are no 15 year old Julia code bases. Once you have taken over a large code base in a language and have the experience maintaining it that is something else.


I think your perspective have all to do with experience. My younger self used to see new languages as magic wands, secret recipes that would make my code lead me to new things and discoveries.

Now my modern self understand how naive i was, and that actually man-years, algorithms, experience and resilience are super important, all that of course with a good sense of opportunity and also luck to make the right thing on the proper time (nor before or after).

Reading codebases of others, with pearls collected over the years of how to do well some things in particular fields gives you a bigger perspective that as long you are able to choose the right tool for the job, the quality and excelence of the final product will depend much more of this experience than of the programming language chosen.

The ecosystem around the language also matters a lot. For instance other languages might be more suitable or performant than Go in cloud, distributed and server computing. But the fact that you will have a great ecosystem giving the language community will make new projects more likely to succeed even if other languages might be better in performance or memory footprint for instance.

The most upvoted comment in this section for instance is in denial and trying to validade the hype. Because theres nothing more comforting than feel good emotionally about something, and the people that also have gone through this and know what you are experiencing, that warns you about it, are perceived as enemies. Because you are breaking this "feels good" cycle, so you must be the enemy right?

(But the thing gets me a little scared about is that the last hypes have been much more ferocious, reminding a lot religious cults dividing people between the ones that believe and the ones that does not)


Yeah, this seems like one of those "correlation is not causation" situations. If you noticed that languages many people loved were correlated to languages that were used for new projects, it seems crazy to eliminate "loved language causes people choose it for new projects" in favor of "people choose it for new projects causes loved language".


The article makes the observation that "loved languages don't have legacy codebases". Also, using Ruby as an example, it postulates that "once a language has enough legacy codebases, it stops being a loved language".


Except it mentions C# as a loved language, which far up there in terms of legacy/enterprise-y.


I suspect there are two C#s in play here - the original C# in which many legacy/enterprise-y codebases are written, and the C# on .NET Core which is a fairly new ecosystem.


I wonder what the 'ugh factor' is for old C# code bases vs those in other languages.


I've never had to maintain legacy code before, and I would prefer any language on the green list to any language on the brown list (right tool for the job aside), aside from Python and maybe C#. I know there are plenty of students and hobbyists who feel the same.

I think the author is thinking too hard and overstating their results.


> I've never had to maintain legacy code before

If you didn't mistype your comment, it's super funny.

So in a discussion about programming languages and software maintenance, you comment saying that you've never had to maintain legacy code? :-))


I mean, if I've never had to maintain legacy code then my opinions on any given language are completely uninfluenced by the "honeymoon period" factor that the article is about, yeah?


In the argument of which is the best pet, Guinea Pig vs Squirrel, having owned none of them, I'd also be completely "uninfluenced by the honeymoon period" of owning them as pets.

But I'd probably just call myself, maybe less politely but probably closer to the truth, clueless about owning small pet rodents :-)


They have owned both a Guinea Pig and Squirrel, just never an old diseased one.


You make a good point about analogies.

But since we were discussing about what the best way to raise them so that they avoid most old age diseases, I guess that takes us to square one :-)


But they're also just uninformed about the subject, generally, no?


The subject is about why the stack overflow most loved programming languages tend to be recent. The article argues that because developers don't like legacy code, their impressions of languages used in legacy codebases are tainted. The subject is distinctly not about what languages are best in legacy codebases.

I have written code in many of the languages on the list, green or brown, and in a few of them I've worked with large codebases not written by me. I wouldn't consider any of them legacy though since they're fairly recent.

I am also a person, so I have preferences about the languages I write in. These preferences are exactly what stack overflow polls about. Because I have not worked on any legacy codebases, my impression of brown languages has not been affected by working on legacy code.

The fact that I, as a person who responded to the stack overflow poll who generally prefers green languages to brown languages, am unaffected by the factor that the author presents as significant, is an anecdata in opposition with the author's argument.

It's true that I'm uninformed about working on legacy codebases, but that's not the subject that my initial comment addressed


You got me thinking, it is somewhat surprising that languages actually didn't get that much better.

Most of the languages on the list are from the early 90s, and while there are some newcomers, it is not like they are winning by a landslide. And it interesting that you put Python after VBA even though Python came first. And in the article Haskell is "green" even though it dates back from 1990.

One would think that modern languages, designed for modern computers, with decades of accumulated knowledge would completely obsolete older languages, but no, new projects, made by people fresh out of school, are still made using languages from the early 90s. In fact, SQL and C, both from the 70s are still strong.

In fact, the only languages that have been obsoleted are from the 60s (COBOL, Fortran, BASIC, ...). They are still in use, but it has been decades since no one started a project with these.

EDIT: and I don't consider assembly to be a programming languages like the others. It is a 1:1 representation of machine code and is tied to the machine. In fact, just saying "I write assembly code" is meaningless if you don't specify the architecture.


I think it's because the last big idea that really shaped programming languages was memory safety/management.

Lots of people predicted in the early '00s that concurrency would have the same effect, but it seems like enough of us work on embarrassingly parallel programs that it doesn't matter that much.


> it seems like enough of us work on embarrassingly parallel programs that it doesn't matter that much.

I'm not sure that's true, it's just that because of the absurd amount of computing resources available, the lack of concurrency doesn't appear to cause business problems, therefore there's been no incentive to solve it.

It is interesting that many of the recent approaches to loads of data rely on inter-computer communication, rather than the intra-computer communication that is concurrency.


> Let’s call this Joel’s Law. A lot of things follow from this premise. Why do most developers think the code they inherited is a mess and want to throw it out and start again? It’s because writing something new is cognitively less demanding than starting from scratch, at least initially. Why are many rewrites doomed to fail? Because much of what makes the code seem messy are vital little improvements that accreted over time. Without some plan for simplifying them, you will end up back where you started.

This also resonates a lot with Chesterton's fence[0]. Often the current solution to a problem might seem unnecessary or complicating. But the complexity lies in the problem itself. Only if you truly understand the problem you can say if the current solution is too complex itself.

[0] https://en.wiktionary.org/wiki/Chesterton%27s_fence


> It’s because writing something new is cognitively less demanding than starting from scratch

For me it's quite the opposite: starting from scratch is hard - you have to make too many decisions. On other hand when I see an average legacy code, with the rare exceptions I find an unpleasant mess - it is rare to find that whoever wrote cared about code readability and left useful comments (and I cannot blame them - in commercial projects code quality, maintainability e. t. c. often has the lowest priority and adding new features - the highest). So maintaining legacy code looks like an easier task for me, but usually more boring.


I don't like the suggestion that rewrites are based on lack of knowledge or insight.

As requirements change over time, past assumptions and architectural decisions also accrete. Unless you're in a company with strong engineering culture, you get a Tragedy of The Commons kind of situation where nobody goes back and changes the architecture because they don't want to be the guy who breaks it all.

In my view, good engineering culture is being unafraid to treat code as disposable and throw it away - as long as the current requirements are properly understood.


I agree that code all is disposable, old and new alike. But without knowledge and insight you won't know which code to throw away.

So you either end up being the guy who introduces the new product that everybody complains about because it doesn't do what the old one did. Or you end up having to maintain both old and new because not everyone will switch to your new codebase.


This is true, but bad codebases are inherently hard and dangerous to change. That's one of the properties of them being bad.


That's why creating a new codebase is not the solution per se. Understanding the old codebase and putting its behaviour under test should be the first step. Only then you can start working on a new codebase, compare its behaviour to the old one and call it an improvement (if you manage to not mess it up as well, which is sadly often the case). Of course this can (and should often) be done is stages and not as a whole.


Agreed, whether you rewrite or change in-place you're not going to be confident in the outcome unless you have tons of end to end tests first.

Then you need to find and skip/ignore the tests that don't actually test end-to-end behavior or business logic, just some implementation detail along the way.

Only then will you be free to do what is probably the first step if you have a crappy codebase: start establishing domain boundaries and interfaces and splitting things across those lines.


Ok but it isn't true that there are no brown languages that are loved. So the interesting exercise is to try to figure out which green languages will remain loved after they turn brown! Obviously this is hard to guess at.

My guesses from the green list: I think Kotlin and TypeScript will remain loved; they solve a real pain point in a simple and well curated way. I think Scala will be dreaded (actually I would already put Scala in the brown category). I think Haskell will remain both loved and dreaded; I think it's a bit different than the rest, because I don't think people mostly dread it because of maintaining old systems, I think whether or not it clicks is just very personal (I'm personally in the "dread" camp on it, though I appreciate many of its ideas). I don't have enough experience with Dart or Julia to make a guess.

The most interesting questions are Go and Rust. My intuition is that I think Go will be like Ruby: quite nice to start with, but increasingly unwieldy as projects get bigger and bigger. I do find it pleasant to hack on small Go files, but would dread joining a project with millions of lines of code. Rust could be dreaded as the C++ of the future, known for big unwieldy difficult to maintain codebases. Or it could be loved as the much better C++ of the future, known for making big unwieldy difficult to maintain codebases more tenable and enjoyable to work with. I'm not sure!


What problem does Kotlin solve? It's basically a "better Java" - the problem being Java is becoming a "better Java" too. I feel like eventually Kotlin will collapse under its own weight as it continually tries to outpace Java and takes mis-steps. Sorta similar to how Scala did - many looked at it as a "better Java" during Java's period of stagnation.


I'm cautiously optimistic that Scala 3 will more towards most loved vs hated.


It solves nightmare of groovy (gradle.build scripts).

Kotlin makes gradle bearable.

https://quickbirdstudios.com/blog/gradle-kotlin-buildsrc-plu...


I think it's harder to become better backwards compatibly, and that for that reason it is unlikely java will ever catch up to some of the most compelling good (in my opinion) decisions Kotlin made. But your point is a good one and you may have convinced me that my guess is wrong about Kotlin for this reason.


People dread Haskell because Hello World uses monads.


> increasingly unwieldy as projects get bigger and bigger.

This applies to any project in any language. How would it be worse in Go versus Kotlin or Typescript?


Yep, as the other commenter said, languages scale differently because of the entire suite of different and interacting features. I know it's cliche to say, but I still believe it's true, that Go suffers from lacking generics, particularly as a project grows. I see big projects with lots of `interface{}` usage to work around this, and at that point the type system is essentially equivalent to Python's, which in my view is harder to maintain at scale. This seems a lot more common in big Go projects than use of Object in big Java projects, for instance, and I think it's a smell. I also think nil-based error handling is harder to maintain than languages with no nulls, or strongly discouraged nulls (but most languages have this problem). I don't have a good sense for how well the concurrency functionality in Go scales, but I get the sense that it's pretty good, and superior to most other languages, including the other ones in this thread.


There are many features in such languages that allow to reduce cognitive overhead, such as null safety.


I think it's a pretty valid hypothesis. Like so many "research" projects, there's a lot of "baggage" that comes with data.

For example, I was reading that a study found that people who take Melatonin do better, when infected with COVID. Then, it was pointed out that this may well be because they tend to get better sleep than people that don't. The "better sleep" may have more to do with the fact that these people take getting sleep more seriously (the Melatonin is an indicator, as opposed to an actual variable).

But "brown" languages are here to stay. One of my first projects (in the late 1980s), was a 1970s-era FORTRAN 4 codebase of over 100KLoC, without a single comment (in those days, disk space and memory was so expensive, that we used short variable names, and no comments).

These days, I am usually the poor schlub that has to go back to my codebase, so I've learned to be pretty heavy-duty in documenting my code. I eat my own dog food.

This article is a few years old, but I think is highly relevant (and a bit meta): https://veekaybee.github.io/2019/05/10/java8/


It hurts seeing Ruby listed as a dreaded language. I think what is actually dreaded is Rails, and the terrible, awful, no-good things PM's forced it to do in the 2010's.

I'm a Python developer now, but I still miss the ease of writing code in Ruby. I find it a cushy, intuitive activity, and I wish it was used for something other than hulking, poorly scaled/planned out web apps of yesterdecade.


It's funny how quickly opinions seem to change.

When I first visited HN (~2010) it seemed Ruby and Rails was all the hype; doing Ruby/Rails stuff seemed to be the hip and cool thing to do. Perhaps Heroku was also introduced around this time?

Nowadays it seems Rails is mostly forgotten and Ruby, well ... Python seemed to have dethroned Ruby as Python seems to be used for similar purposes.

I tried to get into Rails in the past, but it didn't quite click with me. Perhaps in part because I don't do web dev by trade. In general I just don't enjoy web dev. Ruby as a language, I did enjoy and I used it in combination with Calabash for iOS tests. But I believe most of my team members didn't get the same kind of enjoyment out of Ruby as I did, much preferring much to work with statically typed languages, as such most didn't get involved in writing UI tests too much and just focused solely on the mobile app work.

I also used Ruby as a replacement for some shell scripts, when a shell script would be too complicated and problematic to write.

Just last year (after a few borked initial attempts) I really got into Lua [0] and I have to say, I enjoy it even more than I did Ruby in the past and also most statically typed languages that I've worked with (C#, Swift, Objective-C, ...). Lua (with LÖVE [1]) is awesome to me.

Lua seems to be a very neat small little language that is build on just a few very simple concepts, which makes it pretty easy to wrap your head around it. With Ruby there would be quite a bit of magic (complicated internals) happening, which I don't see in Lua.

Some people mentioned Lua might be hard to use in big projects, but I believe it should be manageable and I hope to write a pretty big game using Lua and LÖVE in the future.

---

[0]: http://www.lua.org

[1]: https://love2d.org


> It's funny how quickly opinions seem to change.

Ruby's popularity peaked during Web 2.0 when almost all new apps were server-side web apps. When smartphones came out and a massive fraction of development shifted over to client side apps, it sucked much of the air out of the room for Ruby and Rails.

(And dynamic typing in general. Runtime performance is a fungible cost for server-side programming where you can throw hardware at it, but a hard requirement for client-side apps running on devices you don't control.)


Rails is still the elephant in any web application room. But it isn't hype-y, it's just the mature option for its use case.


I'd say Django is encroaching on that territory more these days, but Rails is still the bear's share.


You may be right because I haven't had my ear to the ground recently, but I thought this like a decade ago (at least 8 years ago, I know I did), so I guess I'm slightly skeptical.


For anyone interested in the links he provided, I'll add a third, a nice tutorial that introduces you to LÖVE[0]

[0]: https://github.com/a327ex/blog/issues/30


> I think what is actually dreaded is Rails, and the terrible, awful, no-good things PM's forced it to do in the 2010's.

That's basically it, for me, yeah. Long-lived (or hell, pretty much any of them that aren't just getting started) Rails codebases, even when they're not particularly complex, without heroic levels of good processes & individual discipline to keep things reasonable and clear, become fucking nightmares to onboard to. I'm more wary of Rails than a bespoke PHP codebase, at this point, and "we're a Rails shop" is damn near an instant "well thanks for the interest, but no" from me. I don't need that stress for the dozenth time. Just done with it.

It sure is impressive how fast one developer can knock together a prototype with Rails. Meanwhile I've had so many extremely-bad experiences with ongoing Rails projects that I hope never to touch one again.

But I actually like using Ruby itself a lot better than, say, Python. Ruby's fine. Rails... no. Never again. Maybe if they embrace static typing and it becomes nigh-universal in the Rails library ecosystem, they can make it tolerable. Too much magic, too little help from my tools to help me understand WTF the magic is doing, where it comes from, et c.


Yeah I agree. I'm a bit mystified by the love for python. It is very clunky compared to ruby. I often wish ruby would have gone the scientific data route rather than the web services route, instead of python being the primary game in that town. But I am not at all mystified by people dreading rails.


I love Ruby's syntax. But I've always found it a nightmare to install anything built in Ruby, due to the dependency spaghetti [even worse than Python's]. Which is why I really want Crystal to succeed.


Hard disagree here. Moving from Ruby's dependency system over to Python's has probably been my biggest regret with Python. I still don't totally understand it.

Gem's certainly aren't perfect, but I'd take them over Python packages any day.


I do still like Ruby and not yet hate working on Rails app. But after using Typescript in Reactjs projects i just loved it. I have a new found love for typed languages. Now trying to move to either C# or Rust to get enough experience to confidently choose those for new projects.


Same, I came to scripting languages (at the time that's what they were) in the 90s via Ruby. Now Python is my goto, for practical reasons, when I'm not doing C# or C++ but I still miss Ruby. I only have a vague idea what Rails is so I just miss Ruby itself.


I'm particularly interested in why several languages show up on both lists, namely SQL, Scala, Haskell, Shell, and HTML if you count it.

One possible explanation (that supports the author's main thesis) would be that three out of five of these are unlikely to be the main language for a project, but rather a supporting language. In other words, SQL and shell are just as likely to show up in a green-field project as in a brown-field project, because we still use SQL to communicate with database same as 20 years ago, and we still use shell scripts to tie it all together.

No idea how one would test this hypothesis, however. And I still don't have an explanation for why Scala and Haskell are both loved and hated.


Scala and Haskell are both "astronaut" languages. They really encourage highly complex abstractions. They're potentially very powerful, but it's easy to get lost in the clouds.

Some people love it, because it potentially gives you an enormous amount of leverage to solve difficult problems with careful but short solutions. I forget where I heard this joke, but you give a Java programmer some specs and he'll spend 4 hours writing code, whereas the Haskell programmer will spend 3 hours and 55 minutes meditating, then write a 10 line solution.

The counterpoint is all that abstraction is often just needless busy work, that more often serves to feed the programmer's ego rather than accomplish real work. It's also not pleasant trying to figure out compiler errors that you need a PhD in abstract algebraic topology to understand.


> Some people love it, because it potentially gives you an enormous amount of leverage to solve difficult problems with careful but short solutions. I forget where I heard this joke, but you give a Java programmer some specs and he'll spend 4 hours writing code, whereas the Haskell programmer will spend 3 hours and 55 minutes meditating, then write a 10 line solution.

I prefer the "meditative" approach, because it will more often produce something readable. It looks unproductive, because there is a small number of lines produced in a given amount of time, but that's actually good. With the approach where the programmer just sits down and bangs away at the keyboard straight away, producing lines of code at uniform velocity, you end up with loads of code doing nothing, "dowork", calling "doworkimpl", stack traces 50 stack frames long where no stack frame seems to be doing any useful work. The "meditative" approach in extreme cases can produce indecipherable code with y combinators and whatnot, if your coworker is a real monk, but generally brevity seems to be a nice benchmark. All those great Haskell abstractions don't actually produce short code, it's the basic Haskell that does it. It just takes a while to arrive at such a solution, be it C or Haskell. And it's a win long-term, when you need to get back to this code to debug it. And you are going to need to get back to debug it.

See e.g. The Evolution of a Haskell Programmer[1]. It's not the great abstractions that produce the shortest code. But it is the shortest code that is the clearest.

[1]: <http://pages.cpsc.ucalgary.ca/~robin/class/449/Evolution.htm>


"It took me four years to paint like Raphael, but a lifetime to paint like a child. "

- Pablo Picasso


> Scala and Haskell are both "astronaut" languages. They really encourage highly complex abstractions.

Haskell encourages very simple but highly abstract abstractions. Scala, I would agree, tends high complexity as well high abstraction level.

Both can be barriers to understanding if one is not familiar with the particular abstraction, but they are different issues (high abstraction level tends to be something you go from not getting intuitively to getting intuitively in a phase transition, while high conplexity tends to be more gradual and has a greater irreducible cognitive load.)


> Scala and Haskell are both "astronaut" languages. They really encourage highly complex abstractions

They encourage highly simple abstractions. You can put functions like `fromString` and `map` onto interfaces. No need to go via builders/generators/collections.

Dijkstra said it best: "The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise."


> It's also not pleasant trying to figure out compiler errors that you need a PhD in abstract algebraic topology to understand.

I'd much rather deal with that and become better in my profession than being woken up at night because something is on fire at runtime and I have to jump in and understand it, fix it and clean up after it.


You will be woken up when the OS runs out of file handles or memory.


And a weak type-system prevents that?...


No, but strict evaluation does.


Scala has strict evaluation by default. :)


But not enough inscrutable compiler errors :)


Young padawan, I'm inviting you to look into my github sideprojects (same name). I think that will change your mind ;)


> I forget where I heard this joke, but you give a Java programmer some specs and he'll spend 4 hours writing code, whereas the Haskell programmer will spend 3 hours and 55 minutes meditating, then write a 10 line solution.

Given the choice of reviewing and maintaining one versus the other, I’ll take unwashed Java code any day. I’m not a fan of enlightened, esoteric solutions.


Reviewing 10 lines is likely easier than reviewing 500 lines that do the same thing.

Also something that is beautiful is not necessarily esoteric (though esoteric isn't really meaningful anyways. Chinese sounds esoteric to me just like English sounds esoteric to others).

But it really comes down to experience, not the qualities of the language. A professional in both Java and Haskell would most definitely prefer a few line Haskell solution vs a massive Java solution. Just like they would prefer a few line Java solution over a massive Java solution.


> an explanation for why Scala and Haskell are both loved and hated

I would posit it's unlikely that the same people both love and hate them. My guess would be we're seeing the OO-FP divide in action. If F# or Elm were more popular, they might be on both lists, too.

In fact, if you interpret it liberally, JavaScript might be considered FP by some takers of the poll, given browner JS codebases (pre-await) would need continuation-style approaches. Obviously, JS has other [reputation] problems, too.


I cant speak for Haskell but imho earlier scala codebases suffered from either too much javaism or too much haskellism. The language is so flexible, you can write code either way. People brought too much baggage. Javaists brought Spring Guice and tones of other sht that simply does not belong in Scala, Haskellers did their darn best to write Scala code exactly like they would write it in Haskell with very little consideration for Scala or JVM. The results in some code bases aint pretty. You basically need to know Haskell, Java, and Scala to read the code where people have went overboard. Having said all that, Scala is still my favorite language on the JVM, and Scala3 really stands on its own when compared to Scala2 more hybrid approach


What is the native Scala style? I have heard of things like "cake pattern", initially touted as the bees knees then falling out of favor after there was some experience to draw from their usage.


It's obvious, but no one seems to notice it: These are not two lists. The list of dreaded programming languages is the list of loved languages reversed. Since the list has only 25 items, 5 languages belong to the top 15 in both directions.


Haskell is an oddball in that it’s an older language, created in the 90s, IIRC a year before Java, with concepts so cutting edge that it was utterly useless. Initially they hadn’t even worked out how to do IO. Probably it’s only been useable in industry for maybe 10 years. So Haskell is relatively old, but you’re unlikely to encounter a lot of old projects written in Haskell. Also, there’s a lot of hype about how difficult it is, I believe this has a lot to do with how different it is from popular languages people already know. In my experience, once learned it can be hard to go back to other development styles.


> Initially they hadn’t even worked out how to do IO. I tried to find some date by which they'd figured it out, the best I can do is 1992[1].

To put it another way, Haskell's had a great story around IO for 29 years, or longer than Java's been around.

All the modern future/io/concurrency frameworks have followed suit. We construct objects representing computations and we flatMap them together, which is all the IO monad is. Although for some reason the syntax from last millennium hasn't made it into the modern languages:

    str1 <- readFile file1
    str2 <- readFile file2
    let str3 = str1 ++ str2
    writeFile file3 str3
vs:

    readFile(file1).flatMap(str1 -> {
        readFile(file2).flatMap(str2 -> {
            String str3 = str1 + str2;
            return writeFile(file3, str3);
    }});
[1] https://www.haskell.org/ghc/docs/papers/imperative.ps.gz


> Haskell's had a great story around IO for 29 years, or longer than Java's been around.

I like that a lot. I did not realize that problem was solved so early on.

The things I was thinking of were more like good application frameworks, database libraries, etc. all the stuff you need to build commercial products and that you might have trouble justifying developing on an investor’s/shareholders’ dime.


The popular syntax for this in newer imperative languages seems to be async/await, although I think I only like Swift's implementation. (unfair statement since I haven't used the rest much)


The cool thing about the syntax in Haskell is it’s not tied specifically to async, you can use it for synchronous IO, business logic, parsers, etc. It makes for small context switches when working on different parts of an application.


To adopt it in other languages don't you need non-strict evaluation, at which point it's hard to stop yourself from becoming Haskell?


Certain idioms in Haskell rely on laziness, but thankfully monads and do notation do not. They’re used in PureScript which is strict.


> To put it another way, Haskell's had a great story around IO for 29 years, or longer than Java's been around.

That is a tall claim. LazyIO has been problematic in Haskell well into the 2010's until Iteratees became well-understood.


Care to explain the downvote?

From Oleg Kiselyov's 2012 paper Iteratees [1]:

  Lazy IO is so irresistible that it was added to Haskell 
  despite the reservations of its inventors and the failure 
  to develop good techniques for reasoning about its correctness 
  [7, Sec 10.5]. However benign, reading is an observable 
  side-effect, whose occurrence may have to be correlated with 
  other side effects. Such correlations are crucial when 
  performing IO over communication pipes, which is typical of 
  web servers.3 As Launchbury and Peyton Jones feared, Lazy IO 
  indeed "gives rise to a very subtle class of programming errors". 
  We have seen deadlocks; mishandling of IO errors; running out of 
  file descriptors and similar scarce resources; unpredictable, 
  volatile and sometimes unbearably excessive use of memory. We 
  illustrate the splendors and miseries of Lazy IO in §2.
This is a very famous Haskell programer's opinion on the default IO in Haskell, and he quotes that one of the main creators of the language himself anticipated such problems [2]. Why downvote a comment in 2021 challenging the claim that "Haskell's had a great story around IO for 29 years"?

[1]: http://okmij.org/ftp/Haskell/Iteratee/describe.pdf

[2]: https://www.microsoft.com/en-us/research/wp-content/uploads/...


Iteratees (nowadays pipes, conduit etc.) are based on functionality that was already there in 1992. They didn't add anything to Haskell. They're just libraries. Lazy IO has indeed always been bad but it wasn't the only part of Haskell's IO story.


Lazy IO is great where lazy IO is great!

Long running processes handling lots of different requests, not so much, and that's made up an increasing amount of what people want to do.

But for "open a file, chew through it, errors when consuming it might as well take down the process" nothing could be easier.


What were the other options available in Haskell in 1992, besides Lazy IO, which made for a great IO story then? Please point me to code or papers from then because I am genuinely interested to learn.


Reading and writing between handles and buffers, just like any other language. If you object specifically to the adjective "great" then, well, I don't think that was the operative point of the original comment.


I object to both the use of “great” and the (needless, IMO) mention of Java in mrkeen’s comment.


I might be naive, but I just assumed that I was still using lazy IO.

I've used conduits before, and understand that pipes fit the same design space.

But most of the time I just use read and write operations exposed by Bytestring, etc.

My point is that since I like IO today, and I didn't think that laziness had been removed, then I probably would have liked IO back in the day.


"Lazy IO" is things like `readFile :: FileName -> IO String`, where that String you get back secretly hides a thunk that will read more from the file when you evaluate it (even in pure code).

The operations provided by `Data.ByteString` do not work like this; the ByteString you get back represents a buffer, and it has already been processed by the time the RHS of >>= starts executing.

The operations provided by `Data.ByteString.Lazy`, on the other hand, do work like that; the ByteString you get back is a linked sequence of buffers, and some of those links might be thunks to go get the next bits of the ByteString for you.

This is why a Data.ByteString.ByteString and a Data.ByteString.Lazy.ByteString are different types, and you can't just pass one where the other is expected (unless you've abstracted over it) - they're actually shaped differently.


There's one language in that list that I ticked as "loved" one year, and "dreaded" in the following year.

My working hypothesis, not incompatible with yours or the article's, is that familiarity breeds contempt.


For Scala and Haskell, it could just be pragmatic developers vs purist developers (to grossly generalize).

There are people out there who want the absolute best language for a project, even if they don't already know it.

Then there are those who would be annoyed at having to learn a new language and all its quirks to do something that Java could have done, even if it cost more in servers or requires more lines of code.


Rarest of all seems to be those trying to get a good compromise: F# or OCaml.


Well, three things on that list are languages that are basically DSLs (Shell to a degree, SQL) or Markup Languages (HTML). Comparing any of those to e.g. C++, Go, Ruby or Python is like comparing apples to oranges and I don't see, how that is a useful distinction.

Scala and Haskell are distinctly non-C-like. Both are functional languages with types. Maybe that is a factor.

Actually, in a new project that wouldn't be "low-level" work on e.g. operating systems, drivers or high-throughput networking software I would strongly suggest using Clojure/ ClojureScript. The net productivity, onboarding speed and efficiency are great. Both are quite performant as well and integrate into the Java/JavaScript world with ease, so there are libraries and tools present. Using babashka or the Node.JS target for ClojureScript could be great for scripting as well, although Python or Hy (Clojure on top of Python basically) are strong contenders because of libraries.


Scala is a kitchen sink language. You can write it like FP, OO, or anything inbetween. So you're bound to get codebases that aren't written in the developers preferred style.

On top of this, lots of companies started using Scala because Java hit a long period of stagnation. So these companies have a mix of Java/Scala and a primarily Java developer - that likely doesn't like kitchen sink languages - may be required to maintain a Scala program from time to time.


It's also the only viable language with a decently sized community that allows you to write mostly FP or even fully FP code on the JVM. And one strength is that you can go from OOP via OOP+FP to fully FP if you want.

Yes, that can also cause a mess, but for learning it is one of the best languages out there imho.


Can't really speak to Scala and Haskell, but shell, HTML and SQL all are generally love/hate languages. All three are pretty simple to be productive with, and all three take a lot of time and knowledge to master (I'm including CSS in with HTML). All three are powerful, yet have pretty big limitations, too.


4 of those 5 (all but Shell) are very declarative languages. They tend to be very concise and powerful, but are quite different from the more imperative languages people are used to.

Could be that once you really grasp them, you love them, but they’re harder to grasp because they’re so different?


Author here. I wanted to dig a little into data from the Stack Overflow survey on what made programming languages loved or hated and I think what I found is pretty interesting: it seems like people don't like the languages where they have to do maintenance work.

Python and C# seems like outliers here though. People really love them.


About 4 years into my career I am really really reaching the end of my rope with Python.

Type annotations have improved things a bit, but since it's not real, or enforced by anything, every library types things differently & often incorrectly, if at all, and the type annotation system itself still has massive limitations.

That's not to mention the package management ecosystem.

I'm getting into Go and Rust. Go is fine but it would be a million times better if it had proper enums & pattern matching for result & options types. Being able to define a class of errors as an enum in Rust makes handling them so easy.

Rust is really cool, but I know I am barely scratching the surface with it and it would be hard to convince any of the Python shops I have worked in to go to Rust due to the learning curve.

All the Python shops I have worked have eventually started to write some stuff in Go, except the one shop which is just data/PySpark stuff .


Putting aside the dreary package management situation with Python (although perhaps Poetry will scratch that itch?) codebases really only shine with comprehensive unit testing, linting, static analysis and a bit of discipline to stop it from degrading. Although perhaps that’s applicable to any large codebase.


I agree.

Poetry is good but not good enough to use at work yet. Also - not Poetry’s fault - many Python packages are miserable at listing and versioning their dependencies correctly.

Re: everything else, you’re right but it gets really tiring writing tests that are handled by the type system in other languages.

Go has this problem too to a certain degree since multiple error subtypes can’t be expressed as an enum. Just errors.Is and errors.As everywhere.


I like C# simply due to the tooling. I legit left a job since they made me use Eclipse with Java.


The more experience I gain as professional software developer, the more I begin to appreciate that what matters is the entire "ecosystem," rather than what language I'm programming in.

What's the IDE like? How are dependencies managed? Is there a solid framework, as opposed to "move fast and break things" frameworks or "scores of amateurish third-party add-ons to choose from" to solve everyday problems? What's the programming community like? What kind of companies use these solutions, and what's the culture like there?

Tools a big part of what we do. If I were a mechanic, I would rather work on Hondas with a good set of tools than I would Ferraris with tools bought at WalMart.

Personally, I've done only a tiny amount of C# development. I'd have no problem going back to that.


Yeah, C# and Python are my two daily drivers. I think a good case can be made for C# due to excellent tooling and sitting in the sweet spot for statically typed languages: less enterprisey and more practical than Java and less painful than C++.


I never understood why a company would enforce the use of a specific IDE. If they can’t set up .gitignore files and formatting properly, they should not be doing IT.


To be fair eclipse and IntelliJ do different things to set up run configurations. Although I'll agree this is a very very bad sign, I left that job as soon as I could. I will say socially they did a lot of fun stuff, we had tons of parties and everything. Felt almost like a college campus, the actual work environment was horrible though.


Standardized IDEs are incredibly important for productivity in complex software projects. Large applications can get to the point where the build system and IDE kind of meld together, and custom IDE plugins are required to navigate or build the code base.

I've worked at a place where developers didn't do any IDE configuration. The IDE (Visual Studio) was customized by another department then was pushed out to developer machines. This meant that developers could focus on building software and not messing around with configuration and plugins. It also ensured that everyone's code compiled the same, ensured library compatibility, etc.

IDEs may not matter so much on small web apps, but one cannot extend that fact to all of software development.


That’s a huge liability/red flag. Builds should be deterministic, and reproducible. An IDE should have no say in that, that’s what build tools are for. That’s just all around terrible. Also, a sane IDE should be able to make use of the config files of the build tool.


I mean, if you say so. Said project has been around for 25+ years, survived a dozen acquisitions, is actively developed by 1000s of developers all over the globe, and has revenues in the $100s of millions. So clearly they are doing something right.

Personally, I loved never fucking around with IDEs.


Just because one aspect is questionable, doesn’t necessarily effect all the other good ones! So good luck with the project!


My experience with build systems tied to specific IDEs is that they 'foster' homogeneity through fear and ignorance of the build process. Any changes along that axis become impossible in practice. On the other hand, text-based build description languages under version control provided a path to understanding and mastery. Even autotools has been better than weird bespoke IDE build integrations.

Also in my experience, "compatibility" is best enforced by API/ABI/FFI contracts, and commitments to support released versions for a given length of time.


>The IDE (Visual Studio) was customized by another department then was pushed out to developer machines.

Even though that may make sense in some large environments it's not something I could put up with. I'd never take a job somewhere like that.


If you're using Java, definitely give IntelliJ a try. I think it makes writing Java a pretty enjoyable experience.


Agreed, I like IntelliJ. I said since I never know if a Java shop will make me use eclipse again, I tend to shy away from java. Of course I do have a price, if we're doing 200k up I'll put up with Eclipse


I agree. One reason I think people hate VBA so much is because the tooling is abysmal. If you've ever had to work with VBA code in the Excel code editor, you'll understand what I'm talking about. Ironically, both that and Visual Studio are made by the same company.


>they made me use Eclipse with Java.

I mean I do use them quite voluntarily. That's the thing that annoy(ed) so much.


Doesn't Eclipse feel a bit dated to you ?

Like they wrote the UI in 1999 and never updated it


> Doesn't Eclipse feel a bit dated to you ?

I wonder what you'd say about the command line. The interface has not changed for like 40y+.

I 1st started using eclipse in 2006 or so, while writing some plugins (post compilation byte code editing) in 2003-2004. The UI has been updated somewhat since, not drastically, though. I've got pretty decent understanding how it works internally and what functionality is available.

Truth be told, updating the UI just to look modern might find some fans but to many it'd make it less usable for no good reason. For instance I don't want my hand drill to feature an OLED display, coupled with bluetooth just b/c it's cool and dandy.


I've maintained large Python codebases, and I found it somewhat painful, especially when finding and fixing issues. I got tired of discovering issues at runtime that any compiled language would have found at compile time.

I still enjoy Python, but I don't consider it an exception to any general principles here.


As a C# zealot, I would have a hard time providing an unbiased take, but its probably the "whole picture" ideal that makes developers take to it so strongly. When working with C# (aka some specific flavor of .NET), you are embraced with the following:

  - Visual Studio, probably the best IDE ever created.
  - With .NET (Core 3.1~6), code that usually "just works" x-platform.
  - Mostly-workable application development ecosystem as of .NET 5. 
  - Ecosystem of first-class CI/CD/Cloud/et. al. products & features.
  - World-class debugging experience, even across the network.
  - Stable versioning scheme with dependable LTS options.
  - Confidently run mission-critical loads on latest Windows Server platforms.
  - Very large library of high quality 3rd party dependencies (nugets).
  - Trivial to configure own nuget server for internal/private use.
  - Virtually everything you need is a first class dependency.
  - LINQ
  - Very good GC, especially when configured and used correctly.
  - Strongly-typed with very expressive language features as of C#8.
  - Fast compilation times, even on monster projects.
  - Principally maintained by largest software company on earth
  - Maintained by the open source community as well
  - Extreme performance (.NET Core optimizations, Kestrel, Disruptor, et. al.)
  - Extreme productivity (VS tooling, Self-Contained Deployments, Blazor, etc.)


One of the main issues with stackoverflow is (has been): very few seasoned developers ask questions and even they do, it'd be likely to be unanswered. That skews its user base very heavily towards the younger people.


Or different styles of learning! Some languages are really good in situ for debugging and solving problems, some are more opaque and require looking things up.

Also 'brown' languages being older and more established, there are plenty of older engineers who RTFM first, look at man pages first, etc then ask questions.


It’s an interesting conjecture but I don’t think the data makes a compelling case. When you compare 2 points in time you have a lot of alternative hypotheses, like the 2016 languages just being historically unpopular for some reason. A better support is a cohort analysis where we see languages start green/liked and transition to brown/disliked over their lifecycle.

The real difficulty though, is addressing the alternative hypothesis that language design improves over time. This is obviously the view of language designers or else they wouldn’t make languages.

In that case, you would see the languages turn brown in your analysis, and even in more robust cohort analysis. But it would not be because of a honeymoon bias, it would be because you don’t want to use a horse-drawn carriage if you could use an automobile.


Different decades have different applications, hardware and trade-offs. So popular languages could be just overfit to the current epoch. It doesn't mean there is always progress, could be just change.


Thank you for sharing. Intuitively I think your point makes a lot of sense. I don't think there's really enough data to really prove it, but I liked your approach.

I do think there's other stuff going on as well though. For example, newer languages are often designed to address perceived problems with existing popular languages. I'm a long-time Kotlin and Java developer, and Kotlin feels a lot like Java 2.0 - it specifically addresses a number of pain points people were experiencing with Java. So of course I'd rather be working with Kotlin, and going back to Java can feel like a drag.


Seems there's a lot of hate for Scala and Haskell regardless of the project? What is it with functional?


I've never seen someone succeed at giving an objective explanation. Anecdotally and subjectively, functional programming is a different type of thinking about a problem... Instead of breaking it down into stages, I'm almost breaking it down into a graph and figuring out how the nodes must connect. LISP is also like this.

I wouldn't be surprised if cognitive modeling shows that graph-manipulation engages different chunks of one's brain than step-by-step procedural description, but I do not know.


There might be a particularly strong Green/Brown delineation with those, with programmers loving to write code in them, but disliking to maintain other people's code.


Scala and Haskell are also in the most loved languages, why do you think there's a lot of hate for them?


I think some people feel productive writing lots of code, while others feel productive learning ways to avoid writing lots of code.


Also with C# and .Net there has been a lot of changes since .Net Core released 2016. Doesn't change that there is a lot of older legacy code so im not entirely sure.


I loved C# as a language. I'm not fond of most companies that use C# though.


Could you elaborate on the second statement? Why is that?


Most companies that use C# and .NET tend to be big old school enterprise orgs where tech is an unrespected cost center.

Java is arguably used in many of the same companies, but also seems much widespread across a more diverse range of different types of companies.


I am a Python (green) programmer who joined a team using Java (Brown), but I have found that working with Java has overall been a great experience. Most of that may be because of Intellij, but I find the verbosity helps prevent future bugs and helps more strickly define interfaces.


I am also a Python programmer, and would much rather write code in Java these days. Having a compiler tell you when you've made a mistake rather than waiting for a test to run is so much more productive.

People who tell you that scripting languages improve productivity are lying.


Scripting languages can be great for very quick iterations, but they can also cause serious issues in larger, mature projects.


I imagine a lot of Python programmers find themselves using strongly typed language, and love that a whole class of bugs has just disappeared.


I went in the opposite direction coz 40% more code to maintain didn't seem like a worthwhile price to pay to catch some pretty shallow bugs.

Especially since more code correlates pretty strongly with more bugs.


Java is certainly more verbose, but I feel that nothing is free and being more concise comes with some costs. For some applications the trade off is certainly worth it! I use python and Django for personal projects to move quickly. But if I need to build something that will be rock solid I need to move more slowly and carefully, and Java works well for that.


> But if I need to build something that will be rock solid I need to move more slowly and carefully, and Java works well for that.

Rock solid with features like null references, AbstractFactoryFactories, extremely over-engineered class and inheritance architectures, object fetishism, etc. I know what you mean, but Java and rock solid are not something I would mention together.


For me it depends what I'm working on.. I love writing loosely typed magic in Python for small scripts. But if I'm working on something big in Python, I take the time to use type annotations. IMO it makes the code easier to understand.


How is it 40% more code??


honestly types are overrated. if you still what's now known as data oriented programming or passing values then Python isn't a pain.

However in the wild, yeah Python code can be an abomination due to people doing OOP then heavy classes without types and that is a pain. This is the main reason, I avoid Django most times even though I like Django because maintenance can be a pain.


Python is strongly typed. You mean static typing.


If you look into prior years, you'll notice that many of these brown languages were once green. When Rails boomed, Ruby shot up in popularity, when Node came to the fire, so did JavaScript. Same with Scala (which happens to be on both lists.)

Python has had a revival because of all the ML and data science. TypeScript is hot. Julia and Motion are new. Dart got a bump from Flutter. Rust is also hot.

Go is probably the exception here, but mark my words many of these green names will also brown in time as developers become bored and ShinyLang, and it's IOTWebAIMobile Framework takes off.


I think this theory is not accurate and not useful due to Simpson's Paradox, which I learned about recently in this great post by vladoh in regards to Tesla crash reports. https://news.ycombinator.com/item?id=26855608

I have an alternate theory. Junior developers prefer languages they learned to program in or closest to it, while senior developers like languages that make is easiest to express a problem solution and this consideration includes the library ecosystem.

I'd like to see this article again rewritten in terms of developer experience.


Eyeballing which languages are outliers, it seems that python, Swift and C# really stand out as good languages.

Though I wonder if it’s that more a function of their codebases being more beige than brown. Python tends to be used more for small, informal, non-critical cases like data science pipelines. It’s less common in the sprawling, mature, long-lived software that wakes you up in the middle of the night. Swift only came out in 2014. So even though it’s widely used, it’s had much less time for code rot on the existing projects.

Going the other way, Haskell and Scala stand out as exceptionally bad. I’m pretty sure that the dread truly does come from the inherent complexity of those languages rather than their use cases. However they’re also widely loved. So those language design choices are more polarizing than they are reviled.


HTML is in both dreaded and loved list. It isn't even a programming language.

I think you've missed the boat slightly. I maintained a VB6 application. I disliked doing that not because it was old, but because the code base was created into many projects, some I had no source for. Independent of that I wouldn't choose VB6 for a new project because it lacked stack traces and wasn't cross platform.

Java: I don't care to program in it because the IDEs are so heavy and I don't like how the ecosystem has grown up.

Go: I don't like it because it is "new" (over 10 years old), I like it because it has reflection and stack traces, it is easy to write in a lighter environment, it is cross platform, it is typed, and it prefers explicit usually. I have a large application written largely in Go. But I don't think about writing in Go. I think about the domain; Go is almost incidental.

Yes, many immature developers hate old code. I don't hate C++ directly, but if you've ever had to work with a C++ code base with 3 types of strings then you may dislike working with C++ ecosystem you've ran into.

People don't dread assembly because it is "old". People dread it because you can blow your foot of without realizing it, but it is still necessary today.

Specifics matter. "Old" doesn't cause it to be "bad". Foot guns and and lack of easily reproducible environments (I'm looking at you R) are "bad".


> Foot guns and and lack of easily reproducible environments

I kinda agree with the reproducibility concerns around R, but you can use conda or MRAN if you really need that. The massive benefit of your concern is that if you install the latest version of R, then you'll get an entire compatible ecosystem of packages, which I really, really appreciate and the lack of which drives me mad in Python.


> Java: I don't care to program in it because the IDEs are so heavy

Just use VSCode, or Sublime, or neovim. They all work fine.


IMO not using IntelliJ with Java is like shooting yourself in the foot and crutching for the rest of your life just to show people how tough you are.


This looks more like a cool vs uncool list. SQL and HTML are "Dreaded"? Frankly, anyone who has the actual opportunity to program in Assembly should thank their lucky stars.


SQL and HTML are on both lists. Presumably because they can be great or terrible depending on the quality of the existing code you’re dealing with


Also they can only dread what they use. The question SO uses specifically asks only about things that you use extensively. That is what makes this interesting to me. It isn't people dreading APL because it looks funny, its people dreading something are using it day to day.


Html has a lot of flaws, but it's easy to learn, so it totally tracks to me that it could be in both categories. I wouldn't want to write a sizeable app in vanilla html, but I can't think of a simpler way to create cross-platform UIs


I'd consider Assembly a lot better language than SQL. You can't get proper testing framework what makes SQL hard - hundreds of lines queries with unknown amounts of joins/unions and not-well-defined relations.

It's not that's inherently dreaded, it just leans itself to a hard to follow one.


I've wondered sometimes if it's possible to quantify what I hate about hacking SQL so much, but it's hard. The language lacks something that I've taken to fuzzily call "localized mutation..." When I have to change someone's existing SQL, it usually involves jumping around in the text buffer a lot (i.e. wrapping an existing statement in parens to use it as a clause in a bigger statement, or having to split a clause that is now complicated enough into a separate WITH clause... These operations involve mutating text that can be dozens of lines separated, and all those mutations need to be coordinated.

It feels like a harder language to refactor than most I use.


Indeed, it's difficult to be isolated and split into smaller blocks (functions/classes/whatever). Effectively it's one massive statement with different clauses and data that's entirely publicly accessible in all aspects, no encapsulation and so on.

As a cheap excuse, I have come to think that 'loving' SQL does require a different mindset.


I love SQL.

I think you're spot on that it takes a different mindset. I treat it like a disposable expression of data, not a program. Essentially, I have data in one form, and I need to translate to this form, what is the logical representation of such a transformation?

If the results of an SQL are not as expected, I have no problem rewriting the entire thing rather than doing a "bug fix."


> I've wondered sometimes if it's possible to quantify what I hate about hacking SQL so much, but it's hard.

In my experience the "problem" is how detached it is from the underlying computational model. Even more so when you're working with columnar stores, querying Vertica with SELECT FROM WHERE is kind of weird.

Probably it's because I don't have a lot of experience with it, but I feel like I have to EXPLAIN every other query, I'm never confident what I said is what I mean.


  > I've wondered sometimes if it's possible to quantify what I hate about hacking SQL so much, but it's hard...
For me, any time I have to write any SQL statements it's the totally and utterly unhelpful error messages:

  >ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your DB server version for the right syntax to use near <insert really long SQL query>
...which, as far as I can see, haven't changed an iota in their total and utter vagueness since I first wrote an SQL query about 20 odd years ago.


For me, any time I have to write any SQL statements it's the totally and utterly unhelpful error messages:

  >ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your DB server version for the right syntax to use near <insert really long SQL query>
...which, as far as I can see, haven't changed an iota in their total and utter vagueness since I first wrote an SQL query about 20 odd years ago.


How are people doing SQL without looking at query plans and table statistics? I just don't understand the problems people have with SQL or stored procedures. Writing queries and proper table design are not that problematic.

Heck, we wrote a program at one point that dumped the operation being done by running queries. SQL is so much easier than a lot of other languages.


SQL is one of those languages that found its way outside of developer circles. My father-in-law knows SQL, and he's just about as far as you can get from your stereotypical developer. SQL is much easier than a lot of other languages, but it means people who have no experience with the ins-and-outs of software development are going to use it. These users are guaranteed to employ the language in ways that are not "proper" but instead ad-hoc and problematic.


Well, if they write one-off queries, it doesn’t really matter. The problem is when developers write bad queries that are often executed.


> [from Dilbert] Will there ever be an engineer who says "that last guy did a great job. Let's keep all of it"?

I don't know about other people here, but this is almost always how I feel? I almost always feel like the previous team made choices that were sensible given the facts at the time. Most changes I want to make come from the changes in our product since that chunk of code was written.

Of course I have my own methodological practices and sometimes I will re-write some particularly ugly copy & paste job the way I want "as a treat," but mostly if something works it works and you move on.

The best code is the code that already exists and works.


It sounds like you have empathy.

A lot of people look at issues with a code base and just assume the problem is due to stupidity. Rather than coming from the angle of, "this person was probably as capable as I am, why did they make this decision?"


Yeah, the trouble is that it's easy to update a method to account for a bug, but the cumulative effect of those changes tends to make a codebase more difficult to reason about for new starters.

In general, being able to take a few steps back and look at the whole system is often rewarding, but it's super difficult. Actually, people who come to a project later can often be great for this, as they can see the project as it is now, rather than as it evolved. Unfortunately, we tend to be quite bad at letting people take the time to build said mental model.

Also, most people hate reading code (or at least they don't take the time to do so). Personally, I really like reading code, and I find legacy projects much easier to work on than many of my colleagues.


I half agree. There is the notion that I actively don't like most of what is on the brown list. And I'm old enough to remember most of those things being new and have used a few of them. Also, I've done maintenance on a lot of code over the years (and still do). Including my own code. If you work products rather than projects and stick around long enough, this happens. Some stuff I've written in one language, I eventually rewrote in a different language. E.g. a lot of my early Kotlin code replaced Java code I wrote before. Kotlin made doing that particularly easy. These days, I rarely deal with Java code bases as I default to Kotlin for the last three years.

I've also done Ruby, Php and declined to ever touch VBA with a ten foot stick even when it was brand new. Just no. Php I never really liked but I appreciate what it does. Ruby was kind of alright but a bit limited for the things I do with it. I've deleted quite bit of it over the years. Some of it written by me.

There's a pattern that the author overlooks: the green languages address issues with the brown languages. E.g. Rust provides meaningful memory safety and other zero cost abstractions relative to C++. That's why a lot Github projects exist that essentially are about building better versions of classic unix tools in Rust. Also see the discussions about allowing Rust in the Linux kernel.

Kotlin was an obvious attempt to improve on both Java and Scala. Scala purists may disagree with that of course. The key issues there were lack of expressiveness in Java and the relative verbosity of that language. The issue in Scala that Kotlin tries to address is the complexity of that language. Jetbrains actually considered using Scala as an alternative to Java and in the end decided to create Kotlin instead.

With Ruby, people loved meta programming but the lack of typing made it less suitable for larger code bases. I've seen enough messy code bases to agree with that. There are several languages that you could name that ended up with a lot of former ruby-ists that basically feature powerful type systems, similar levels of expressiveness, etc.

So there's a progression of languages and programmers. Of course you use a green field language for a greenfield project. Why wouldn't you? Brown field projects are more common in this industry and rewriting them tends to be costly. So, that tends to not be a thing. Particularly successful things last a long time.


Just to keep in mind: StackOverflow deliberately removed Clojure from their surveys. People who embrace it are loving it to bits. Also Haskell and Clojure are not even in the Top 50 programming languages according to TIOBE.

"Languages not in the top 20 in 2016 are more likely to be used in new projects. "

Based on what statistic?

This is a wishful thinking article with very little basis in reality.


Clojure is statistically insignificant, that is why it was removed, what's the point of saying "Clojure is the most loved language" when only two out two voted for that.


Yeah this article is kind of a mess. It wants to have a data-driven perspective, but what the data shows is "people tend to like newer languages more." Now, this could be because there are fewer legacy projects in newer languages.

Or it could be because newer languages learned lessons from older languages. Python is still considered "well-loved" despite being pretty old, while its contemporaries C++ and Java are fairly disliked — this is (probably) because Python actually innovated over those other languages in a lot of ways. And languages which learned from Python (JS, TS, Julia, Dart) are all well-loved, with the possible exception of Ruby, which famously differs from Python with its TMTOWTDI philosophy.

I'm not necessarily saying that there is obviously a forward march of programming language progress, but it's worth noting that the data the author's looking at can just as easily acommodate that thesis too.


> StackOverflow deliberately removed Clojure from their surveys

How? When? Why?


Maybe we need more innovation in reading code. Language servers and autoformatters already are doing a lot. Visualizers could make it way easier too.

There's a general issue though that we haven't figured out the silver bullet for abstraction. Traits/typeclasses are convenient but they're inherently global. Interfaces are similarly global and are quite annoying when you have to take in two objects of the same type. Omitting traits and using something like modules can work but you lose quality of life stuff like easy printing (quick, how do you say something is printable in OCaml?). I'm not familiar with Erlang/Elixir but I suppose message passing could be an option, although I'm not sure how it'd work for memory intensive situations.

You could go the PL nihilism route and be against abstraction as a whole, but I don't think that's a valid answer. Abstraction is necessary for code to function at scale.


I think green/brown also applies for projects I've written myself (in my case older stuff tends to be Java or even PHP, newer stuff Python, Go). I've become a better programmer and when I have to touch code that I wrote a decade ago.. I sometimes cringe. That said I still think Go is objectively better than Java!


I share the following rule with younger developers and try to hold myself to it as well:

If you look back at code you wrote 12 months ago and don't think, "Ewww, what was I thinking here and why did I write it this way?", then you're not growing as an engineer. For very beginners, I change that to 4-6 months depending on how fast they're picking it up.


Interestingly, the author classifies python as a brown language, yet it's on the top 15 of most loved programming languages.

Now, maybe it's because for a lot of people, it's a green language since it only became that popular in the last 10 years despite being an old one (1991).

But for me it's definitely a brown language, as I've been using it since 2.4 (we are at 3.9). And I must say, reading a decade old Python code bases, even with the 2=>3 transition in the middle, is still very easy.

I went back to a project I wrote 10 years ago (first commit 2011), and the code is clear. I can make changes to it with no problem at all. And it's not even a small project, it's a streaming website that still serves half a million users a day using an old Django.

Today I'm working for a client on a FastApi project. It uses all the current modern Python gimmicks, async, typing and f-string and so on. I could get into the code base in less than a day, and make my first commit.

I know Python has the reputation to not scale, not be good for big projects or big teams, but It's certainly not have been my experience.

The upcoming Python 3.10 has been controversial because it introduce some weird choices for pattern matching. But it's the tree hiding the forest:

- it's a sign the language is still actively evolving and will not become obsolete. Legacy design decision will always make adding new features an exercise in compromises.

- 3.10 also have been focusing on not-s-sexy but oh-so-important things like improving the error messages (I'm actually very excited about this, I've followed it and it's very well done)

So I'm pretty confident it's going to stay a brown, but nice language to work with.

Not that's it perfect, the more I use other languages, the more I can see the limits of Python. But I expect it to still be a solid choice for new projects for a long time.


This is an interesting approach to take on analyzing the topic.

One confounding factor I can imagine is how many languages are created in response to lessons learned maintaining legacy code with other languages. We can see examples of design decisions explicitly made to address common and challenging patterns in other languages (Rust's static memory rules as a response to the unchecked non-garbage-collected memory patterns of languages like C++, for example).

This suggests a follow-up question: is it possible to see a pattern of languages ranking as beloved for longer and longer times depending on their newness? Sort of a "reverse half-life?" If, as an industry, we're getting better at developing languages, we might expect them to stay more well-loved for longer than the languages preceding them.


Isn’t it also true that newer languages might have learned from what made older languages hated? Isn’t a massive confound the possibility that language design as a field is meaningful and people are actually improving languages still?

I know the article mentions this, almost in passing, but it seems hard for me still to separate the size of the bias towards greenfield and against older languages and I don’t feel they adequately addressed it. The fact that python is definitely a “brownfield” language for me but still one I reach for and cherish as well designed seems to suggest that language design matters more to me.


Python seems like a notable exception - despite being of comparable age as Java, it is still mostly a loved language.


Large python backends are an absolute hell to deal with. Bad performance, no static typing, no clue what's going where and difficult to understand the flow even on modern IDEs. I guess most people haven't dealt with that and so even though it is old, it is cool.

Python for ML/DS use cases is chef-kiss though. This and newbie friendliness is where the love for Python comes from imo


Python 1.0 was directed more towards a programming literacy idea.

Python 2.0 from ~2000 was largely directed at web applications and text processing (a la Perl).

Python 3 (and later versions of Python 2) has been more directed (in the past decade) towards number crunching (numpy) and data analysis and machine learning.

It would be interesting to see a breakdown of perspectives on the language based on the applications it's been used for. Would web app maintainers still feel the love if they're maintaining something originating circa 2005, versus a data analysis app that was started in 2015.


I see nothing in Python 3 itself directed towards number crunching. Its integer performance actually worse than for Python 2 (because integers in 3 are big integers). nympy can be considered a DSL based on Python and it was used with Python 2 too.


I don't understand the point of your comment. I called out numpy for number crunching explicitly along with later versions of Python 2. I didn't say Python was good for number crunching, but that it's being used for number crunching and listed the library that has largely driven that trend (by making the language effective at number crunching).


Your phrasing actually did very much imply that Python the language was intended ("directed") for these tasks.

>Python 3 (and later versions of Python 2) has been more directed (in the past decade) towards number crunching

I don't know where "more directed" means anything but planned/intended e.g. you are saying here that the Python core devs have been building a language as a data analysis tool.

(This is obviously up to some interpretations and it's fair to say some poeple won't read it this way at all).

It sounds like you mean to say the growth/use has been in data analysis due to the Python-based tools that have grown up around the language, the ecosystem. I would agree with you.


Directed is an overloaded term. How people are using it is what the language is directed towards this is the sense I mean.

Directed could also mean intended by the developers of the language itself. This is not what I mean. Numpy is a secondary capability added by others, not core to the language proper.


Could you please elaborate then in which way Python 3 has been more directed towards number crunching?

I see that Fortran and Chapel are designed for number crunching, but Python IMHO used for this because it is a popular language in the first place and people having a computational problem choose the tool they already like.


I'm talking about what people are using it for, where the community (not necessarily the language's core devs) are directing its use. Contrast to the 00s, where it was not (as a general rule) being used for number crunching activities (ML or just regular number crunching a la Fortran or Matlab at the time). In the 10s, Python has been heavily used for applications in machine learning (and obviously number crunching heavy activity) and scientific simulation, data (number heavy) analysis, statistics work.

Prior to the 10s, those domains were more the purview of Fortran (as you list), Matlab, R (statistics), and others.

In the 00s, Python was more used for web applications and text processing (it was a "better" (subjective so in quotes) Perl).


I think this is a bit biased, their age might be the same, but the adoption rate is not - Python became much more popular in last years with DataScience boom, while Java was already popular before


The language itself is old, but I think there are much less old projects in Python. It is easy to imagine some enterprise software developed in Java during 15-20 years. But it would be hard to find something comparably boring in Python. On other hand Python is a popular choose in relatively new areas like ML and data science.


This is interesting to watch when it comes to Java/Kotlin. Everyone (including me) thought that Kotlin is a 'better Java'.

Time has passed and I am more and more convinced that the evolution of Java is just great. It's slow, but when something gets part of the language then it is almost always good (I'm talking about the post-JDK8 era).

So I think eventually Java will remain dominant over Kotlin.


It feels a bit like TypeScript to me, a bandaid over a wound. In time the wound heals and you don't need the bandaid anymore.


Strange to see R as dreaded... It's not a tool for everything, but for the right niche (data analysis), it seems like a very sensible choice.

Could it be that it's something that non-programmers are forced to use if they want to do some advanced stuff? And that these non-programmers dread programming in R not because of the language, but because it's programming.

If not, then what is so dreadful about R?


R is mostly just a different paradigm than most programmers are used to. A surprising number of them are scared off by R's 1-based indexing by default, or the slightly-unfamiliar syntax.

It's designed for REPL usage foremost, and with vectors / dataframes as the normal unit of operation. There's also a whole bunch of built-in functions with unfamiliar names and options, and R libraries tend to be similarly opaque to the user with a programming (non-stats) background.

For an R-like written for programmers, see Julia.


> For an R-like written for programmers, see Julia.

Yeah, if you look at the people behind dataframes.jl, it's a lot of people who were involved in R in the earlier days.

And there is no better environment for solving a data analysis problem than R. Python can work better for some DS use-cases (sklearn is ace), and it's definitely better for glue but if you need to understand what the hell is going on for a product/service/whatever, R is definitely the right choice.


"Sensible choice due to the ecosystem and tools" and "loving the language for its features" are two very different things.


I've used mostly C and orthodox C++ for more than twenty years and I am only starting to consider alternatives.

Zig and Jai are looking very nice, in my opinion.

I am pretty sure that Rust will follow a route similar to C++, too complex and too many young coders trying to embrace it without enough experience.


> "It’s harder to read code than to write it". Let’s call this Joel’s Law.

People have said "Spolsky's Law" for a long time about several different aphorisms, but when I hear it I assume people usually mean this one: http://www.joelonsoftware.com/articles/LeakyAbstractions.htm...


This quote from the article is interesting:

> Find me a file in a codebase that has been under active development for more than three years, and it will be hard to follow.

It might be true of enterprise [1] software, but is not generally the case.

The question is whether code quality is valued in a given environment. If it's not, it doesn't matter what language is used, a mess will be created. Despite words to the contrary from most enterprise software shops, code quality is usually not valued at all - if it were the patterns which prevail would... not.

By contrast, at random just now, I chose a popular device (Intel E1000 NICs), and looked at one of the files from the FreeBSD driver code for it [2]. This code written in C was added in 2008. The code is not "hard to follow" despite not being an expert on FreeBSD drivers, it has not atrophied or suffered from rot, while remaining under active development for at least 13 years. I didn't track the history beyond the addition of that file, so it's likely the code is actually older.

I could have performed this experiment on any project that values quality: Illumos, the Linux Kernel, LLVM, the Go standard library, and I'd wager the results would be similar more often than not.

[1]: "Enterprise" software is the (pejorative) term I tend to use to mean over engineered software with liberal use of frameworks and ORMs, generally at least 4-5 layers of mapping code adding no value, and an "architecture committee" - even if that committee consists of a single individual who also writes all the code for the project...

[2]: https://github.com/freebsd/freebsd-src/blob/main/sys/dev/e10...


Seems this "It’s because writing something new is cognitively less demanding than starting from scratch" could do with some editing. Doesn't new and scratch mean the same thing in this context?

"The reason that [ developers ] think the old code is a mess is because of a cardinal, fundamental law of programming: It’s harder to read code than to write it." Joel

I couldn't agree less with this. Currently working on a large codebase built on top of Apache ofbiz with Java. At intervals every dev involved in this project reminds our boss he shouldn't be using this codebase. Of course, events always remind us we are wrong because many features that would've taken months of dev time and work are already implemented and taken advantage of.

Anyway, takeaway, remind yourself - yeah - that reading code is hard!


There are so utterly terrible codebases, on which we should pull the plug.

But my experience is that even not-that-bad code bases will be seen as bad by new developers, solely because of their complexity (mostly inherent in this case). The thing is, programs grow continuously and they will pick up on complexity, and most software out there is simply beyond human understanding with every intricacy of it. And developer egos routinely say that the code is bad, instead of saying that they don’t understand the context of this and that decision.


Good catch. I have fixed it.

   It's because writing something new is cognitively less demanding than the hard work of understanding an existing codebase, at least initially.


I am very surprised that Python was not a "green" language. Why would you not use Python for various new Deep Learning projects? What would you use instead, then? I am questioning the author's Python assessment. Also, I do not program in Java, but I think many new corporate large-scale projects are done in Java these days (and in C#, if you are a Microsoft shop). Many new high-performance projects (Deep Learning infrastructure) are done in C/C++ for the reason of needing to manage memory directly. No new projects in JavaScript? What would you program the (new) browser scripts in, then? I am not sure what the brown-field languages are, really. COBOL is the one, for sure.

I think rating languages is a highly-perilous task and the author did not disappoint.


> What would you use instead, then?

Julia, for example.


This presents a strong case, IMO. And taking in account that studies have been made suggesting that language choice has little to no correlation with number of bugs[1], it would make sense that recency bias plays a part in, well, preference in technologies.

I'm interested in the outliers though: Both the ones among the loved brownfield languages, and the ones present in both loved and dreaded lists. I feel like programming language designers, people in charge of choosing the stack for new projects, and people considering renovating legacy codebases can learn a lot about what to do and what not to do from those.

[1]: Though that one ended up in a flame-war, like discussion on programming languages tend to do. Apparently not even academia is safe.


I'm seeing this a lot with SQL it seems.

ANSI SQL has been a thing since 1986, and SQL itself having been invented in the 1970s.

With the boom of JavaScript on the client, various forms of NoSQL came into existence. Recently, the HN frontpage has open source SQL management studios, Sqlite articles, and Node frameworks for directly executing SQL in JS.

It almost seems as if the greater development community is catching up to why these things have been done this way for a long time. People seem to be getting really interested in SQL, maybe because they are at a point in their careers where they are being exposed to it more and the benefits relational models can offer.

I'm not debating the benefits of one over the other, just that as trends go, SQL seems to be cool again.


I am probably wrong but I think all this conversation are heavily biased because:

1) it's mostly US centric 2) it's mostly Silicon Valley centric

Surveys say nothing because they are heavily biased, Google Trends too.

While we are discussing Rust vs Go, Python vs Ruby or whatever language is brought on the table, companies around the world are making millions with PHP and many other languages considered legacy.

At the end of day, we don't realize that the language and other tools we select to do our jobs are influenced not by how useful they are to solve our problems but how much they increase our chances to get a new job.

We disguise our choices as technical choices but they are not, they are, indeed, just our preferences biased towards our necessity to find better jobs.


The reason for reading code is hard as compared to writing code is that while writing code you already know "what" and you are figuring out "how" whereas while reading code you need to figure out both what and how at the same time.


I'm much more fascinated by the languages that made both lists. Any language (Haskell and Scala as well as---inexplicably---HTML, SQL and Shell programming) that makes both a 'most dreaded' and 'most loved' is probably interesting enough to investigate)

p.s. I must confess some disappointment at no Lisps on either initial list, especially on a Y Combinator site, but I think Haskell has usurped the "Language beloved by people who make it very clear they think they're better than you" throne. I blame Norvig's defection to Python.

pps: Shell? HTML? SQL? Really? Also: VBA is still a thing? Ewwww.


  >I've wondered sometimes if it's possible to quantify what I hate about hacking SQL so much, but it's hard.
For me, any time I have to write any SQL statements it's the totally and utterly unhelpful error messages:

  >ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your DB server version for the right syntax to use near <insert really long SQL query>
...which, as far as I can see, haven't changed an iota in their total and utter vagueness since I first wrote an SQL query about 20 odd years ago.


I may have missed a line in the original text, but I don’t find what are the 5 loved brown languages. I feel they may be the most interesting to learn, having passed the test of time and still being loved.


If you cross reference the two lists, it is: Python, C#, Swift, JavaScript, and SQL.


What I really enjoy about typescript is that the things I do frequently in java code require like a tenth of the effort to make.

Wrapping data into structure objects is pleasent in typescript, so I do it more. Same with handling missing entries. I don't need to wrap each indirection in yet another if statement to check for null; in typescript I can do the whole check at once and worry about what to do if I cant find the data using ??

When I'm working on the java code now, I'm mostly saying "this would be so much simpler to do in typescript"


Amusing that Scala and Haskell are on both the loved and hated lists.

Python and Javascript running counter to the author's premiss is not that odd to me. Both of these language do a good job of adapting to new approaches and technology. I am not a fan of untyped Python and Javascript, but Python with type linting and Typescript are great. Maintaining code without these features is a pain, while the newer code in the same project with these features is more interesting.


That's definitely a good explanation for language sentiment over a high number of developers.

I don't think these results or this article has much use in any language discussion, simply because I wouldn't trust the majority of developers to recommend a language.

I'd rather read why I should avoid Ruby on Rails magic from an expert.


Another possible explaination is simply that people have gotten better at designing programming languages. Or that newer languages are better adapted to solving the problems we now want to solve. Which really shouldn't be too hard to swallow.


I’m not sure how you’d distinguish the conclusions drawn from this paper from the hypothesis that the newer languages implement newer concepts in a more useful/ergonomic fashion.


Well following along the lines of the article, congrats to Python, Javascript and Swift for making it to the list of top loved languages despite being "brown" languages.


Stroustrup basically wrote this entire essay in a single sentence: "There are only two kinds of languages: the ones people complain about, and the ones nobody uses."


One trend that I notice is that most new languages focus their design on writability over readability. And by writability I mean prioritizing features that allow you to express more, while typing less code. These languages are specially prone to become "brown languages".

One classic example is Perl. One of the killer aspects of Perl is that it allowed you to write in just one line or two what in other languages would take dozens of lines and boiler plate. Writing Perl is actually really nice. You could go from idea to working code extremely fast. And that's why Perl became super popular two decades ago. However, maintaining a 100K LoC Perl website written by a lot of different people over 20 years, it's definitely not a nice experience.

I know this is going to upset a lot of people, but another extreme example is Lisp. I think I've never seen any language as expressive as Lisp. Once you grasp it, writing Lisp is really really nice. However, reading a complex Lisp program using a ton of macros and a lot of higher order functions could be really hard. In my experience some of the hardest code to read that I have ever encountered has been written in Lisp. And if reading is hard, I don't even want to talk about debugging. But okay, Lisp never really became super popular, so let's ignore it for now.

One more modern example: Kotlin. Kotlin's main improvements over Java are mostly on writability. Semantically, these languages are very similar. That's kind of intentional, as one of the goals of Kotlin is maintaining a very good interoperability with Java. However, Kotlin is nicer to write than Java. Java is verbose, Kotlin is succinct. Kotlin adds a lot of syntax and features to make you write the same things that you would express in Java but in a much shorter way. Writing Kotlin is so much nicer than writing Java, I'm sure of that.

I recently started working on a large Kotlin code base, and I can say that reading Kotlin is harder than reading Java. It turns out that verbosity is not a problem when actually reading code. And having few ways of expressing things actually makes code easier to read.

Languages with a lot of features and different ways of doing things are easily abused. You can still write readable code in them, but it requires a lot more discipline. It's so tempting to use that obscure language feature to make your code so succinct!

Python is a language that always put emphasis on readability. The developers of the language are famous for rejecting a lot of ideas to be added to the language. Even though Python is almost as old as Perl, so far, it has escaped from becoming a brown language and it's still loved. Who knows if it will remain like that.

Another language that seems very serious about this is Go. I know that there are a lot of Go haters here on HN, but you have to admit that Go designers put more emphasis on readability than writability. I predict that Go will escape from becoming a brown language.


Two words are enough: Rampant Neophilia.


Somehow Haskell ended up on _both_ the top 15 Loved and Dreaded lists...


Love how Haskell makes it into both loved and dreaded languages.


from the title and the URL, I thought this was going to be which languages are the most and least energy efficient.


Rust is already brown. I love it.


Ruby is a top dreaded language?!?!

People suck :(


Another article where SQL and HTML are listed as programming languages, great.


"There are only two kinds of languages: the ones people complain about, and the ones nobody uses." ― Bjarne Stroustrup


"This is blatantly false" -- Dude looking for COBOL developers




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: