Remix.run Logo
jchw 5 days ago

I think the true answer is that the moment you have to do tricky concurrency in Go, it becomes less desirable. I think that Go is still better at tricky concurrency than C, though there are some downsides too (I think it's a bit easier to sneak in a torn read issue in Go due to the presence of fat pointers and slice headers everywhere.)

Go is really good at easy concurrency tasks, like things that have almost no shared memory at all, "shared-nothing" architectures, like a typical web server. Share some resources like database handles with a sync.Pool and call it a day. Go lets you write "async" code as if it were sync with no function coloring, making it decidedly nicer than basically anything in its performance class for this use case.

Rust, on the other hand, has to contend with function coloring and a myriad of seriously hard engineering tasks to deal with async issues. Async Rust gets better every year, but personally I still (as of last month at least) think it's quite a mess. Rust is absolutely excellent for traditional concurrency, though. Anything where you would've used a mutex lock, Rust is just way better than everything else. It's beautiful.

But I struggle to be as productive in Rust as I am in Go, because Rust, the standard library, and its ecosystem gives the programmer so much to worry about. It sometimes reminds me of C++ in that regard, though it's nowhere near as extremely bad (because at least there's a coherent build system and package manager.) And frankly, a lot of software I write is just boring, and Go does fine for a lot of that. I try Rust periodically for things, and romantically it feels like it's the closest language to "the future", but I think the future might still have a place for languages like Go.

dev_l1x_be 4 days ago | parent | next [-]

> But I struggle to be as productive

You should calculate TCO in productivity. Can you write Python/Go etc. faster? Sure! Can you operate these in production with the same TCO as Rust? Absolutely not. Most of the time the person debugging production issues and data races is different than the one who wrote the code. This gives the illusion of productivity being better with Python/Go.

After spending 20+ years around production systems both as a systems and a software engineer I think that Rust is here for reducing the TCO by moving the mental burden to write data race free software from production to development.

zelphirkalt 3 days ago | parent | next [-]

TCO? Tail call optimization? But that doesn't make sense in this context. hm.

bodski 3 days ago | parent [-]

https://en.wikipedia.org/wiki/Total_cost_of_ownership

jchw 4 days ago | parent | prev [-]

With the notable inclusion of Google where the SRE team is usually separate from the SWE team (but it wasn't for my particular case) I actually was always doing operations and code at all of my jobs at least at points and usually during most of the job. This is in part my own election. I do mean all of them though I don't really love listing my work history publicly everywhere just to keep some separation.

So, my first job actually started as a pure Python gig. Operations for Python/Django absolutely sucked ass. Deploying Django code reliably was a serious challenge. We got better over time by using tools like Vagrant and Docker and eventually Kubernetes, so the differences between production and dev/testing eventually faded and become less notable. But frankly no matter what we did, not causing production issues with Django/Python was a true-to-life nightmare. Causing accidental type errors not caught by tests was easy and MyPy couldn't really cover all that much of the code easily, and the Django ORM was very easy to accidentally cause horrible production behavior with (that, of course, would look okay locally with tiny amounts of data.) This is actually the original reason why I switched to Go in the first place, at my first job in around 2016. The people who I worked with are still around to attest to this fact, if you want I can probably get them to chime in on this thread, I still talk to some of them.

Go was a totally different story. Yes, we did indeed have some concurrency pains, which really didn't exist in Python for obvious reasons, but holy shit, we could really eek a lot of performance out of Go code compared to Python. We were previously afraid we might have to move data heavy workloads from Twisted (not related to the Django stuff) to something like C++ or maybe even optimized Java, but Go handily took it and allowed us to saturate the network interface on our EC2 boxes. (A lot of communications were going over Websockets, and the standards for compression in websockets took a long time to settle and become universally supported, so we actually played with implementing the lz4 compression scheme in JS. I wound up writing my own lz4 implementation based on the algorithms, I believe, from the C version. It wound up being too much compute, though. But, we had to try, anyway.)

So how much reliability problems did we wind up having doing all this? Honestly not a whole lot on the Go side of things. The biggest production issue I ever ran into was one where the Kubernetes AWS integration blew up because we wound up having too many security groups. I wound up needing to make an emergency patch to kubelet in the early hours to solve that one :) We did run into at least one serious Go related issue over time, which was indeed concurrency related: when Go 1.6 came out, it started detecting concurrent misuses of maps. And guess what? We had one! It wasn't actually triggering very often, but in some cases we could run into a fairly trivial concurrent map access. It didn't seem to crash before but it could at least cause some weird behaviors in the event that it actually triggered before Go 1.6; now it was a crash that we could debug. It was a dumb mistake and it definitely underscores the value of borrow checking; "just don't mess up" will never prevent all mistakes, obviously. I will never tell you that I think borrow checking is useless, and really, I would love to just always write 100% correct software all the time.

That said though, that really is most of the extent of the production issues we had with Go. Go was a serious workhorse and we were doing reasonably non-trivial things in Go. (I had essentially built out a message queue system for unreliable delivery of very small events. We had a firehose of data coming in with many channels of information and needed to route those to the clients that needed them and handle throttling/etc. Go was just fantastic at this task.) Over time things got easier too, as Go kept updating and improving, helping us catch more bugs.

I can only come to one conclusion: people who treat Go and Python in the same class are just ignorant to the realities of the situation. There are cases where Rust will be immensely valuable because you really can't tolerate a correctness problem, but here's the thing about that Go concurrent map access issue: while it could cause some buggy behavior and eventually caused some crashing, it never really caused any serious downtime or customer issues. The event delivery system was inherently dealing with unreliable data streams, and we had multiple instances. If there was a blip, clients would just reconnect and people would barely notice anything even if they were actively logged in. (In fact, we really didn't do anything special for rolling deployments to this service, because the frontend component was built to just handle a disconnection gracefully. If it reconnected quickly enough, there was no visual disturbance.)

That's where the cost/benefit analysis gets tricky though. Python and Django and even Twisted are actually pretty nice and I'm sure it's even better than when we originally left it (to be clear we did still have some minor things in Django after that, too, but they were mostly internal-only services.) Python and Django had great things like the built-in admin panel which, while it couldn't solve everyone's needs, was pretty extensible and usable on its own. It took us a while to outgrow it for various use cases. Go has no equivalent to many Django conveniences, so if you haven't fully outgrown e.g. the Django admin panel and ORM, it's hard to fully give up on those features.

Throughout all of this, we had a lot more issues with our JS frontend code than we ever did with either Python/Django or Go, though. We went through trying so many things to fix that, including Elm and Flow, and eventually the thing that really did fix it, TypeScript. But that is another story. (Boy, I sure learned a lot on my first real career job.)

At later jobs, Go continued to not be at the center of most of the production issues I faced running Go software. That's probably partly because Go was not doing a lot of the most complicated work, often times the most complicated bits were message queues, databases and even to some degree memory caches, and the Go bits were mostly acting like glue (albeit definitely glue with application logic, to be sure.)

So is the TCO of Go higher than Rust? I dunno. You can't really easily measure it since you don't get to explore parallel universes where you made different choices.

What I can say is that Go has been a choice I never regretted making all the way from the very first time and I would choose it again tomorrow.

bombela 5 days ago | parent | prev | next [-]

It wasn't really tricky concurrency. Somebody just made the mistake of sharing a pointer across goroutines. It was quite indirect. Boils down to a function takeing a param and holds onto it. `go` is used at some point closing over this pointer. And now we have a data race in the waiting.

jchw 5 days ago | parent [-]

Aside from the type system bypass described in the article though, this is basically no different from the status quo for virtually all languages with free threading that aren't Rust. I argue that while everyone is fallible, experienced programmers usually don't make this sort of mistake directly, because they are usually well aware that sharing pointers over a closure on another thread is a recipe for disaster. Instead, I think that most of these issues are actually involving tricky circumstances that result in this happening by accident, like accidentally re-using an err variable from the enclosing function of a closure. These sorts of bugs are really bad, because they happen in spite of everyone knowing not to inappropriately share data across goroutines, and they are easy to sneak by in code reviews unnoticed. They don't intuitively look like concurrency bugs, and sometimes they're as little as one single : away from being correct. (Which I agree is a bad place for a language design to be.)

Thankfully though, people don't just throw their hands up there; a good amount of work has gone into figuring out the kinds of mistakes that often lead to Go concurrency bugs in the real world and writing static analysis tools that can help prevent them. That work, combined with Go's builtin tools and standard library, and the memory safety of individual isolated goroutines, makes most production Go concurrency bugs fairly boring even compared to C concurrency bugs, even though they theoretically have the same basic problem where you can freely share mutable data unsafely across concurrent threads.

So yes, it is still possible to write trivial, obvious concurrency bugs. The language won't stop you. However I've used Go across almost every job I've had since like 2016 and it has been rare to come across a concurrency bug this trivial. I hope I would catch flagrantly shared mutable state across threads during code review.

bombela 4 days ago | parent [-]

Yes experienced programmers won't make the obvious mistake... until they do because the distance from the source of the bug to it's manifestation is too great to notice until it fails in production.

jchw 4 days ago | parent [-]

Look, this is pointless. I'm not learning anything new when you tell me that it can and will happen. How will it happen and how much will it happen?

Hence linking to Uber's case study on the issue. The answer? Not that much.

Uber started performing race detection in production over a 6 month period and found 2,000 different race conditions. Ouch, that sounds horrible!

But wait, we're talking about 50 million lines of Go code and 2,100 services at the time of that writing. That means they were seeing approximately 1 race condition per 25,000 lines of code and about 1 race condition per service. That actually lines up pretty well with my experiences. Although I haven't had a production outage or serious correctness issue caused by a race condition in Go, I have seen probably about one or two race conditions that made it to production per service. I reckon those codebases were likely somewhere between 10,000 and 25,000 lines of code most likely, so not so far off of the scale.

But again it doesn't always lead to a serious production outage, it's just that simple. It could be worse too (could corrupt some data and pollute your production database or something, in the worst case) but usually it's better (wonky behavior but no long-term effects, maybe the service periodically crashes but restarts, leading to some dropped requests but no long term downtime.) Uber has no doubt seen at least some Go data races that have caused actual production outages, but they've seen at least 2,000 Go data races that haven't, otherwise they would've probably been caught before the race detector caught them, Go dumps stacktraces on crash. That has to tell you something about the actual probability of causing a production outage due to a data race.

Again, you do you, but I will not be losing sleep over this. It is something to be weary of when working on Go services, but it is manageable.

zozbot234 4 days ago | parent [-]

Identifiable "wonky" behavior and periodic crashes seem like a very real issue to me. This wouldn't fly for any mission-critical service, it's something that demands a root cause analysis. Especially since it's hard to be sure after the fact that no data has been corrupted somehow or that security invariants have not been violated due to the "wonky" behavior.

jchw 4 days ago | parent [-]

I am saying in no uncertain terms that most people here, and by most I am not talking simple majority stuff, have literally not once worked on software that is mission critical by any meaningful definition of "mission critical". Even Rust is questionable on truly mission critical software, since it does not actually prevent all runtime crashes and certainly not all correctness issues; you'd have to go further, towards something like Ada/SPARK for that. I kind of wish I could get into Ada/SPARK, too, to be honest, but it's a pretty big rabbithole it seems.

zozbot234 4 days ago | parent [-]

A meaningful definition of "mission critical" is just "serious money can be lost if this software crashes or misbehaves in problematic ways". That would seem to cover a whole lot of software that is not written in Ada/SPARK or anything comparable. I'm not talking about the "safety critical" kind where actual human lives may be at stake, only about the well known run-of-the-mill stuff.

jchw 4 days ago | parent [-]

In that case, when we're just talking about money, it's pretty easy to reason about this then, no? You can literally determine how much risk you're willing to take on by estimating what you might have to lose from such a bug and how much it might cost you versus how often they are likely to happen. The answer for how often is "not very often", and depending on the nature of the bug the monetary cost of it may be "pretty much $0" in the easy cases. Let's be conservative and say that you might see a moderate severity Go concurrency bug every 10,000 lines of Go code or so. That's still really not much. It means that a moderate sized 50,000 line code program might see like five of said kinds of bugs, and they might wind up being benign. Computers and networks are unreliable. Dropping some requests occasionally or having a weird bug for a small fraction of requests or database records is usually not going to cause you serious financial distress as a business.

When working on Go services it is nearly the last thing I am concerned about.

zozbot234 4 days ago | parent [-]

> Computers and networks are unreliable. Dropping some requests occasionally or having a weird bug for a small fraction of requests

This seems to come with the obvious implication that Golang should only ever be used to implement "services" that are essentially a part of the network infrastructure, passing requests along to other parts of the backend but not implementing any "logic" themselves (since that's where the correctness issues we're discussing might have severe consequences for the business). Isn't this a rather sobering take, all things considered?

jchw 4 days ago | parent [-]

No, no. It's just that boring glue software is the majority of all software. Seriously, it is. It's what most people here are writing most of the time.

Rust is surely good for when you are doing something vastly more complicated than boring web services, but if you try to write a database or message queue you are not going to pass Jepsen testing because you have a borrow checker present. Some of the most proven software in the world is written in programming languages with worse concurrency control than Go, like sqlite in C.

But, if you wanted to write something with super complex concurrency from scratch, you probably would opt to use Rust, because well, it's just good at that, and it probably is worth the up front and ongoing investment to entirely eliminate some classes of concurrency issues. But in those cases you need much more rigorous testing that will likely help to prevent menial concurrency bugs too, like running torture tests with race detection that try to ensure consistency guarantees hold up in all situations.

So are all Go programs of note just boring glue logic? Also no. I use tons of Go software every day that is a lot more than glue logic. Some examples include ESBuild, SyncThing, rclone, restic, and probably a bunch of other utilities of various shapes and sizes. People write databases and message queues and whatever else in Go too.

Still, yes most software is terribly boring. Most software is doing glue shit and basic CRUD operations and not much more. That doesn't mean that companies that write these kinds of software do nothing interesting, but even if they do, most of the software is going to be really god damned boring, because a lot of what we need to do is not super novel cutting edge stuff, and you don't rewrite a relational database or message queue system every single time you need one, you pick an off the shelf option and go on your way.

zozbot234 5 days ago | parent | prev [-]

> And frankly, a lot of software I write is just boring, and Go does fine for a lot of that. I try Rust periodically for things, and romantically it feels like it's the closest language to "the future", but I think the future might still have a place for languages like Go.

It's not so much about being "boring" or not; Rust does just fine at writing boring code once you get familiar with the boilerplate patterns (Real-world experience has shown that Rust is not really at a disadvantage wrt. productivity or iteration speed).

There is a case for Golang and similar languages, but it has to do with software domains where there literally is no viable alternative to GC, such as when dealing with arbitrary, "spaghetti" reference graphs. Most programs aren't going to look like that though, and starting with Rust will yield a higher quality solution overall.

Mawr 5 days ago | parent | next [-]

> (Real-world experience has shown that Rust is not really at a disadvantage wrt. productivity or iteration speed).

I don't believe that for a second. Even just going from Python to Go drops my productivity by maybe about 50%. Rust? Forget it.

Sure, if you have a project that demands correctness and high performance that requires tricky concurrency to achieve, something like Rust may make sense. Not for your run-of-the-mill programs though.

Yoric 5 days ago | parent | next [-]

Hey, going from Rust to Go drops my productivity by maybe about 50% :)

But more seriously, yeah, Rust doesn't make sense for trivial programs. But these days, I write Python for a living, and it doesn't take long to stumble upon bugs that Rust would have trivially detected from within the comfort from my IDE.

sophacles 5 days ago | parent | prev | next [-]

I believe your productivity drops as you say. I don't think it's inherent to the language though, at least not most of it. Rather it think it's a matter of familiarity and experience in each. When you're less practiced in a language, you're slower at it. I can write python fast, but im pretty slow at ruby. I've written a lot of python rust and go, and am about equally productive in them (although how that productivity is distributed through the dev cycle is different). It wasn't always this way, I was slow in each of them at first.

brabel 4 days ago | parent [-]

Rust is objectively harder to write than Go (or any other GC-language) because it exposes more concerns for the programmer to take care of. With Rust, you must always ensure your program complies with the borrow checker's rules (which is what makes Rust memory-safe) which includes having to add lifetime annotations to your variables in many cases. Go just doesn't have any of that. You could argue Rust still has an advantage in that it prevents bugs that in Go you're free to write, but then what you're claiming is that this compensates for the extra work you have to do upfront in Rust. That's a difficult position to defend, though, because an experienced Go developer probably has internalized how to avoid those bugs and the cost of preventing them can be nearly negligible. I do agree that they will still make mistakes, and those can have a cost, but they may also be quite rare, or may not matter much most of the time depending on your domain. I think that's why most people seem to agree Rust is probably only advantageous where the cost of data races in production is higher than the cognitive cost (which translates into increased effort) on the programmer.

sophacles 4 days ago | parent | next [-]

>Rust is objectively harder to write than Go (or any other GC-language) because it exposes more concerns for the programmer to take care of.

comparing apples to apples: Once you get a tiny bit of experience, almost all of that goes away. The common patterns and idioms in the language allow you to write whole programs without ever thinking about lifetimes or memory allocation or anything else different from the gc language case.

comparing apples to oranges: you do need to worry about those things when writing tricky memory management code that you couldn't even get from most gc lanuages... yeah then you have to worry about the things since it's a case where those things are the point.

> You could argue Rust still has an advantage in that it prevents bugs that in Go you're free to write, but then what you're claiming is that this compensates for the extra work you have to do upfront in Rust.

I have evidence in the form of multiple services and programs running in prod under heavy use for years without having to revist the code to deal with bugs. Meanwhile the stuff written in go has to be touched a lot to deal with bugs. The extra couple of weeks upfront to do it in rust is mitigated after the first incident with the go code. The effort proves worthwhile after the second incident.

Also tangentially related: the cost of an incident in the form of lost business, refunds, etc is usually far higher than the cost of a couple developer weeks.

>because an experienced Go developer probably has internalized how to avoid those bugs and the cost of preventing them can be nearly negligible

Some of them yes. But this is literally the same argument I'm making about rust experience meaning that you don't spend all that much extra effort up-front. Like I said, I'm about equally productive in go, python or rust.

> I think that's why most people seem to agree Rust is probably only advantageous where the cost of data races in production is higher than the cognitive cost (which translates into increased effort) on the programmer.

I think people who say this haven't gotten much experience in rust. In my experience they spent a week trying to learn rust and decided to stop and compare it to their years of other languages and paradigms.

brabel 4 days ago | parent [-]

> I think people who say this haven't gotten much experience in rust. In my experience they spent a week trying to learn rust and decided to stop and compare it to their years of other languages and paradigms.

I have written Rust for around 6 years now.

sophacles 4 days ago | parent [-]

That doesn't say much about experience. Ive written ruby at a rate of a few dozen lines/year, for the 20 years.

I guess I could say I've written ruby for 20 years... But someone full-time in ruby for only a year would likely be significantly better at the language than I am (i am bad at it).

zozbot234 4 days ago | parent | prev [-]

> an experienced Go developer probably has internalized how to avoid those bugs and the cost of preventing them can be nearly negligible.

And an experienced Rust developer has internalized the patterns (such as cloning or ARC) that are needed to cope with the borrow checker while writing prototype-quality, quick-iteration code. What's easier, fixing hard-to-spot bugs in the code or getting that code to compile in the first place?

zelphirkalt 3 days ago | parent [-]

I am not a fan of Golang or the approach taken to designing it, but I will say, that writing code in a certain way may even have zero cost, because after some time it may be natural to write code that way to someone. For example this works for programming paradigms. I am just as familiar with FP as with OOP and when writing FP code I avoid mutation. Does that make my code writing slower? Only in so far as a problem inherently is or is not more difficult to solve without mutation.

Ar-Curunir 4 days ago | parent | prev | next [-]

I am much more productive with Rust than any other programming language, except maybe python for programs shorter than 100 lines. Does that mean every other language has terrible productivity? No, it just means that I am more experienced with Rust. In general, experienced rust devs tend to be as efficient with Rust as other devs with other languages. There’s even Google data corroborating that internally Rust teams are as productive as Go teams

ralfj 4 days ago | parent | prev [-]

See https://www.youtube.com/watch?v=QrrH2lcl9ew for a a presentation of Google's study, which found no measurable difference in productivity between teams using Rust vs Go.

jchw 5 days ago | parent | prev [-]

Rust can yield a higher quality solution, but we can't make a perfect solution, we can only approach perfection. If we want to go further, we could introduce formally-proven code, too. Personally I'm interested in the intersection of proof assistants and Rust, like creusot-rs, and have been investigating it.

But as much as I love LARPing about correctness (believe me I do,) it's just simply the case that we won't right perfect software and it's totally OK. It's totally OK that our software will have artificial limitations, like with Go, only accepting filenames that are valid UTF-8, or taking some unnecessary performance/latency hits, or perhaps even crashing in some weird ass edge case. There are very few domains in which correctness issues can't be tolerated.

I don't deal with domains that are truly mission critical, where people could die if the code is incorrect. At worst, people could lose some money if my code is incorrect. I still would prefer not to cause that to happen, but those people are generally OK with taking that risk if it means getting features faster.

That's why Go has a future really. It's because for most software, some correctness issues are not the end of the world, and so you can rely on not fully sound approaches to finding bugs, like automated testing, race detection, and so on.

Rust can also make some types of software more productive to write, but it is unlikely to beat Go in terms of productivity when it comes to a lot of the stuff SaaS shops deal with. And boy, the software industry sure is swamped in fucking SaaS.

sophacles 5 days ago | parent | next [-]

A lot of sass people i know are more and more choosing rust for boring code. This includes several people who said things like "go is good enough, i don't want to deal with all the rust completely".

Once your sass products get enough users, and you're dealing with millions or billions of requests per day, those rare bugs start showing up quite often... And it turns out programming towards correctness is desirable, if for no other reason than to keep pagerduty quiet. Tolerating correctness issues isn't cost-free... People having to respond during off hours costs money and stress. I think most people would rather pay the costs at dev time, when they aren't under the pressure of an incident, than during an outage.

jchw 5 days ago | parent | next [-]

But correctness is not binary, it's more like a multidimensional spectrum. Your choice of programming language has some influence, as does standards and conventions, the ecosystem of your programming language, use of automated tooling like linting and testing, or even just ol' unreliable, discipline. Being a relatively greenfield language, Go is not in a terrible place when it comes to most of those things. Tons of automated tooling, including tools like the Checklocks analyzer or the many tools bundled with golangci-lint. Uber has done a pretty good job enumerating the challenges that remain, and even working at improving those issues too, such as with NilAway.

The question isn't "wouldn't you prefer more correctness?" it's "how much would you pay for how much of an improvement in correctness?".

Rust is still growing rapidly though, whereas Go is probably not growing rapidly anymore, I think Go has at least saturated it's own niche more than 50% and is on the other end of the curve by now. Last I checked Rust is the trendiest language by far, the one that people most wish they were writing, and the one that you want to be able to say your project is written in. So it would be extremely surprising to hear if there wasn't a growing Rust presence basically everywhere, SaaS's included.

lossolo 4 days ago | parent | prev | next [-]

> A lot of sass people i know are more and more choosing rust for boring code

It seems like you're in some kind of bubble, especially when looking at Rust usage in the industry.

> Once your sass products get enough users, and you're dealing with millions or billions of requests per day, those rare bugs start showing up quite often...

This is a blanket statement that's simply not true and I'm speaking as someone who uses Go in the exact scenario you described.

What kind of bugs are actually happening to these people? Do you have any real-world examples of the issues you're referring to, ones that suddenly start occurring only at the scale of millions or billions of requests per day to them?

zozbot234 5 days ago | parent | prev [-]

This is also in line with everything we know about good software engineering. Putting out fires in production is extremely costly, hence potential issues should be addressed at the earliest feasible stage.

josephg 5 days ago | parent | prev [-]

> Rust can also make some types of software more productive to write, but it is unlikely to beat Go in terms of productivity when it comes to a lot of the stuff SaaS shops deal with. And boy, the software industry sure is swamped in fucking SaaS.

I just wish Go supported parametric enums (sum types) and Option, rather than copying Hoare’s billion dollar mistake.

I ported some code to Go and rust a few years ago to try both languages out. The rust code ended up being 30% smaller because I could use an enum and a match expression. In Go I needed to make a set of types and interface{} to achieve the same thing - which was both slower and way more verbose. My rust implementation was as fast as my C implementation in 2/3rds as much code. And it was trivial to debug. My Go implementation took way more code to write - about the same amount of code as C, but it was harder to read than C and ran much slower.

For cookie cutter SAAS and prototypes, I prefer typescript. It’s fast enough for most things, and the type system is much more expressive without getting in your way. Not as convenient to deploy as go - especially on mobile. And the standard library is more like an attic. But in my opinion it’s a much better designed language.

Philpax 4 days ago | parent [-]

You're not the only one who wishes Go was just a bit more like Rust: https://github.com/borgo-lang/borgo

Sadly, that project seems to be dead, but I hope someone picks up its mantle some day. A marginally better Go could, well, go far.