This addresses pretty much all of my least favorite things with writing Go code at work, and I hope--at the very least--the overwhelming positivity (by HN standards -- even considering the typical Rust bias!) of the responses inspires Go maintainers to consider/prioritize some of these features, or renews the authors interest in working on the project (as some have commented, it seems to have gone without activity for a little bit over half a year).
I have to disagree. I'm on record here lamenting Go. I've never really enjoyed writing it. When I've had to use it, I've used it. Lately though, I've found a lot more pleasure. And much of that comes from the fact that it does NOT have all these features. The code I write, is going to look like the code written by most other on my team. There's an idiomatic way to write Go, and it doesn't involve those concepts from other languages. (For better or for worse) So I'm super hyped that we'd have a "compiles TO Go" language, but I'm not as excited as using it as a catalyst to get new (and perhaps wrong for the language) features into Go.
> the very least--the overwhelming positivity (by HN standards -- even considering the typical Rust bias
As someone who has the "Rust bias", I feel like it's a bit of an open secret that a _lot_ of Rust developers don't actually need the extreme low-level performance that it offers and use it more because of the quality of life things (including some of the features in Borgo, but also tooling like cargo, rustdoc, etc.). I've said for a while that a language that focused on this sort of "developer experience" but used a GC to be a bit more flexible would probably be enough for a large portion of Rust developers, and pretty much everyone Rust developer I've talked to agrees with this (even if they aren't in the portion that would use this).
It's also pretty common for me to see people asking why someone would use a low-level, C++ language for something like web development, and I think the explanation is pretty similar; people like a lot of what Rust has to offer besides the low-level C++-like semantics, but there isn't something higher-level that offers enough of those features yet. Probably the language that would come closest to this is OCaml, but stuff like the documentation and "multiple preludes" are exactly the kind of thing that add friction to getting up and running, which is something Rust has invested a lot of time into reducing.
I think, for any language that "targets the Golang runtime", you do need some way to express to the runtime to "use the zero-value default initializer." Otherwise, you'd have no hope of code in your language being able to be used to define e.g. protobuf-compatible types; or of using Golang-runtime reflection (due to e.g. the interface zero-value.)
Having worked on multiple very large Go codebases with many engineers, the lack of actual enums and a built-in optional type instead of nil drive me crazy.
I think I'm in love.
Edit:
Looks like last commit was 7 months ago. Was this abandoned, or considered feature complete? I hope it's not abandoned!
Rather than the tagged union which the word represents in Rust, and only Rust. Java's enums are close, since they're classes and one can add arbitrary behaviors and extra data associated with the enum.
An Enum type has to be on the core Go team's radar by now. It's got to be tied with a try/catch block in terms of requested features at this point (now that we have generics).
About a year ago, I tried writing a language that transpiled to Go with many of the same features, in my research I found other attempts at the same idea:
I am genuinely appreciative that a post like this, a GitHub link to a semi-slow moving, but clearly well considered and sincerely developed programming language, can not only remain on the front page of HN, but can generate a diverse and interesting group of discussions. It’s material like this that keeps me coming back to the site. I’m not sure if anyone needed this comment, but I’m sure my posting it isn’t going to hurt.
I'd love to be able to use a bit more type-y Go such as Borgo, and have a Pythonesque dynamic scripting language that latches onto it effortlessly.
Dynamic typing is great for exploratory work, whether that's ML research or developing new features for a web app. But it would be great to be able to morph it over time into a more specified strongly typed language without having to refactor loads of stuff.
Like building out of clay and firing the parts you are happy with.
Could even have a three step - Python-esque -> Go/Java-esque -> Rust/C++esque.
> Like building out of clay and firing the parts you are happy with.
> Could even have a three step - Python-esque -> Go/Java-esque -> Rust/C++esque.
We do exactly that with Common Lisp. It compiles to different languages/frameworks depending on what we require (usually sbcl is more than enough, but for instance for embedded or ML we need another step. All dev (with smaller data etc) is in sbcl so with all the advantages.
Dart? Version 1 was a lot like Javascript/Typescript in one spec (a dynamic language with optional unsound typing). Version 2 uses sound typing, but you can still let variables unannoted (and the compiler will infer type "dynamic") for scripts.
Sounds like JavaScript and typescript would be a good fit for you. Highly expressive, dynamic and strongly typed, and highly performant both on server side and within the browser.
I like the idea but in all honesty I have difficulty imagining it working in practice. Once your python code is stable (i.e. You've worked out 99% of the bugs you might have caught earlier with strict type checking) would there be any incentive to go back and make the types more rigid or rigorous? Would there be a non-negligible chance of introducing bugs in that process?
This seems to achieve a similar type safety<->complexity tradeoff as Gleam [1] does. However, Gleam compiles to Erlang or JavaScript, which require a runtime and are not as performant as Go.
I wonder if Borgo's compiler messages are as nice as Rust's/Gleam's, though.
In other benchmarks, Golang does indeed win out with similar or even bigger advantages... so the only thing you can ultimately say is ... that it depends. Its a different story if you chose other languages though. But JS, Golang and Erlang are all extremely optimized for their ideal usecase.
Same. It's ugly, it breaks acronyms, it doesn't work in all (spoken) languages, it doesn't work well with serialization, etc.
Frankly if they insisted on visibility being part of the name, I would have preferred they go with the age-old C++/ancientPHP tradition of using a _ prefix for private members.
That's what C# offers (except true* Rust-style enums).
The latter will be there in one of the future versions and is in an active design phase, which luckily focuses on tagged-union implementation strategy.
With that said, you can already easily use one of the Option/Result libraries or write your own structure - switching on either is trivial (though you have to sometimes choose between zero-cost-ness and convenience).
It already has struct generics, iterator expressions (LINQ), switch pattern matching, good C interop and easy concurrency primitives (no WaitGroup nonsense, also has Channel<T>). Oh, and also portable SIMD, C pointers and very strong performance in general.
* True as in proper tagged unions with either a tag or another type of discriminant and aliased layout, instead of tag + flattening all constituent parts into a one jumbo struct. Or making it an opaque pointer to a box (like Java does, or C# if you go inheritance/interface route). These don't count. I'm curious about Borgo's lowering strategy for enums, but given Go doesn't have those, I'm not holding my breath and expecting something like F# struct unions at best.
This looks like an interesting sweet spot. Rust is often praised for the borrow checker, but honestly I really only like rust for the type system and error handling. Go is praised for it's simplicity, but hated for it's error handling.
Rust without borrow checker is much less feasible than Go with Result/Option types to address the nil overdose problem. Unfortunately Go team refuses to acknowledge the common themes coming out of years of user complaints. They don't have to cater to every wishlist but when nil/enum related complaints are the majority in every discussion about issues with Go, one would think to acknowledge the legitimacy of those shortcomings. Nope, not Go team and their band of simplicity zealots.
The author notes[0] that it keeps the Rust syntax to avoid having to write a parser.
I have no issue with the syntax but I think the chance of uptake would be considerably improved if the syntax were as close to Go's as reasonably possible. That's because I estimate Go programmers to be a better target for this than Rust programmers, but maybe I'm wrong.
Rust’s syntax looks alien to people who are not familiar with it, but the syntax itself is fine.
Some users also blame Rust’s syntax for being complicated when they actually struggle with Rust’s semantics, e.g. borrow checking wouldn’t be any less strict if Rust chose a less weird sigil for lifetime labels.
The word "transpiler" propagates the misunderstanding that there is something special about a compiler that emits machine code, that requires some special "compiler" techniques for special "compiler" purposes that are not necessary for "transpiler" purposes because "transpiling" requires a completely different set of techniques.
There aren't any such techniques. If one were to create an academic discipline to study "transpilers" and one to study "compilers", all you'd end up with is an identical bunch of techniques and analyses with different names on them. (A thing that sometimes happens when diverse disciplines study what turns out to be the same thing; see machine learning versus statistics for a well-known example.)
Even "compiling" to machine code isn't special anymore, because CPUs don't actually execute assembly anymore. They themselves compile assembly into internal micro-ops, which is what they actually execute. So compilers don't even compile "machine language" anymore; it's just another target. This also dodges "is it a 'compiler' or a 'transpiler' if it targets WASM?", which is good, because there is no value in that question on any level.
The only language I can think of that has pulled off “compiles to another totaling language” and gained mainstream adoption is typescript, and I’m sure it wouldn’t have done so if it were possible to run in the browser otherwise.
I'd never let a rando project on GitHub generate my code. Become dependent on their tiny new syntax AND let it generate the Go code that will actually be built from. Asking for things like backdoor insertion trick to be introduced later, after they have enough folks dependent on them and decide reward worth the risk. GitHub is The Jungle and all that entails.
Option instead of nil is amazing. Imo, the biggest flaw in Go's design is having nils instead of optionals.
I don't have a strong opinion on Result and Pattern matching - it seems nice, but I don't know if it adds much to the language. It is nice, but it may not be worth the complexity.
The error handling with ? is a no for me. I'd rather have something more like the go-errors/errors package in the standard library instead. This has been proposed before, and it was rejected for a good reason: it makes it too easy to be lazy and just bubble up errors instead of properly handling them.
[+] [-] tbrockman|1 year ago|reply
Some of the design decisions seem to me to be a bit more driven by being Rust-like than addressing Go's thorns though. In particular, using `impl` to define methods on types (https://borgo-lang.github.io/#methods), the new syntax for channels and goroutines (https://borgo-lang.github.io/#channels), and the `zeroValue()` built-in (https://borgo-lang.github.io/#zero-values-and-nil) seem a bit out of place. Overall though, if I had a choice, I would still rather write Borgo by the looks of it.
[+] [-] nobleach|1 year ago|reply
[+] [-] saghm|1 year ago|reply
As someone who has the "Rust bias", I feel like it's a bit of an open secret that a _lot_ of Rust developers don't actually need the extreme low-level performance that it offers and use it more because of the quality of life things (including some of the features in Borgo, but also tooling like cargo, rustdoc, etc.). I've said for a while that a language that focused on this sort of "developer experience" but used a GC to be a bit more flexible would probably be enough for a large portion of Rust developers, and pretty much everyone Rust developer I've talked to agrees with this (even if they aren't in the portion that would use this).
It's also pretty common for me to see people asking why someone would use a low-level, C++ language for something like web development, and I think the explanation is pretty similar; people like a lot of what Rust has to offer besides the low-level C++-like semantics, but there isn't something higher-level that offers enough of those features yet. Probably the language that would come closest to this is OCaml, but stuff like the documentation and "multiple preludes" are exactly the kind of thing that add friction to getting up and running, which is something Rust has invested a lot of time into reducing.
[+] [-] derefr|1 year ago|reply
[+] [-] lordofgibbons|1 year ago|reply
Having worked on multiple very large Go codebases with many engineers, the lack of actual enums and a built-in optional type instead of nil drive me crazy.
I think I'm in love.
Edit: Looks like last commit was 7 months ago. Was this abandoned, or considered feature complete? I hope it's not abandoned!
[+] [-] samatman|1 year ago|reply
Enumerated types are simply named integers in most languages, exactly the sort you get with const / iota in Go: https://en.wikipedia.org/wiki/Enumerated_type
Rather than the tagged union which the word represents in Rust, and only Rust. Java's enums are close, since they're classes and one can add arbitrary behaviors and extra data associated with the enum.
[+] [-] H1Supreme|1 year ago|reply
[+] [-] Hasnep|1 year ago|reply
- braid: https://github.com/joshsharp/braid
- have: https://github.com/vrok/have
- oden: https://oden-lang.github.io/
[+] [-] sharno|1 year ago|reply
[+] [-] throwaway17_17|1 year ago|reply
[+] [-] sevagh|1 year ago|reply
[deleted]
[+] [-] ralegh|1 year ago|reply
I'd love to be able to use a bit more type-y Go such as Borgo, and have a Pythonesque dynamic scripting language that latches onto it effortlessly.
Dynamic typing is great for exploratory work, whether that's ML research or developing new features for a web app. But it would be great to be able to morph it over time into a more specified strongly typed language without having to refactor loads of stuff.
Like building out of clay and firing the parts you are happy with.
Could even have a three step - Python-esque -> Go/Java-esque -> Rust/C++esque.
[+] [-] anonzzzies|1 year ago|reply
We do exactly that with Common Lisp. It compiles to different languages/frameworks depending on what we require (usually sbcl is more than enough, but for instance for embedded or ML we need another step. All dev (with smaller data etc) is in sbcl so with all the advantages.
[+] [-] claudionaoto|1 year ago|reply
[+] [-] mattlondon|1 year ago|reply
[+] [-] VBprogrammer|1 year ago|reply
[+] [-] adsharma|1 year ago|reply
The larger problem is building an ecosystem and a stdlib that's written in python, not C. Use ffi or similar instead of C-API.
[+] [-] DerSaidin|1 year ago|reply
The rest of the readme focuses on the delta between Go and Borgo. It doesn't say much about the delta between Borgo and Rust.
I think the delta there is mainly no lifetimes/ownership?
[+] [-] eximius|1 year ago|reply
[+] [-] giovannibonetti|1 year ago|reply
I wonder if Borgo's compiler messages are as nice as Rust's/Gleam's, though.
[1] https://gleam.run/
[+] [-] ffsm8|1 year ago|reply
Ymmv, you might be surprised if you actually bothered to benchmark. Depending on the workload, either JS or erlang can ultimately turn out on top.
They're all optimized to a degree that each has a niche it excells at and leaves the others in the dust.
even with heavily scewed benchmark like techempower fortunes (https://www.techempower.com/benchmarks/#hw=ph&test=fortune&s...) you end up with JS getting ahead of Go with raw requests. And not just slightly, but by 1.5 times the throughput.
In other benchmarks, Golang does indeed win out with similar or even bigger advantages... so the only thing you can ultimately say is ... that it depends. Its a different story if you chose other languages though. But JS, Golang and Erlang are all extremely optimized for their ideal usecase.
[+] [-] HippoBaro|1 year ago|reply
[+] [-] preommr|1 year ago|reply
[+] [-] odc|1 year ago|reply
[+] [-] tredre3|1 year ago|reply
Frankly if they insisted on visibility being part of the name, I would have preferred they go with the age-old C++/ancientPHP tradition of using a _ prefix for private members.
[+] [-] shepherdjerred|1 year ago|reply
[+] [-] neonsunset|1 year ago|reply
The latter will be there in one of the future versions and is in an active design phase, which luckily focuses on tagged-union implementation strategy.
With that said, you can already easily use one of the Option/Result libraries or write your own structure - switching on either is trivial (though you have to sometimes choose between zero-cost-ness and convenience).
It already has struct generics, iterator expressions (LINQ), switch pattern matching, good C interop and easy concurrency primitives (no WaitGroup nonsense, also has Channel<T>). Oh, and also portable SIMD, C pointers and very strong performance in general.
* True as in proper tagged unions with either a tag or another type of discriminant and aliased layout, instead of tag + flattening all constituent parts into a one jumbo struct. Or making it an opaque pointer to a box (like Java does, or C# if you go inheritance/interface route). These don't count. I'm curious about Borgo's lowering strategy for enums, but given Go doesn't have those, I'm not holding my breath and expecting something like F# struct unions at best.
[+] [-] owenpalmer|1 year ago|reply
[+] [-] noisy_boy|1 year ago|reply
[+] [-] pjmlp|1 year ago|reply
[+] [-] eximius|1 year ago|reply
But introducing a new language is a scary thing.
[+] [-] littlestymaar|1 year ago|reply
rustaceans “I love the Rust syntax so much I want it in Go too”
[+] [-] Scramblejams|1 year ago|reply
I have no issue with the syntax but I think the chance of uptake would be considerably improved if the syntax were as close to Go's as reasonably possible. That's because I estimate Go programmers to be a better target for this than Rust programmers, but maybe I'm wrong.
[0] https://news.ycombinator.com/item?id=36847594
[+] [-] pornel|1 year ago|reply
Rust’s syntax looks alien to people who are not familiar with it, but the syntax itself is fine.
Some users also blame Rust’s syntax for being complicated when they actually struggle with Rust’s semantics, e.g. borrow checking wouldn’t be any less strict if Rust chose a less weird sigil for lifetime labels.
[+] [-] lf-non|1 year ago|reply
https://goplus.org/
[+] [-] samuell|1 year ago|reply
[+] [-] metadat|1 year ago|reply
It appears to be a transpiler (consumes a Borgo and does the work to convert and emit a Go program as text):
https://github.com/borgo-lang/borgo/blob/main/compiler/src/c...
[+] [-] jerf|1 year ago|reply
There aren't any such techniques. If one were to create an academic discipline to study "transpilers" and one to study "compilers", all you'd end up with is an identical bunch of techniques and analyses with different names on them. (A thing that sometimes happens when diverse disciplines study what turns out to be the same thing; see machine learning versus statistics for a well-known example.)
Even "compiling" to machine code isn't special anymore, because CPUs don't actually execute assembly anymore. They themselves compile assembly into internal micro-ops, which is what they actually execute. So compilers don't even compile "machine language" anymore; it's just another target. This also dodges "is it a 'compiler' or a 'transpiler' if it targets WASM?", which is good, because there is no value in that question on any level.
[+] [-] PurpleRamen|1 year ago|reply
And it's written in rust. Kinda unholy.
[+] [-] michaelsbradley|1 year ago|reply
https://en.wikipedia.org/wiki/Source-to-source_compiler
[+] [-] frozenport|1 year ago|reply
[+] [-] unknown|1 year ago|reply
[deleted]
[+] [-] Qerub|1 year ago|reply
[+] [-] philosopher1234|1 year ago|reply
Can anyone think of another example?
[+] [-] templaedhel|1 year ago|reply
[+] [-] christophilus|1 year ago|reply
[+] [-] syngrog66|1 year ago|reply
[+] [-] tail_exchange|1 year ago|reply
I don't have a strong opinion on Result and Pattern matching - it seems nice, but I don't know if it adds much to the language. It is nice, but it may not be worth the complexity.
The error handling with ? is a no for me. I'd rather have something more like the go-errors/errors package in the standard library instead. This has been proposed before, and it was rejected for a good reason: it makes it too easy to be lazy and just bubble up errors instead of properly handling them.