top | item 40211891

Borgo is a statically typed language that compiles to Go

666 points| manx | 1 year ago |github.com

545 comments

order
[+] tbrockman|1 year ago|reply
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).

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
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.
[+] saghm|1 year ago|reply
> 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.

[+] derefr|1 year ago|reply
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.)
[+] lordofgibbons|1 year ago|reply
Wow, this is everything I want from a new Go!

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
While I have no particular beef with Rust deciding to call its sum types "enum", to refer to this as the actual enum is a bit much.

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
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).
[+] throwaway17_17|1 year ago|reply
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.
[+] sevagh|1 year ago|reply

[deleted]

[+] ralegh|1 year ago|reply
Great! Something I've always wanted.

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
> 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.

[+] claudionaoto|1 year ago|reply
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.
[+] mattlondon|1 year ago|reply
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.
[+] VBprogrammer|1 year ago|reply
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?
[+] adsharma|1 year ago|reply
py2many does python-esque to both Go and Rust.

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
I like the graph at the top of the readme as a summary.

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
No traits, const generics, probably no turbofish equivalent for when inference struggles.
[+] giovannibonetti|1 year ago|reply
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.

[1] https://gleam.run/

[+] ffsm8|1 year ago|reply
> are not as performant as Go.

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
Go has an amazing runtime and tool ecosystem, but I’ve always missed a little bit more type safety (especially rust enums). Neat!
[+] preommr|1 year ago|reply
This and pub/private modifiers for structs instead of letter casing is all I've ever wanted.
[+] odc|1 year ago|reply
I love Go's letter casing. It's such a neat way to remove cruft.
[+] tredre3|1 year ago|reply
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.

[+] shepherdjerred|1 year ago|reply
I would kill for these languages features in Go
[+] neonsunset|1 year ago|reply
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.

[+] owenpalmer|1 year ago|reply
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.
[+] noisy_boy|1 year ago|reply
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.
[+] pjmlp|1 year ago|reply
You can get Rust's type system in most ML derived languages, some of them even go beyond what Rust is capable of today.
[+] eximius|1 year ago|reply
Be still my heart. I would use this so fast at work where we currently use Go.

But introducing a new language is a scary thing.

[+] littlestymaar|1 year ago|reply
Many people on HN “Rust syntax is so ugly”

rustaceans “I love the Rust syntax so much I want it in Go too”

[+] Scramblejams|1 year ago|reply
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.

[0] https://news.ycombinator.com/item?id=36847594

[+] pornel|1 year ago|reply
There’s no contradiction here.

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
In the same vein, Go+ is also interesting, and its being actively developed.

https://goplus.org/

[+] samuell|1 year ago|reply
Where's the list of "Awesome Go-derived languages"? :)
[+] metadat|1 year ago|reply
Is it correct to say Borgo "compiles to Go", or should it say "transpiles to Go"

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
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.

[+] PurpleRamen|1 year ago|reply
Readme says transpile: "Borgo is a new language that transpiles to Go."

And it's written in rust. Kinda unholy.

[+] frozenport|1 year ago|reply
Transpiler is a kind of compiler
[+] philosopher1234|1 year ago|reply
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.

Can anyone think of another example?

[+] templaedhel|1 year ago|reply
They made a coffeescript for go
[+] christophilus|1 year ago|reply
They made a Typescript for go. Coffeescript was dynamic.
[+] syngrog66|1 year ago|reply
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.
[+] tail_exchange|1 year ago|reply
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.