Here's an example that compares them: https://pkg.go.dev/braces.dev/errtrace#readme-comparison-wit...
Since the HTTP library uses a separate goroutine to create connections, the stack trace at creation time doesn't have details about the user request that triggered the connection.
I also felt that Go errors where too bare-bones, so I developed a small package (https://github.com/Vanclief/ez) based on an awesome post that I saw here once. I use this package in all Golang code I touch.
I guess the difference we try to make is that we really wanted to make errors that are understandable by users. Each time the error is returned we try to wrap it with an information where and why.
I've asked in their Discord, Andrew Kelley himself passed on commenting (I know his stance, every C++ dev wants their fav feature), but the reality remains that it's just infeasible to do with a DSL so it's just the wrong language for writing graphics code.
It does seem that tensors are one of the core abstractions for modern ML systems. I've heard people joke that AI is just matrix multiplication. Python is such a flexible language that creating abstractions around its syntax was super easy. I believe that was part of the reason Python has come to dominate this space (not the only reason obviously).
I too felt the same as you, but as a distant admirer of Zig. I totally understand that operator overloading can be misused. But I have an intuition that at least providing operators for linear algebra (and probably complex/quaternion) is a really important feature for any languages from this point in history going forward.
1. https://www.youtube.com/watch?v=SEwTjZvy8vw&ab_channel=LLVM
providing operators for linear algebra (and probably complex/quaternion) is a really important feature for any languages from this point in history going forward.
This is why I have started using Fortran for writing AI model inference code. It natively handles array manipulation like python and has a `matmul` intrinsic and compiles into fast code. There are some rough edges, but it's great as a low level matrix programming language which was its original point.Not sure where the joke is, today's deep learning based AI models are literally matrix multiplications with learned weights.
I'm still a happy Zig user though, and hey, there's still time before 1.0.
C# has operator overloading and during my whole career I have never seen it abused so hard that people needed to ban it, let alone write guidelines and a lot of shops adopting it.
I barely see anyone use it not for really good cases like graphics.
The only interesting case was using "/" operator for Path Combines so "home" / "folder1" performs Path.Combine("home", "folder1")
but still, that was PoC or lib, not even prod.
So, is it about community, some culture or actually what?
C++ also allows you to overload short-circuiting operators, but of course your overload can't short-circuit so you just silently destroyed an important feature. Why ?
As others have pointed out, several languages have been able to provide this feature without causing half the mess and disappointment. Ten years ago if you said move assignment semantics are a bad idea you might persuade people because the C++ move semantics are messy, but hey, turns out a fresh language is able to just provide the destructive move developers actually wanted (but couldn't pull off for C++) and that's really nice.
This isn't a pedantic nerd snipe; the point is that operator overloading really is indispensable in certain contexts.
Seems like there is a bunch of interesting low level languages gaining steam at the moment.
Or is it that the three years it’s been around indicate it will never progress?
Also it seems like even the discussion of Geometric Algebra has been covered before 3 years ago: https://github.com/ziglang/zig/issues/7295#issuecomment-7389...
Unless it's actually possible after all this time (even in some random beta) to do vector code in infix notation, it doesn't feel like it's going to happen :(
Zig won't ship with llvm as part of the standard download, but i imagine it will be easy to get zig+llvm working
a #everything_until_the_next_space b is rewritten in #everything_until_the_next_space(a,b)
So you'd have:
-a #foo b #foo c is foo(foo(a,b),c)
-a #foo b #bar c is forbidden, use parenthesis.
-and maybe #: for the inverse composition where a #:foo b #:foo c is foo(a, foo(b,c))
It's explicit, no hidden overloading, yet it's "short" enough to be usable: (a #* b) #+ c isn't that much worse than a*b+c and is much more readable than madd(mmul(a,b),c)..
If there is no implicit conversion name clashes shouldn't be too bad (both #+ could be usable for matrix and for graphic libraries).
https://en.wikipedia.org/wiki/Computational_complexity_of_ma...
You don't want to know what the innocent-looking `*` in this function compiles to:
fn square(num: u10000) u10000 {
return num * num;
}How is that different from say, a function call? A function may look like a single O(1) operation from the input/output/name, but actually do something much more complex. That seems like the same thing to me, and very common. (and frankly I'm not sure that could even be avoided)
pkg/errors captures a stack trace of when the error occurred, and attaches it to the error. This information doesn't change as the error moves through the program.
errtrace captures a 'return trace'--every 'return' statement that the error passes through. This information is appended to at each return site.
This gives you a different view of the code path: the stack trace is the path that led to the error, while the return trace is the path that the error took to get to the user.
The difference is significant because in Go, errors are just plain values that you can store in a struct, pass between goroutines etc. When the error passes to another goroutine, the stack trace from the original goroutine can become less useful in debugging the root cause of the error.
As an example, the Try it out section (https://github.com/bracesdev/errtrace/#try-it-out) in the README includes an example of a semi-realistic program comparing the stack trace and the return trace for the same failure.
>This repository has been archived by the owner on Dec 1, 2021. It is now read-only.
It's largely complete so it is essentially fine at the moment, but it won't be adapted to future language or community changes. A future landmine.
tbh I'm not sure what the current popular option is for wrapping with stack traces.
Re join: it isn't a joiner-error, it has no need to do anything for that. Just stdlib-join-then-wrap.
As far as error handling is concerned, errors as values is the modern thinking. Go is not behind the times here. If you squint, the `(T, error)` return type is very similar to Rust's `Result`, and the `if err != nil` idiom is basically Monadic control flow.
This requires the kind of squinting where 9 x 9 = 81 is basically the same as 9 + 9 = 18 right? I mean, they're roughly the same symbols, albeit one at slightly different angle, and in a different order...
Result is a sum type, as are a lot of key things in Rust. Take the Rust type Result<bool,()> - this has three possible values, Ok(true), Ok(false), Err. The analogous Go product type has four possible values, (false,false) (false, true), (true, false) and (true, true).
I can add stack traces and raise panics all day long in my code and it will never help me trace a deep error in my system. The collective blindness to that in the go world is staggering.