A for-loop has what's called "mechanical sympathy", and will go through things in the order that it is in memory. It'll allow the compiler and runtime to manage things quickly through memory, CPU registers, and CPU pipelines.
A great post on the subject is "Why Go Getting Generics Will Not Change Idiomatic Go": http://www.jerf.org/iri/post/2955
Go's compiler is just particularly naive.
The compiler has definitely gotten more optimal over the years, but it's a different beastie than the rust one. Because go is not rust.
The main compiler is the self-hosting gc go compiler. Iirc ~~it's the reference implementation~~ erm I guess it's determined by spec, not reference implemenation. Gc is definitely "the default" though.
Then There's the gofrontend, which is a compiler frontend to other compilers, which can work with gcc and llvm. I am not aware of the state of the art for these, but I wonder if there are performance differences.
I disagree that it would be without sacrifice. That's kind of the whole point.
Unless I'm missing something, go has iterators with for loops.
Go's for loops can only iterate over builtin types: slices, maps, channels, etc. You can't produce a custom type that is to be iterated over.
The zero of Error is nil, so logically this would be Result(0, nil). But what do you set the internal state? It's not Ok, cause that int isn't used, and it's not Err either.
Option would work fine though and it would be amazing to map over options instead of nil checks.
I think you'd need to build Result on top of Option, it's naturally kind of ternary - "I have value" "I have error" "idk", either internally or externally.
What might be awesome would be if the Error were a slice type, nil would be "uninitialized" and empty slice means "initialized". still not...pleasant.
[0]: https://doc.rust-lang.org/std/default/trait.Default.html
Since it's implemented for Option<T> you can do it the same way [3] for that, but that's not available for Result<T,U> since the semantics are different from Option which is basically just Rust's alternative for 'null'/'nil' (but verifiable by the compiler).
Thus you'd have to choose what variant of the enum you want to have at initialization, after which you can use the Default implementation of the enclosed type, if available (and so on, if there are more nested types).
Though honestly I can't recall using the kind of pattern in Rust that would "need" something like that. Through the handling of code blocks as expressions, early returns etc. you for example don't need to initialize a variable before having an if-/match-/for-/while-/etc. block, you can simply use that block as an expression on the right side of the assignment [4].
[0]: https://play.rust-lang.org/?version=stable&mode=debug&editio...
[1]: https://doc.rust-lang.org/stable/error-index.html#E0381
[2]: https://play.rust-lang.org/?version=stable&mode=debug&editio...
[3]: https://play.rust-lang.org/?version=stable&mode=debug&editio...
[4]: https://play.rust-lang.org/?version=stable&mode=debug&editio...
It would also allow defer-like syntax to be used on the value a function returns, to return early from the calling function. Rust's ? is an excellent example of this, allowing explicit delegation of error handling that is still very lightweight syntactically.
Foo, err requires either that all receiving functions accept (foo, err), or manually nil-checking at every stage.
Try/catch is the least composable, because deeper error types can "jump out" from any layer. Which means you have to keep wrapping catches, until you hit some base layer you can recover from. You get stack traces, but you lose type information along the way.
Sum (result) and product (foo, nil) types preserve type information. Meaning you can operate more generically over it. Meaning less code duplication.
Very few languages outside of Rust and Haskell actually do this reliably and that's including languages like Ocaml and F#. Rust and Haskell are certainly the only even remotely popular languages that do it.
This is perhaps not the right way to measure, but: When I last checked the programming language benchmark game [0], the Haskell submissions were basically as fast as C/C++/Rust. But, this came at the cost of writing non-idiomatically/non-functionally – essentially abusing the language to write C in Haskell. I would be curious how well "idiomatic" Haskell compares to C++/Rust, in terms of the compiler optimizing away the functional abstractions.
[0] https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
Look at both
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
and
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
> with flambda under sufficiently strong optimization flags, such compositions of operators should be compiled to an actual loop with no overhead!
I can't bet on what Java and JavaScript JITs make of map / forEach / filter / reduce, but I suspect that they can be pretty efficient, given the clear delineation and the repeated patterns.
Nowadays I use Fastapi, pydantic, Result, and static typing everywhere. Protocol interfaces are great.
Fwiw - I do dabble in Go. I’ve used it for some very targeted systems work where I don’t have to install a python interpreter on the target machine and hacking some k8s operators. I really like Go - but the ML ecosystem is pretty heavily python.
Do it, do it nao! And by that, I mean at your earliest convenience. It's such a step up from Flask. All the serde is handled for you via Pydantic. No more manually vetting data. Just write constraints.
Are you seriously saying that github.com/somelib is a better package management? Of course nobody forces to use that, but it's what actually been used in most go projects. Even NPM looks better in comparison.
The best quality package management I've seen is Maven, followed by Cargo.
This doesn't mean people _will_ name their things sensibly of course. I've seen golang projects with packages named after gardening, meteorology, and aviation… and each is totally confusing when you're new to it, especially when the naming theme is completely unrelated to what the project actually does.
Here maven would be acceptable (similar to go, there is a domain identifier embedded) whereas cargo (bare words) wouldn't be great.
for private Go packages all I need is to point it to another git repo. for nuget/maven etc - I need an artifact registry, with it's own bells and whistles
Well, yeah, I mean if one can say Maven is best package management then I think I can get away by saying Earth is flat or stationary or some such interesting facts.
Github repos can vanish, NPM will only let repos be deleted if they have no direct dependencies also on NPM. So you have some guarantees your dependencies wont vanish.
You can also configure go to use your own for internal projects or if you just want to avoid the global proxy.
I'm hoping generics makes it easier to write things like numpy, without doing `meao_u8`, `mean_u16` etc.
+ there's bool, int/uint8,16,32,64, float32/64, complex64/128, that's 13 right there, plus object, a bunch of extended sizes on some architectures, and c-alias types.
But as someone who used to write a LOT of Python, Go has replaced it for anything service or business-logic oriented, and while I do very little data wrangling and machine learning, Julia would be my go to for that. Julia and Go are in, many ways, complementary opposites. If you need to use PyTorch/TensorFlow, okay, fine Python (I'm not going to seriously advocate for just wrapping it all in PyCall.jl unless it's just incidental usage), but Julia is a really strong language for this stuff nowadays.
It is hard to be done with OOP when Go also does OOP, even if in a different way than Python does it.
But Go has solid answers for these problems and an excellent static typing story (generics are gravy, but sum types would be nice). I’ve been very happy with Go on balance.
For things that are performance-critical or require high reliability, I have successfully used Rust, even if I am still much slower writing it. One thing I like is that the resulting code is not more verbose. Which also means that it is easy to read even after months of not touching it.
And python does have map / reduce and much more... so I'm not sure what you mean there.
OTOH, I feel Go and Python are mostly used in quite different domains. To me, Python is the new bash. Go is more for those who dislike C++ and Rust (or Haskell or...) and prefer a certain kind of simplicity.
Go felt good, a bit verbose, but my issue was that map/reduce/filter are a much better abstraction over imperative loops, and with generics, the dream of Go with more functional and high-level concepts is closer.
This comment is going to be very controversial, so let me remind you this is my very own opinion.