[HN Gopher] Show HN: Error return traces for Go, inspired by Zig
       ___________________________________________________________________
        
       Show HN: Error return traces for Go, inspired by Zig
        
       Author : abhinavg
       Score  : 76 points
       Date   : 2023-11-29 13:01 UTC (9 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | Kharacternyk wrote:
       | The logo is awesome. Has an artist been hired to create it?
        
         | abhinavg wrote:
         | Thanks! No, just one of the maintainers with a free evening.
        
       | Eun wrote:
       | Can you explain why we should this over
       | https://github.com/pkg/errors?
        
         | para_parolu wrote:
         | Even this package is not needed anymore
        
           | dagss wrote:
           | How do you get stack traces of errors?
        
             | randomdata wrote:
             | The same way you get stack traces of names, email
             | addresses, random numbers, etc. It is funny how the word
             | 'error' leaves some suddenly forgetting how to write
             | software.
        
         | abhinavg wrote:
         | The README covers the idea behind errtrace in more details, but
         | the primary difference is in what is captured:
         | 
         | 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.
        
           | avg_dev wrote:
           | How does one go about implementing something like this? I am
           | quite curious.
        
             | yalue wrote:
             | Judging by the project, it's implemented by instrumenting
             | the source code; either manually modifying error returns
             | with a wrapper function, or by running source files through
             | an automated tool that will find and modify the return
             | statements for you.
        
             | marhee wrote:
             | I suspect it is based on https://pkg.go.dev/runtime#Caller
        
         | Groxx wrote:
         | At the very least:
         | 
         | > _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.
        
           | oefrha wrote:
           | It's archived mainly because it's been superseded by
           | fmt.Errorf() with the %w directive. Go 1.20 also introduced
           | errors.Join() and multi-%w which github.com/pkg/errors lack,
           | so using for green field projects is very ill-advised.
        
             | Groxx wrote:
             | Except for the stack trace part, which is a gigantic reason
             | why it was popular.
             | 
             | 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.
        
               | oefrha wrote:
               | It's pretty easy to write your own Errorf() wrapper or
               | some sort of WithStack() that stores
               | runtime/debug.Stack() output. github.com/pkg/errors
               | offers more flexibility in formatting though.
        
               | Groxx wrote:
               | Well, sure, but by that metric this library is _even
               | easier_ to build yourself since it 's only gathering a
               | single stack entry per wrap. And it has no backwards
               | compatibility to worry about.
               | 
               | "You can build X by hand too" has little to do with why
               | people choose to create or use libraries.
        
               | healsdata wrote:
               | > "You can build X by hand too" has little to do with why
               | people choose to create or use libraries.
               | 
               | In my experience, "you can build X by hand" is the Go
               | community's preferred approach.
        
             | pstuart wrote:
             | It would be great if the internals added %W as an option
             | that would also include the relevant trace. Shouldn't be
             | unreasonable or impossible.
        
       | pixelpoet wrote:
       | (Aside about Zig, sorry. Although this applies to Go as well, I
       | think?) Urgh I am _so_ keen to switch to Zig but their attitude
       | towards having vector operators just completely kills the
       | viability for me as a graphics programmer.
       | 
       | 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.
        
         | Night_Thastus wrote:
         | I'm a C++ dev, could you explain a bit of what is missing in
         | Zig for vector operations? Does Zig not have operator
         | overloading?
        
           | klyrs wrote:
           | Nope, no operator overloading. As I understand it, the
           | philosophy is to not hide O(n) behavior behind notation that
           | looks O(1).
        
             | Night_Thastus wrote:
             | Strange.
             | 
             | 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)
        
               | klyrs wrote:
               | I didn't mean to volunteer to defend this choice, but
               | without investigating a function you can't really support
               | an opinion about its runtime. A language can make such
               | promises about its basic syntax however.
               | 
               | Perhaps I'll rephrase how I understand the philosophy: if
               | it's a function call, it should look like a function
               | call. Operator overloading breaks that.
               | 
               | That said, this isn't my hill to die on.
               | 
               | Edit to clarify my final sentence there: I have zero
               | interest in debating this any further. Pixelpoet, if
               | you're going to be so fussy, go read Harvey and van der
               | Hoeven and stop trying to win language fights, they're
               | tedious.
        
               | pixelpoet wrote:
               | I appreciate your being such a good devil's advocate,
               | however as ForkMeOnTinder points out, there is already
               | the super complicated[0] overloaded O(N^1.58+) operator
               | for arbitrary precision integer multiplication, easily
               | argued to be vanishingly less useful than simple vector
               | operators, particularly if they were well-expressed at
               | the IR level and well-mapped to modern hardware /
               | instructions.
               | 
               | The ask isn't for general operator overloading (I'm also
               | in favour of not having that), rather just not stopping
               | native algebraic type support at scalars; the C function
               | atan2(y, x) basically just wants to give you the complex
               | argument, for example. Really it would just do so much to
               | unify and simplify everything, besides being able to
               | write vector stuff in a sane way; if every rando has to
               | write their own vector and complex number classes, I'm
               | much less likely to vouch for its correctness.
               | 
               | [0] I've recently been looking into Karatsuba
               | multiplication to reduce it from O(N^2) to O(N^1.58):
               | https://en.wikipedia.org/wiki/Karatsuba_algorithm
        
             | ForkMeOnTinder wrote:
             | And what's funny about that stance is mathematical
             | operators aren't actually O(1).
             | 
             | https://en.wikipedia.org/wiki/Computational_complexity_of_m
             | a...
             | 
             | You don't want to know what the innocent-looking `*` in
             | this function compiles to:                 fn square(num:
             | u10000) u10000 {         return num * num;       }
        
               | pixelpoet wrote:
               | It's mildly offensive that u10000 is a builtin type but
               | vec2f is not (also note that I am not asking for general
               | operator overloading!). Which has dedicated CPU
               | instructions across all modern architectures, what's the
               | relative usage frequency, what's the cost/benefit of
               | each, etc etc... :( And we all know why u10000 is in
               | there: because you have to have arbitrary-width integers
               | when writing a compiler, so they figured eh, we'll just
               | expose that because we have it already. Absolutely
               | transparent compiler-programming (cf. rendering-
               | programming) bias, almost nobody else needs that.
               | 
               | And yeah, I get that Add(Add(Add(a, b), Mul(c, 3)), d) is
               | possible, but come on... imagine if you had to write your
               | normal "a + b + c * 3 + d" with ints/floats like that!
               | What's that, suddenly people care, but nobody cares if
               | it's not their field...
               | 
               | Whatever, I will continue to look longingly at Zig for
               | all the bits of C/C++ (and apparently Go, to try bring it
               | back to the original topic) it solves, but missing the
               | trivial and absolutely critical single feature to enable
               | an entire class of performance-critical programming.
        
               | defen wrote:
               | > And we all know why u10000 is in there: because you
               | have to have arbitrary-width integers when writing a
               | compiler
               | 
               | You don't need them as a built-in type to write a
               | compiler. They're there because LLVM was the original
               | backend and you essentially get them for free (in the
               | sense that the backend code generation is already handled
               | for you, so why not include them).
        
         | truckerbill wrote:
         | It is strange that we stop at scalars for algebra in most
         | languages. Odin's approach is almost more frustrating, allowing
         | for quaternion types, but not clifford algebra which can
         | elegantly describe them and much more(though i know it's a
         | comically niche request at this point in time)
        
           | reactordev wrote:
           | agreed, further with today's parallelism it _should_ be
           | trivial but like you said, most languages stop at scalars and
           | force the onus on you. I get it, higher order math is an
           | implementation detail but to not provide the proper tools for
           | those implementations is frustrating.
        
           | pixelpoet wrote:
           | The main thing that stands out about this comment to me
           | (agreeing 100% about algebraic types) is the "at this point
           | in time" bit, such boundless optimism :D
        
         | ForkMeOnTinder wrote:
         | That's one of the downsides of a BDFL. Zig is like 98% amazing,
         | and 2% strange decisions that I think could have been avoided
         | if the creator had more experience with languages other than C
         | and Javascript.
         | 
         | I'm still a happy Zig user though, and hey, there's still time
         | before 1.0.
        
           | pixelpoet wrote:
           | He's actually fluent in a lot of languages[0]. Just somehow
           | apparently not much sympathy for numerical computing, or UI
           | code (I'm fairly sure you want 2d vectors there too), or
           | plotting, or ...
           | 
           | [0] https://andrewkelley.me/post/not-a-js-developer.html
        
           | dilyevsky wrote:
           | Not supporting operator overloading is not a "strange
           | decision" it's widely hated feature outside of very specific
           | domains (like maths and graphics) and every shop i worked at
           | which bothered with a c++ guideline banned it
        
             | snovv_crash wrote:
             | Banned for in-house use, sure. Require an extra review
             | before including a library, sure. But don't tell me you
             | refuse to use Eigen and force everyone to write their own
             | matrix multiplication routines that don't have operator
             | overloading...
        
               | dilyevsky wrote:
               | That is why I specifically mentioned math and graphics as
               | exceptions. Honestly I still like explicit DSL model
               | better for these than trying to build dsl on top of your
               | existing language c++/lisp style
        
         | zoogeny wrote:
         | I was watching a recent talk about the new Mojo language [1].
         | There is a section on SIMD and how they treat scalar values as
         | a special case of vector operations (around the 33 min time).
         | 
         | 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
        
           | sevagh wrote:
           | >I've heard people joke that AI is just matrix multiplication
           | 
           | Not sure where the joke is, today's deep learning based AI
           | models are literally matrix multiplications with learned
           | weights.
        
           | xh-dude wrote:
           | Julia has good ideas, interesting trade-offs here as well.
           | ISTM the deep problem is that there's so much room for
           | optimization under composition of operations or with
           | invariants not captured in types that the typical LinAlg
           | library will never capture. But I agree most languages should
           | be anticipating that users need something helpful here.
        
         | lll-o-lll wrote:
         | Doesn't this open github issue imply that vector operators are
         | still being considered?
         | https://github.com/ziglang/zig/issues/7295
         | 
         | Or is it that the three years it's been around indicate it will
         | never progress?
        
           | pixelpoet wrote:
           | This is far better than my attempts at initiating the
           | discussion, thanks for linking!
           | 
           | Also it seems like even the discussion of Geometric Algebra
           | has been covered before 3 years ago: https://github.com/zigla
           | ng/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 :(
        
         | el_oni wrote:
         | Odinlang is a language in a similar space that seems to have
         | first class support for matrix and vector operations. As well
         | as having built in support for various graphics apps [0].
         | 
         | Seems like there is a bunch of interesting low level languages
         | gaining steam at the moment.
         | 
         | [0] https://odin-lang.org/news/major-graphics-apis/
        
       | Vanclief wrote:
       | While from a first instance, this package seems a bit overkill, I
       | think the idea is interesting and is something that can be
       | improved for Go.
       | 
       | 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.
        
       | zgk7iqea wrote:
       | go is step by step reinventing exceptions
        
       ___________________________________________________________________
       (page generated 2023-11-29 23:01 UTC)