Re: [go-nuts] Re: Breaking an io.Pipe loop

2024-06-18 Thread Harri L


I pointed out that maybe exec.Cmd.StdinPipe and exec.Cmd.StdoutPipe would 
be better. Here’s the *modified* sample from this thread and the complete 
program for easier copying to play with—no deadlock with this.
func main() { defer err2.Catch() cmdName := "/bin/bash" cmdArgs := []string{
"-c", "sleep 5"} cmd := exec.Command(cmdName, cmdArgs...) cmdStdinW := 
try.To1(cmd.StdinPipe()) cmdStdoutR := try.To1(cmd.StdoutPipe()) go func() 
{ defer err2.Catch() // No need to close the pipes 
try.To1(io.Copy(cmdStdinW, cmdStdoutR)) fmt.Println("copier ends") }() 
try.To(cmd.Start()) // we cannot use just Run() with Cmd.XxxPipe calls... 
try.To(cmd.Wait()) // ... according to docs fmt.Println("all OK") } 

The entire program sample:
package main import ( "fmt" "io" "os/exec" "github.com/lainio/err2" 
"github.com/lainio/err2/try" ) func main() { defer err2.Catch() cmdName := 
"/bin/bash" cmdArgs := []string{"-c", "sleep 5"} cmd := 
exec.Command(cmdName, cmdArgs...) cmdStdinW := try.To1(cmd.StdinPipe()) 
cmdStdoutR := try.To1(cmd.StdoutPipe()) go func() { defer err2.Catch() // 
No need to close the pipes try.To1(io.Copy(cmdStdinW, cmdStdoutR)) 
fmt.Println("copier ends") }() try.To(cmd.Start()) // we cannot use just 
Run() with Cmd.XxxPipe calls... try.To(cmd.Wait()) // ... according to docs 
fmt.Println("all OK") } 
​
On Tuesday, June 18, 2024 at 7:47:06 AM UTC+3 Ian Lance Taylor wrote:

> On Mon, Jun 17, 2024 at 7:49 PM Salvatore Domenick Desiano
>  wrote:
> >
> > Here's a hopefully semantically identical minimal example:
> >
> > func main() {
> >
> > cmdName := "/bin/bash"
> > cmdArgs := []string{"-c", "sleep 5"}
> > cmdStdinR, cmdStdinW := io.Pipe()
> > cmdStdoutR, cmdStdoutW := io.Pipe()
> > go func() {
> >
> > defer cmdStdinW.Close()
> >
> > io.Copy(cmdStdinW, cmdStdoutR)
> >
> > }()
> > cmd := exec.Command(cmdName, cmdArgs...)
> > cmd.Stdout = cmdStdoutW
> > cmd.Stdin = cmdStdinR
> > if err := cmd.Run(); err != nil {
> >
> > fmt.Println(err)
> >
> > }
> >
> > }
> >
> > This program deadlocks after seconds. The three locked Go routines are 
> the io.Copy( (stuck inside io.Copy because cmdStdoutR doesn't close), the 
> exec.Command Go routine (also stuck in an io.Copy) and the main routine 
> (stuck in cmd.Wait()).
>
>
> I haven't checked whether this is the problem, but as someone else
> pointed out this is a strange place to use io.Pipe. Much better to
> use os.Pipe. Much better still to use exec.Cmd.StdinPipe and
> exec.Cmd.StdoutPipe.
>
> Ian
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/53ebdd3a-9f8a-4a42-8575-6c0ecd75e850n%40googlegroups.com.


Re: [go-nuts] Fwd: cmd.Wait & io.Pipe & SIGKILL

2024-06-17 Thread Harri L


I’m wondering if there’s a specific reason you’re using io.Pipe instead of 
the Cmd.StdoutPipe helper? When using io.Pipe you need to Close the pipe by 
yourself, but when using the Cmd.StdoutPipe, the Cmd.Wait will close the 
pipe for you.

Here’s a sample following your previous example:
func main() { defer err2.Catch() cmdName := "/bin/sh" cmdArgs := []string{ 
"-c", "for i in 1 2 3 4 5 6 7 8 9 10; do echo step $i; sleep 0.1; done", } 
cmd := exec.CommandContext(context.Background(), cmdName, cmdArgs...) 
stdoutPipe := try.To1(cmd.StdoutPipe()) var wg sync.WaitGroup go 
readPipe(stdoutPipe, &wg) try.To(cmd.Start()) wg.Wait() try.To(cmd.Wait()) 
fmt.Println("DONE") } func readPipe(src io.Reader, wg *sync.WaitGroup) { 
defer err2.Catch() wg.Add(1) defer wg.Done() buf := make([]byte, 256) for 
eof, n := try.IsEOF1(src.Read(buf)); !eof; eof, n = 
try.IsEOF1(src.Read(buf)) { try.To1(os.Stdout.Write(buf[:n])) } } 

And here’s a sample using io.Pipe; please see the noted line:
func main() { defer err2.Catch() cmdName := "/bin/sh" cmdArgs := []string{ 
"-c", "for i in 1 2 3 4 5 6 7 8 9 10; do echo step $i; sleep 0.1; done", } 
cmdStdoutR, cmdStdoutW := io.Pipe() cmd := 
exec.CommandContext(context.Background(), cmdName, cmdArgs...) cmd.Stdout = 
cmdStdoutW var wg sync.WaitGroup go readPipe(cmdStdoutR, &wg) 
try.To(cmd.Run()) cmdStdoutW.Close() // NOTE: needed for io.Pipe ↓ 
fmt.Println("DONE") wg.Wait() } 
​
On Monday, June 17, 2024 at 6:21:13 AM UTC+3 Salvatore Domenick Desiano 
wrote:

> Ah!
>
> I apologize... in reducing it to a compact example I didn't notice that I 
> changed the semantics of what the code was doing. You are, of course, right 
> about the cause of the deadlock in this code.
>
> That said, working backward from the self-contained example to my full 
> code clarified the actual issue I'm debugging. It is sufficiently different 
> from what I said here that I will start a new thread if I can't figure it 
> out myself.
>
> Thank you!
>
> -- Salvatore
> smile.
>
>
> On Sun, Jun 16, 2024 at 10:35 PM Robert Engels  
> wrote:
>
>> It hangs because cmd.Run() waits for the process to complete - and with 
>> nothing reading the pipe it will never complete. 
>>
>> On Jun 16, 2024, at 9:33 PM, Robert Engels  wrote:
>>
>> 
>> It looks like you don’t have anything reading from the pipe so it’s going 
>> to hang. 
>>
>> On Jun 16, 2024, at 8:54 PM, Salvatore Domenick Desiano <
>> near...@gmail.com> wrote:
>>
>> 
>> Simpler self-contained example, same result:
>>
>> func main() {
>>
>> cmdName := "/bin/bash"
>> cmdArgs := []string{"-c", "while true; do echo step; sleep 1; done"}
>>
>> cmdStdoutR, cmdStdoutW := io.Pipe()
>> cmd := exec.Command(cmdName, cmdArgs...)
>> cmd.Stdout = cmdStdoutW
>> if err := cmd.Run(); err != nil {
>>
>> fmt.Println(err)
>>
>> }
>> fmt.Println("DONE")
>>
>> cmdStdoutR = cmdStdoutR
>>
>> }
>>
>> For the sake of completeness I'll mention that this runs fine if 
>> cmd.Stdout is not assigned, which points to exec.awaitGoroutines() as being 
>> the culprit.
>>
>> FWIW, I have no direct evidence that the pipes aren't being closed on the 
>> SIGKILL. That said, the (exec-internal) goroutines are hung on io.Copy(). I 
>> expect that if the process's output pipe was actually closed the io.Copy() 
>> would return, the goroutine would complete, and the deadlock would not 
>> happen.
>>
>> -- Salvatore
>> smile.
>>
>>
>> On Sun, Jun 16, 2024 at 7:58 PM Salvatore Domenick Desiano <
>> near...@gmail.com> wrote:
>>
>>> I hope this isn't a red herring but in constructing a self-contained 
>>> example I triggered a deadlock. Perhaps the deadlock is the answer to my 
>>> question or perhaps it is another issue. Either way this code does not seem 
>>> malformed:
>>>
>>> func main() {
>>>
>>> cmdName := "/bin/bash"
>>> cmdArgs := []string{
>>>
>>> "-c",
>>>
>>> "while true; do echo step; sleep 1; done",
>>>
>>> }
>>> cmdStdinR, cmdStdinW := io.Pipe()
>>> cmdStdoutR, cmdStdoutW := io.Pipe()
>>> cmdStderrR, cmdStderrW := io.Pipe()
>>> ctx, cancelCmd := context.WithCancel(context.Background())
>>> cmd := exec.CommandContext(ctx, cmdName, cmdArgs...)
>>> cmd.Stdin = cmdStdinR
>>> cmd.Stdout = cmdStdoutW
>>> cmd.Stderr = cmdStderrW
>>>
>>> if err := cmd.Start(); err != nil {
>>>
>>> fmt.Println(err)
>>>
>>> }
>>>
>>> cmdStdinW.Close()
>>> if err := cmd.Wait(); err != nil {
>>>
>>> fmt.Println(err)
>>>
>>> }
>>>
>>> fmt.Println("DONE")
>>>
>>> cancelCmd = cancelCmd
>>> cmdStdoutR = cmdStdoutR
>>> cmdStderrR = cmdStderrR
>>>
>>> }
>>>
>>> If you run this code and SIGKILL the bash process, go flags it as a 
>>> deadlock and panics. FWIW, this also happens if there are goroutines 
>>> monitoring cmdStdoutR and cmdStderrR.
>>>
>>> What am I missing?
>>>
>>> -- Salvatore
>>> smile.
>>>
>>>
>>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to golang-nuts...@goo

Re: [go-nuts] io.Reader can return (n, err), both non-zero

2024-03-21 Thread Harri L


+1

I’d love to hear more about the motivation behind the io.EOF as an error. 
And why select a strategy to prefer *no* *discriminated unions* for the 
error results? Why transport non-error information in error values (io.EOF, 
'http.ErrServerClosed)?

“Normal” vs. “error” [control flow] is a fundamental semantic distinction, 
and probably the most important distinction in any programming language - 
Herb Shutter

The io.Reader has caused many problems during its existence. Even so, the os 
packages official documentation  and the File.Read 
example starts with a potential bug and incorrect io.Reader usage. Should 
the if clause be:
if err != nil && err != io.EOF { ... 

The issue #21852  gives an 
excellent overall picture of how deep unintuitive io.EOF usage can affect 
Go’s code and test base. It includes an interesting comment that maybe Go 2 
will fix the io.Reader. Now it’s official that there will never be Go 2, 
maybe io.Reader2?
​
On Wednesday, March 20, 2024 at 6:39:29 AM UTC+2 Nigel Tao wrote:

> On Wed, Mar 20, 2024 at 2:13 PM Ian Lance Taylor  wrote:
> > Some earlier discussions:
> >
> > https://groups.google.com/g/golang-nuts/c/b78eRMOS0FA/m/jq8lAQhenaoJ
> > https://groups.google.com/g/golang-nuts/c/WGYJx3ICCW4/m/1L0WcN8eqmkJ
> >
> > See in particular this message from Russ:
> > https://groups.google.com/g/golang-nuts/c/b78eRMOS0FA/m/sbbgr9MUo9QJ
>
> Russ said:
>
> > Once in a while we think about changing the definition
> > to require n==0 when err==EOF but it doesn't help the
> > more general case, a partial read that returns an error
> > saying why more data wasn't returned (disk error, etc).
>
> OK, partial reads are a thing, but one possible design (in hindsight,
> not now) was to push the complexity in tracking that into Read
> callees, not Read callers. Instead of a callee returning (positiveN,
> nonNilErr), have it save nonNilErr to a struct field and return (0,
> nonNilErr) on the next Read call.
>
> I'd expect fewer programmers writing callees than callers, and they'd
> generally be more experienced Go programmers. Anecdotally, when I was
> doing a lot of Go code reviews some years ago, I'd often have to point
> out the "Callers should always process the n > 0 bytes returned before
> considering the error err" comment, often to the programmer's
> surprise.
>
> While it's relatively easy, *if you already know*, to do this:
>
> n, err := r.Read(buffer)
> doStuffWith(buffer[:n])
> if err != nil {
> return err
> }
>
> instead of this:
>
> n, err := r.Read(buffer)
> if err != nil {
> return err
> }
> doStuffWith(buffer[:n])
>
> it's not really obvious if you don't know that you don't know. And
> sometimes doStuffWith is more than just "something += n". If
> doStuffWith can itself lead to further errors (e.g. you're parsing the
> bytes you've just read), you also have to be careful not to clobber
> the err variable.
>
> Anyway, it's far too late to change it. I was just wondering if there
> was some motivating reason that I'd otherwise missed.
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/3f26b58e-b451-4fdd-b0b8-17638a30ce4en%40googlegroups.com.


Re: [go-nuts] assert library with generics?

2024-02-28 Thread Harri L


I’m biased as well. FWIW, this is a subpackage of the error handling 
solution, err2 .

The assertion pkg  
is proven to be a precious tool for many projects. It is unique because it 
can be used both for the test and production code runs. You’ll set, e.g., 
assert.NotEmpty(s) in whatever function you need. It’ll be checked in test 
runs *and* regular main() started runs. And all of this is done 
automatically.

For instance, if a currently tested function A calls a function B that uses 
this assertion package and violates assertion, the test fails in function 
A’s caller. Still, you get the whole location list to the call stack no 
matter how deep the call stack is to the function B. This works even over 
Go module boundaries, but you need help with the error result listing, 
e.g., the Vim plugin.

Naturally, the happy path performance has been necessary, and, e.g., 
assert.That is the same as if condition.
​
Br,
-Harri

On Monday, February 26, 2024 at 12:53:10 PM UTC+2 roger peppe wrote:

> I'm biased because I had a big hand in designing the API, but I get a lot 
> of pleasure from using this package:
>
> https://pkg.go.dev/github.com/go-quicktest/qt
>
> It does a lot more than just "equals" and "not equals" but it's still 
> relatively small and low-dependency.
> And the error messages when it fails are decent too.
>
>   cheers,
> rog.
>
> On Thu, 22 Feb 2024 at 08:20, Harmen  wrote:
>
>> Hi,
>>
>> anyone has a tip for a nice (small) "assert" test help library which uses 
>> generics for the "equals" and "not equals" functions?
>>
>> testify is the obvious library to use for tests, which works fine, but it 
>> would
>> be nice to have something which uses generics here.
>>
>> Thanks!
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to golang-nuts...@googlegroups.com.
>>
> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/golang-nuts/ZdcDz2ULDQl02Z3R%40arp.lijzij.de
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/15daa57e-9f5e-4594-a4a9-5b4a96b7838cn%40googlegroups.com.


Re: [go-nuts] Re: Error handling

2023-08-04 Thread Harri L
if err != nil {
>> return fmt.Errorf("copy %s %s: %v", src, dst, err)
>> }
>>
>> if _, err := io.Copy(w, r); err != nil {
>> w.Close()
>> os.Remove(dst)
>> return fmt.Errorf("copy %s %s: %v", src, dst, err)
>> }
>>
>> if err := w.Close(); err != nil {
>> os.Remove(dst)
>> return fmt.Errorf("copy %s %s: %v", src, dst, err)
>> }
>> }
>>
>> - new approach ratio 5:5
>> func CopyFile(src, dst string) error {
>> r, err := os.Open(src) *orelse* return fmt.Errorf("copy %s %s: %v", src, 
>> dst, err)
>> defer r.Close()
>>
>> w, err := os.Create(dst); *orelse* return fmt.Errorf("copy %s %s: %v", 
>> src, dst, err)
>> err := io.Copy(w, r) *orelse* {
>> w.Close()
>> os.Remove(dst)
>> return fmt.Errorf("copy %s %s: %v", src, dst, err)
>> }
>>
>> err := w.Close() *orelse* {
>> os.Remove(dst)
>> return fmt.Errorf("copy %s %s: %v", src, dst, err)
>> }
>> }
>>
>> On Sunday, July 30, 2023 at 9:27:27 PM UTC-6 Marcello H wrote:
>>
>>> I think the current error handling is just fine.
>>> For the extra typing, they invented keyboard snippets and such.
>>>
>>> But for this proposal, I would like to see how a return with multiple 
>>> values would look to get a better understanding.
>>> ```
>>> // translate this in the proposed solution?
>>> func myFirstFunction() (string, err) {
>>>result, err := myFunction()
>>>if err != nill {
>>>return rest, err
>>>}
>>> }
>>> ```
>>>
>>> Op maandag 31 juli 2023 om 04:32:01 UTC+2 schreef DrGo:
>>>
>>>> Another possibility Jeremy is that the orelse block is executed if any 
>>>> of the returned error values is not nil. 
>>>>
>>>> On Sunday, July 30, 2023 at 8:14:58 PM UTC-6 DrGo wrote:
>>>>
>>>>> Thanks...
>>>>> yes indeed. Too many requirements but I think this solution comes 
>>>>> close to meeting them. If a rare function returns more than one error 
>>>>> value 
>>>>> (yet to see one in the wild) then the compiler should reject orelse use 
>>>>> and 
>>>>> the user can fallback on the (the if err!= nil) approach. 
>>>>>
>>>>> On Sunday, July 30, 2023 at 6:02:57 PM UTC-6 Jeremy French wrote:
>>>>>
>>>>>> Also, errors are values, which means - although uncommon - a function 
>>>>>> could return two or more error values.  Which would orelse evaluate?  
>>>>>> Even 
>>>>>> if you arbitrarily chose one, that would violate the explicit vs 
>>>>>> implicit 
>>>>>> code flow principle.  
>>>>>>
>>>>>> My sympathies, OP.  I too hate the "if err!= nil" boilerplate, and 
>>>>>> have suggested my own idea for fixing it, which was similarly dismantled 
>>>>>> for good reasons by those more knowledgeable than me.  The truth is, 
>>>>>> this 
>>>>>> problem/issue has so many restrictions placed on it (currently idiomatic 
>>>>>> principles, backwards compatibility promise, explicit vs implicit, etc) 
>>>>>> that the set of possible solutions is VERY narrow, possibly infinitely 
>>>>>> so.
>>>>>>
>>>>>> On Sunday, July 30, 2023 at 3:51:49 PM UTC-4 Brian Candler wrote:
>>>>>>
>>>>>> err := io.Copy(w, r) *orelse* {
>>>>>> w.Close()
>>>>>> os.Remove(dst)
>>>>>> return fmt.Errorf("copy %s %s: %v", src, dst, err)
>>>>>> }
>>>>>>
>>>>>> My question still stands. Semantically, what value exactly does the 
>>>>>> "orelse" condition test is not equal to nil?
>>>>>>
>>>>>> - does it test the value from the preceding assignment? If so, is 
>>>>>> "orelse" only valid immediately following an assignment expression? The 
>>>>>> original posting didn't say this.  And if it *is* linked to an 
>>>>>> assignment 
>>>>>> expression which assigns multiple values, does it only look at the last 
>>>>>> value? (Again, that was not specified)
>>>>>>
>>>>>> - does it always test a variable called "err"? Th

[go-nuts] Re: Error handling

2023-07-30 Thread Harri L
IMHO, you have used the irrelevant example (== 2nd code block) from Russ 
Cox's paper. The paper says:
> This code is not nice, not clean, not elegant, *and still wrong:* like 
the previous version, it does not remove dst when io.Copy or w.Close fails.

I want to compare your proposal with the third example from the paper, 
which does (proper) error annotation and cleanup. Thanks.
On Sunday, July 30, 2023 at 8:57:15 AM UTC+3 DrGo wrote:

> I looked at the long list of proposals to improve error handling in go but 
> I have not seen the one I am describing below. If I missed a similar , can 
> you pls direct me to where I can find it. If not what do you think of this 
> approach. 
>
> This involves introducing a new keyword "orelse" that is a syntactic sugar 
> for an "if err!=nil" block.
>
> The example code in Russ Cox's paper[1] will look something like this:
>
> func CopyFile(src, dst string) error {
>
> r, err := os.Open(src) orelse return err 
>
> defer r.Close()
>
> w, err := os.Create(dst) orelse return err
>
> defer w.Close()
>
>   err = io.Copy(w, r) orelse return err
>
> err = w.Close() orelse return err
>
> }
>
> It is an error to not return an error from an orelse block.
>
> In my eyes, this has the same explicitness and flexibility of the current 
> style but is significantly less verbose. It permits ignoring the error, 
> returning it as is or wrapping it. Because orelse is not used for any other 
> purpose, it would be easy for reviewers and linters to spot lack of error 
> handling.  
>
> It also works well with named returns. e.g., 
>
> func returnsObjorErro() (obj Obj, err error) {
>
>   obj, err := createObj() orelse return  //returns nil and err
>
> } 
>
> otherwise orelse is like "else" so e.g., it can be followed by a block if 
> additional cleanup or error formatting etc is needed before returning, eg 
> w, err := os.Create(dst) orelse {
>   
>   return err 
> }
>
> Similarity to "else" hopefully means that it is easy to learn. It is 
> obviously backward compatible  
>
> What do you think?
>
> [1] 
> https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/2f8d00bb-bb77-4932-9ccb-370db58fa9afn%40googlegroups.com.


Re: [go-nuts] [RFC] Yet another proposal for Go2 error handling

2023-07-02 Thread Harri L
The sample block below is what we can have without any language updates. I 
will let you decide your thoughts about its readability, but please note 
that even the error strings are built automatically—error propagation with 
error traces, of course.  Deferred error handling seems to clarify certain 
things, like errors from a rollback in this case. The full playground 
. (Please remember to try the automatic 
error traces when playing with it.)

func (db *Database) MoneyTransfer(from, to *Account, amount int) (err 
error) {
defer err2.Handle(&err)

tx := try.To1(db.BeginTransaction())
defer err2.Handle(&err, func() {
if errRoll := tx.Rollback(); errRoll != nil {
err = fmt.Errorf("%w: ROLLBACK ERROR: %w", err, errRoll)
}
})

try.To(from.RecerveBalance(tx, amount))

defer err2.Handle(&err, func() { // optional, following sample's wording
err = fmt.Errorf("cannot %w", err)
})

try.To(from.Withdraw(tx, amount))
try.To(to.Deposit(tx, amount))
try.To(tx.Commit())

return nil
}

We have used the err2 package  in 
production for business-critical systems for four years. And yes, I'm the 
author of the OSS package.

On Friday, June 30, 2023 at 8:04:01 AM UTC+3 Mike Schinkel wrote:


   
*func (db *Database) Transfer(from, to Account, amount int) (err error) {*  
   
*err = db.Begin()* *when err != nil **goto noTrans*
 *if **from*
*.Balance() >= amount {* 
* goto noFunds* *}*
 *err = **from*
*.Withdraw(amount)* *when err != nil **goto **noWithdraw*
 
*err = to.Deposit(amount)* *when err != nil **goto **no**Deposit*
 
*err = db.Commit()* *when err != nil **goto **no**Commit*
 
*return nil* 
*:noCommit:*   
*db.Rollback()*   
*return fmt.Errorf("cannot commit; %w", err)* 
*:noDeposit:*   
*db.Rollback()*   
*return fmt.Errorf("cannot deposit; %w", err)* 
*:noWithdraw:*   
*db.Rollback()*   
*return fmt.Errorf("cannot withdraw; %w", err)* 
*:noTrans:*   
*db.Rollback()*   
*return fmt.Errorf("cannot begin transaction; %w", err)* 
*:noFunds:*   
*db.Rollback()*   *return errors.New("no funds")*
 *} *8. Using the example above, is there not a way to also annotate 
the error in a shared manner vs. having to have all the different handle 
labels and duplicated code?

-Mike

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/fadd6051-bb65-4625-b1b2-9e87c40bf328n%40googlegroups.com.


[go-nuts] Re: Error Handling

2023-02-12 Thread Harri L
A package err2  helps you to implement the 
`errReturn` even though Go doesn't have macros or can return from the 
function enclosing the function checking the error.
Please see the playground that does exactly that:
https://go.dev/play/p/GvXFU1LbVvs

However, I recommend you to use `err2` with all of its power, i.e., 
automation. Could you look at the following playground? Even the error 
strings/messages are autogenerated from function names (yeah, localization, 
but in most cases, enough to start with). Declarative error handling helps 
to keep your code safe.
https://go.dev/play/p/6Ky5nMtqu4F

And yes, I'm the author of the err2.
On Tuesday, February 7, 2023 at 11:38:41 PM UTC+2 Rich wrote:

> In most of my code I create a function to handle errors. looks something 
> like this:
>
> func errorHandle(err error, str string, ex bool) {
>  if err != nil {
>   fmt.Printf("error: %s -- %v\n",str, err)
>  }
>  if ex {
> os.Exit(1)
>  }
> }
>
> This cleans up my code:
> inFile, err := os.ReadFile("Mydata.txt")
> errorHandle(err,"read mydata.txt",true) // The true will exit
>
> So you see that I can exit the program when there is an error, what I want 
> to know is if it's possible to do the same thing inside a function, to 
> where I don't exit the program but return from the function:
>
> func OpenFile( filename string) []byte {
> inFile,err := os.ReadFile(filename)
> errReturn(err, "read "+filname,true)
>
> When there is an error it would return from the OpenFile function,
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/7292381a-655f-4ded-b193-19d85e64b2d2n%40googlegroups.com.


[go-nuts] Re: Error Handling Question

2022-10-24 Thread Harri L
Hi,

On Friday, October 21, 2022 at 12:14:52 AM UTC+3 dple...@google.com wrote:

>
> var x0 float
> try {
>x0 = check DoSomeMath(check FetchSomething(), check ComputeSomething())
> } handle err {
>log.Info("Unable to estimate initial approximation, defaulting to 1...")
>x0 = 1
> }
> // code continues and does things with x
>
 
I wanted to show what the previous block looks like with the help of the 
current Go and some help from the err2 -package 
(I'm the author). The Go playground .

 calcSomething := func() (x0 int) {
defer err2.Catch(func(err error) {
log.Printf("Unable to estimate initial approximation: %v, 
defaulting to 1...", err)
x0 = 1
})
return try.To1(DoSomeMath(try.To1(FetchSomething()), 
try.To1(ComputeSomething(
}
x0 := calcSomething()

Of course, that's not exactly what you are proposing:

This makes it easy to see what error handling will happen at any point 
> within the function, keeps the control flow linear (so that, unlike 
> defer()-based recovery, you don't have to skip ahead in the function to get 
> context before the handler makes sense - the context comes first, followed 
> by the handling code), and allows code to recover from errors without 
> aborting an entire function.
>
 
I also wanted to say that the `defer` -based error handling isn't so bad 
when you are used to the defer keyword already in the Go. 

Best Regards,
-Harri

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/1d1e051d-4485-4fe0-a9c8-16afdc5d80e6n%40googlegroups.com.


[go-nuts] Re: Generic error handling with panic, recover, and defer

2022-08-06 Thread Harri L
Thanks for mentioning https://github.com/lainio/err2. I'm the author of the 
package. Maybe a few words about it would be ok.

We could say that the err2 package is one of the most important libraries 
in our corporation's use. It's over three years old by now, and we have 
used it both for internal and open source projects: small and large, and, 
of course, in production as well. So, we take it quite seriously.

The idea and need for the package came from the famous: "more error 
handling with less checking." You can read my blog post about some of the 
reasoning 
. 
Please note that the post is written before Go generics. We used Go's code 
generation to solve high-performance needs with ease of use. Since we had 
so many big projects using err2 before Go 1.18 and generics, we offered a 
migration tool to port those repos to use the new Go generics-based err2 
API if they wanted. Now the API relay on Go generics, and we drop the type 
variables.

I always nice to hear that others are working on the same problem area. I'm 
sure we can help each other!

-Harri

On Saturday, July 30, 2022 at 1:02:16 AM UTC+3 Nathaniel Lehrer wrote:

> This is similar, maybe this one is better to use? 
> https://github.com/lainio/err2
>
> On Tuesday, September 21, 2021 at 1:57:38 PM UTC-7 mces...@gmail.com 
> wrote:
>
>> With go 1.18 generics implementation it is now possible to provide error 
>> handling functions in a fashion similar to the "try" proposal. I wrote a 
>> small library that implements this approach: 
>> https://github.com/mcesar/must.
>>
>> An example of usage is as follows:
>>
>> package main
>> import (
>> "fmt"
>> "os"
>> "github.com/mcesar/must"
>> )
>> func main() {
>> fmt.Println(f())
>> }
>> func f() (err error) {
>> defer must.Handle(&err)
>> f := must.Do(os.Open("file"))
>> defer f.Close()
>> // ...
>> return nil
>> }
>>
>> This idea is not new, but I think it is worthwhile to have an 
>> implementation to experiment with.
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/c41717e7-03b3-48e8-b836-fb55ade4c924n%40googlegroups.com.


[go-nuts] Re: “Normal” vs. “error” (control flow) is a fundamental semantic distinction

2022-05-30 Thread Harri L
Thank you!

Indeed, the selected names follow the try/catch idiom, and with the err2 
, you can write code that includes 
non-local control flows. I hope that err2 is not confused with exception 
handling.

The Go2 try-proposal 

 
speaks about a helper library needed to get every help that try-macro could 
offer. The err2 package has that library now, and thanks to generics, the 
try-API is almost similar to try-macro.

I know many didn't like the try-proposal, but what has been a considerable 
surprise is how much benefit you get when merging panics and errors.

Rus Coxx: Error Handling -- Problem Overview 

:
"*Panics. We’ve spent a while trying to harmonize error handling and 
panics, so that cleanup due to error handling need not be repeated for 
cleanup due to panics. All our attempts at unifying the two only led to 
more complexity*." 

Then harmonization is now done with err2-package.

On Wednesday, May 25, 2022 at 2:15:18 PM UTC+3 yan.z...@gmail.com wrote:

> Try & Catch sounds great!
>
> 在2022年5月19日星期四 UTC+8 00:15:09 写道:
>
>> Hi all,
>>
>> I thought now was the time to go public. The automatic error propagation 
>> is possible with the help of a simple Go package, and it has been about 
>> three years now:
>>
>> func CopyFile(src, dst string) (err error) {
>> defer err2.Returnf(&err, "copy %s %s", src, dst)
>>
>> r := try.To1(os.Open(src))
>> defer r.Close()
>>
>> w := try.To1(os.Create(dst))
>> defer err2.Handle(&err, func() {
>> _ = os.Remove(dst)
>> })
>> defer w.Close()
>>
>> try.To1(io.Copy(w, r))
>> return nil
>> }
>>
>> The playground .
>>
>> A couple of blog posts about the subject:
>>
>>- Error Propagation 
>>
>> 
>>- Errors as Discriminated Unions 
>>
>>
>> I'm the author of those posts and the err2 package 
>> . Additional sources for original ideas 
>> are mentioned in the blogs and the package documentation. And, of course, 
>> pure error values are needed when transporting errors through channels.
>>
>> I hope that any gopher who tries the err2 package finds it as valuable 
>> and productive
>> as we have. Indeed, Go is one of the most pragmatic and refactor-friendly 
>> native languages.
>>
>> Best regards,
>> -Harri
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/397750bd-9028-4165-9cbd-3a8406e42c94n%40googlegroups.com.


Re: [go-nuts] uber handler to collect stacktrace when program crashing

2022-05-30 Thread Harri L
If you write a wrapper, please look at the err2-package 
. It's an error-handling package, but we 
needed to build a panic-safe system with automatic stack tracing. Traces 
are context optimized as well. Here's a playground demo 
.

You add the following one-liners to your goroutines, and that's it.

go func() {
 *defer err2.CatchTrace(func(err error) {})*
 var b []byte
 b[1] = 0
}()

On Monday, May 30, 2022 at 6:11:47 PM UTC+3 sre.ag...@gmail.com wrote:

> Yes, I was asking about a generic handler.  
>
> I am thinking of writing a wrapper function which takes a function and 
> spuns up a goroutine with the above mentioned defer function by default.  
>
> On Sat, May 28, 2022 at 1:27 AM 'Sean Liao' via golang-nuts <
> golan...@googlegroups.com> wrote:
>
>> I believe this is asking for a single handler that will apply to all 
>> goroutines, to which the answer is no such feature exists
>>
>> - sean
>>
>> On Sat, May 28, 2022, 03:09 Ian Lance Taylor  wrote:
>>
>>> On Fri, May 27, 2022 at 10:42 AM Aggarwal Sre  
>>> wrote:
>>> >
>>> > Is there a recommended pattern besides adding a defer call ( with 
>>> recover call, to collect debug stack trace) to each goroutine, for 
>>> collecting a stack trace when a golang is crashing due to any sort of panic.
>>> >
>>> > In other words, is there a way to register an uber handler ( probably 
>>> using OS signals) at the main function level, to indicate that a golang 
>>> program crashed and stacktrace to clearly specify where exactly?
>>>
>>> A panic handle is run at the bottom of the stack.  If you write this:
>>>
>>> defer func() {
>>> if recover() != nil {
>>> fmt.Printf("%s", debug.Stack())
>>> }
>>> }()
>>>
>>> in your main function, it will print a stack trace showing the point
>>> of the panic.
>>>
>>> Ian
>>>
>>> -- 
>>> You received this message because you are subscribed to the Google 
>>> Groups "golang-nuts" group.
>>> To unsubscribe from this group and stop receiving emails from it, send 
>>> an email to golang-nuts...@googlegroups.com.
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/golang-nuts/CAOyqgcV4d9HxDbdp_in95j6aKFF_m%2BN_hFdeyUMuMOWRt5%2B6dw%40mail.gmail.com
>>> .
>>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to golang-nuts...@googlegroups.com.
>>
> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/golang-nuts/CAGabyPoRyv63ztmyrAGkuQ4u8Dcqffo4dUVo6H%3DczLU7%3DvsVcw%40mail.gmail.com
>>  
>> 
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/d7987acf-099b-4048-b38a-dcd01db0da47n%40googlegroups.com.


[go-nuts] “Normal” vs. “error” (control flow) is a fundamental semantic distinction

2022-05-18 Thread Harri L
Hi all,

I thought now was the time to go public. The automatic error propagation is 
possible with the help of a simple Go package, and it has been about three 
years now:

func CopyFile(src, dst string) (err error) {
defer err2.Returnf(&err, "copy %s %s", src, dst)

r := try.To1(os.Open(src))
defer r.Close()

w := try.To1(os.Create(dst))
defer err2.Handle(&err, func() {
_ = os.Remove(dst)
})
defer w.Close()

try.To1(io.Copy(w, r))
return nil
}

The playground .

A couple of blog posts about the subject:

   - Error Propagation 
   

   - Errors as Discriminated Unions 
   
   
I'm the author of those posts and the err2 package 
. Additional sources for original ideas are 
mentioned in the blogs and the package documentation. And, of course, pure 
error values are needed when transporting errors through channels.

I hope that any gopher who tries the err2 package finds it as valuable and 
productive
as we have. Indeed, Go is one of the most pragmatic and refactor-friendly 
native languages.

Best regards,
-Harri

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/d66ef525-9e3f-41b6-8cdd-f8b8caf6bd31n%40googlegroups.com.