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

2023-07-09 Thread Shulhan
Hi Mike,

On Thu, 29 Jun 2023 22:04:01 -0700 (PDT)
Mike Schinkel  wrote:

> There are many aspects of this proposal that I really like, and a few
> that I think need to be reconsidered.
> 
> In general I like that it:
> 
>1. Does not try to handle errors *above *where the errors
> occurred, which is the pattern when using both *defer* and
> *recover(). *I personally find having to jump back much harder to
> reason about than jumping forward to find the error handler.
>2. Does not require handling the error in a closure or other
> *func* as the former adds a lot of visual noise and the latter
> complicates by creating a different variable scope. 
> 
> 
> It is in many ways similar to a proposal I have been planning on
> preparing but have no found the right opportunity. Possibly this is
> the right opportunity and maybe taking aspects of this and aspects of
> mine we could find a solution beneficial enough that Ian Lance Taylor
> would consider it a big enough improvement. I'll try to follow up on
> that soon.
> 
> As for the specifics of this proposal:
> 
> 1. I think *when err handle * is a bit too much magic.  I
> think it would be more Go-like if it were instead:
> 
>*when err!=nil handle *
> 
> I know this makes for more repeated syntax, but within the scope of
> this proposal I do not think you can avoid it without it adding
> magic.  I do think that could be addressed, and what I have in mind
> addresses that. But I wanted to first comment on your proposal, not
> introduce mine.

If we use WHEN like this, then there is no different with IF
statement.
The purpose of WHEN statement is to check for non-zero value.
Using IF statement, it could be written like these

  if !ZeroValue(err) handle 

> 
> 2. As for *check* as you have proposed it — handling zero return
> values — it seems to add more magic, and that it would only work in
> selected use-cases so it might be best to omit this from the proposal?

I am not sure on this one. The "check" keywords is proposed by parent
proposal [1], not by this proposal.

[1]
https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md

> 
> 3. I do like the concept of labels that do not fall through to the
> code in the next label.  However, it is not exactly clear how they
> should work.  Do your handlers always have to have a *return*
> themselves?
> 
>
> *func foo()error {*
> * ...*
> * when err != nil handle cleanup*
> * ...*
> * return nil*
> 
>:*cleanup:*
>  *doCleanup()*
> * return err*
>*}*

No. The body of handler is similar with body of function.
If the function does not expect return value than the execution of
function body will stop before the first handler defined.

Case example,

func main() {
hex, err := ioutil.ReadAll(os.Stdin)
when err handle fatal

data, err := parseHexdump(string(hex))
when err handle fatal

os.Stdout.Write(data)
// The function body stop here, the log.Fatal below will not be
// executed.
:fatal:
log.Fatal(err)
}


> 
> 4. When you are in a handler, is there any way to correct the problem
> and *resume* or *retry* the code where you left off without resorting
> to using *goto* and labels?

No, but one can use by using recursive call.
IMO, the part of code that try handling error by resuming or retry
is an indication that it should be moved into separate function.

> 
> 5. I do not think you need the new keyword *handle*, i.e. I think
> this would be sufficient to use *goto* instead since the syntax of
> your handler label with the preceding colon should be sufficient to
> distinguish between the two:
> 
>
> *when err!=nil goto *

That is possible, yes, I think it will minimise number of new syntax
introduced by this proposal.
I believe the implementation in the Go internal would be rather complex.

> 6. If you use *goto* instead of *handle* then you actually have two 
> orthogonal features, the latter one being labels that do not fall
> through that can be used without when. Those could be proposed as a
> feature in their own right.
> 
> 7. How would your proposal handle shared cleanup?  As we can see from
> the following example I have to call *db.Rollback()* for every error
> case, and I would really rather only have to call it in one place in
> the case.  Does your proposal have a solution for this that I missed?
> 
>
> *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", 

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

2023-07-03 Thread Mike Schinkel
Hi Henry,

For clarity, my comments were not intended to call out any lack of 
motivation — which you keyed on — but instead focus on the fact no silver 
bullet is likely to exist that addresses error handling without new 
language features, and that many Go developers want error handling 
addressed. 

In hindsight I would remove the mention of motivation if I could so as not 
to be misinterpreted. #justfyi  #fwiw

-Mike

On Monday, July 3, 2023 at 2:03:00 AM UTC-4 Henry wrote:

> I don't think it has anything to do with motivation, Mike. The problem I 
> see is that there is no good enough solution that offers a substantial 
> benefit over the current approach. Many error handling proposals involve 
> rearranging the code with a few line savings, and sometimes at the cost of 
> readability. Note that there is no perfect solution to error handling to 
> date. Even the conventional try-catch-finally has its own problems. I 
> appreciate the Go Team's restraint in this matter.
>
> On Monday, July 3, 2023 at 9:42:02 AM UTC+7 Mike Schinkel wrote:
>
>> On Wednesday, June 28, 2023 at 1:30:41 PM UTC-4 Sven Anderson wrote:
>>
>> I think for what you want to do you don't need any language extension. 
>>
>>
>> On Sunday, July 2, 2023 at 2:04:29 PM UTC-4 Harri L wrote:
>>
>> *The sample block below is what we can have without any language updates.*
>>
>>
>> Many times when people ask for new language features it is possible to 
>> simulate what is being requested via some combination of convention and/or 
>> reusable package(s).
>>
>> But sadly, at least in my experience, most teams are only motivated to 
>> continue the approach they chose initially and not interested in changing 
>> to a new non-standard approach, and this is the case for almost anything 
>> proposed as *"something we can do today"* unless it has already 
>> established itself as a defacto-standard way to approach the problem.
>>
>> Although some conventions and some packages come close to achieving 
>> defacto-standard status — Cobra for CLI is the closest one I can think of 
>> for Go even though it is far from defacto — the use of most conventions 
>> and/or packages required a motivated team or at least a motivated 
>> individual. 
>>
>> The simple fact is even if the core Go team adds a new feature for error 
>> handling, many will still not embrace it, at least not for a while.  But if 
>> there is any chance a motivated individual has to get an unmotivated team 
>> to adopt a new approach, it almost has to be an approach advocated for by 
>> the core Go team, and with new features that make that approach possible.
>>
>> So while it may be great for motivated individuals and the rarer 
>> motivated teams to hear about how we can do things today without the new 
>> language features we are requesting — and the developer of the package that 
>> enables it is certainly motivated — there is little chance a *"can do 
>> today"* approach will address the reason people ask for a new language 
>> feature.  And especially for error handling improvements, which is near the 
>> top of the things people want to see improved in Go, per the Q1 2023 Go 
>> Developer Survey[1]. 
>>
>> #fwiw
>>
>> -Mike
>>
>>  [1] Go Developer Survey 2023 Q1 Results - The Go Programming Language 
>> (golang.org) 
>>
>

-- 
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/9cfdf812-f9fa-4baa-9402-0e60bc03ef00n%40googlegroups.com.


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

2023-07-03 Thread Henry
I don't think it has anything to do with motivation, Mike. The problem I 
see is that there is no good enough solution that offers a substantial 
benefit over the current approach. Many error handling proposals involve 
rearranging the code with a few line savings, and sometimes at the cost of 
readability. Note that there is no perfect solution to error handling to 
date. Even the conventional try-catch-finally has its own problems. I 
appreciate the Go Team's restraint in this matter.

On Monday, July 3, 2023 at 9:42:02 AM UTC+7 Mike Schinkel wrote:

> On Wednesday, June 28, 2023 at 1:30:41 PM UTC-4 Sven Anderson wrote:
>
> I think for what you want to do you don't need any language extension. 
>
>
> On Sunday, July 2, 2023 at 2:04:29 PM UTC-4 Harri L wrote:
>
> *The sample block below is what we can have without any language updates.*
>
>
> Many times when people ask for new language features it is possible to 
> simulate what is being requested via some combination of convention and/or 
> reusable package(s).
>
> But sadly, at least in my experience, most teams are only motivated to 
> continue the approach they chose initially and not interested in changing 
> to a new non-standard approach, and this is the case for almost anything 
> proposed as *"something we can do today"* unless it has already 
> established itself as a defacto-standard way to approach the problem.
>
> Although some conventions and some packages come close to achieving 
> defacto-standard status — Cobra for CLI is the closest one I can think of 
> for Go even though it is far from defacto — the use of most conventions 
> and/or packages required a motivated team or at least a motivated 
> individual. 
>
> The simple fact is even if the core Go team adds a new feature for error 
> handling, many will still not embrace it, at least not for a while.  But if 
> there is any chance a motivated individual has to get an unmotivated team 
> to adopt a new approach, it almost has to be an approach advocated for by 
> the core Go team, and with new features that make that approach possible.
>
> So while it may be great for motivated individuals and the rarer motivated 
> teams to hear about how we can do things today without the new language 
> features we are requesting — and the developer of the package that enables 
> it is certainly motivated — there is little chance a *"can do today"* 
> approach 
> will address the reason people ask for a new language feature.  And 
> especially for error handling improvements, which is near the top of the 
> things people want to see improved in Go, per the Q1 2023 Go Developer 
> Survey[1]. 
>
> #fwiw
>
> -Mike
>
>  [1] Go Developer Survey 2023 Q1 Results - The Go Programming Language 
> (golang.org) 
>

-- 
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/3f93f16f-6d43-492d-8961-400be98ef707n%40googlegroups.com.


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

2023-07-02 Thread Mike Schinkel
On Wednesday, June 28, 2023 at 1:30:41 PM UTC-4 Sven Anderson wrote:

I think for what you want to do you don't need any language extension. 


On Sunday, July 2, 2023 at 2:04:29 PM UTC-4 Harri L wrote:

*The sample block below is what we can have without any language updates.*


Many times when people ask for new language features it is possible to 
simulate what is being requested via some combination of convention and/or 
reusable package(s).

But sadly, at least in my experience, most teams are only motivated to 
continue the approach they chose initially and not interested in changing 
to a new non-standard approach, and this is the case for almost anything 
proposed as *"something we can do today"* unless it has already established 
itself as a defacto-standard way to approach the problem.

Although some conventions and some packages come close to achieving 
defacto-standard status — Cobra for CLI is the closest one I can think of 
for Go even though it is far from defacto — the use of most conventions 
and/or packages required a motivated team or at least a motivated 
individual. 

The simple fact is even if the core Go team adds a new feature for error 
handling, many will still not embrace it, at least not for a while.  But if 
there is any chance a motivated individual has to get an unmotivated team 
to adopt a new approach, it almost has to be an approach advocated for by 
the core Go team, and with new features that make that approach possible.

So while it may be great for motivated individuals and the rarer motivated 
teams to hear about how we can do things today without the new language 
features we are requesting — and the developer of the package that enables 
it is certainly motivated — there is little chance a *"can do today"* approach 
will address the reason people ask for a new language feature.  And 
especially for error handling improvements, which is near the top of the 
things people want to see improved in Go, per the Q1 2023 Go Developer 
Survey[1]. 

#fwiw

-Mike

 [1] Go Developer Survey 2023 Q1 Results - The Go Programming Language 
(golang.org) 

-- 
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/8dad58af-3c67-4db8-9495-094b6fcbfb70n%40googlegroups.com.


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

2023-07-02 Thread 'Dan Kortschak' via golang-nuts
On Sun, 2023-07-02 at 10:41 -0700, Jeremy French wrote:
> Scrolling in code is bad - a necessary evil, obviously, but evil
> nonetheless.  Vertical scrolling is bad because it causes what we
> were looking at to move and our eyes have to track and/or reacquire
> what we were looking at.  It's obviously possible, but on the micro-
> scale it's expensive when you have to do it 1000 times per day of
> coding.  Horizontal scrolling is even worse because not only is it
> harder to track visually, but we don't have nearly the same ease of
> use on our mouse to horizontally scroll as we do to vertically
> scroll.   Just reacquiring where you were in the code takes up a
> miniscule amount of time and brain power that could be used for
> better purposes.  Again, it doesn't seem like much, and you may
> dismiss me as being melodramatic, but this discussion is a recurring
> one for a reason.  It's enough of a problem to bug people and want it
> to be different. 
> 
> So to speak to Dan's point, trading vertical scrolling for horizontal
> scrolling would be a move in the wrong direction.  But if you can
> reduce three lines to one WITHOUT causing horizontal scrolling, that
> benefits everyone, or at least everyone who uses a scroll wheel.

Scrolling is part of it, eye tracking is a less-obvious but more
significant issue; there is a reason newspaper columns are narrow — it
eases reading. Another part is burying semantics in a line, for
example, I find the common practice of `if err := f(); err != nil {...`
to be significantly less readable than the equivalent where the f call
is outside the if, and reject code in review with this unless it's
needed for scoping reasons. I sort of wish that this feature did not
exist, though — even though the exact same semantics are possible in
the language without it with the use of block scopes — I can see why it
exists.

In general I agree, with what you're saying though as a problem
statement. The problem is tuning the gofmt heuristics (if a single-line
if handling were adopted). This has been discussed in numerous issues
and rejected (for a variety of reasons), so it's unlikely to be
changed.

-- 
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/ecc70f6c0d3facd0f74763f95711ebb25c789e5f.camel%40kortschak.io.


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()

tx := try.To1(db.BeginTransaction())
defer err2.Handle(, 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(, 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.


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

2023-07-02 Thread Jeremy French
Scrolling in code is bad - a necessary evil, obviously, but evil 
nonetheless.  Vertical scrolling is bad because it causes what we were 
looking at to move and our eyes have to track and/or reacquire what we were 
looking at.  It's obviously possible, but on the micro-scale it's expensive 
when you have to do it 1000 times per day of coding.  Horizontal scrolling 
is even worse because not only is it harder to track visually, but we don't 
have nearly the same ease of use on our mouse to horizontally scroll as we 
do to vertically scroll.   Just reacquiring where you were in the code 
takes up a miniscule amount of time and brain power that could be used for 
better purposes.  Again, it doesn't seem like much, and you may dismiss me 
as being melodramatic, but this discussion is a recurring one for a 
reason.  It's enough of a problem to bug people and want it to be 
different. 

So to speak to Dan's point, trading vertical scrolling for horizontal 
scrolling would be a move in the wrong direction.  But if you can reduce 
three lines to one WITHOUT causing horizontal scrolling, that benefits 
everyone, or at least everyone who uses a scroll wheel.

On Sunday, July 2, 2023 at 1:55:31 AM UTC-4 Dan Kortschak wrote:

> On Sat, 2023-07-01 at 22:34 -0700, Mike Schinkel wrote:
> > > What is the difference to if err != nil { goto  } ?
> > 
> > Thanks you for asking.
> > 
> > If you run go fmt  on a file that contains the formatting you ask
> > about the line will be expanded to the 3 lines, which brings us back
> > to status quo:
> > 
> >if err != nil {
> >  goto 
> >}
> > 
>
> Why is there a bias towards favouring horizontal code over vertical
> code?
>
> In my experience, it's much easier to read and digest vertical code
> compared to horizontal; Java (horribly horizontal in general) cf Go
> (generally quite vertical).
>
>
>

-- 
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/a6c91a61-e021-4888-8837-e9105b89537fn%40googlegroups.com.


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

2023-07-01 Thread 'Dan Kortschak' via golang-nuts
On Sat, 2023-07-01 at 22:34 -0700, Mike Schinkel wrote:
> > What is the difference to if err != nil { goto  } ?
> 
> Thanks you for asking.
> 
> If you run go fmt  on a file that contains the formatting you ask
> about the line will be expanded to the 3 lines, which brings us back
> to status quo:
> 
>    if err != nil {
>  goto 
>    }
> 

Why is there a bias towards favouring horizontal code over vertical
code?

In my experience, it's much easier to read and digest vertical code
compared to horizontal; Java (horribly horizontal in general) cf Go
(generally quite vertical).


-- 
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/5ea3976b6a1d665da1a0ee67a6ef2341568dbc08.camel%40kortschak.io.


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

2023-07-01 Thread Mike Schinkel
Hi Sven,

> *What is the difference to if err != nil { goto  } ?*

Thanks you for asking.

If you run *go fmt*  on a file that contains the formatting you ask about 
the line will be expanded to the 3 lines, which brings us back to status 
quo:

*if *

*err != nil { goto  } *Of course *go fmt* could be modified, but 
allowing that formatting strikes me as even more *non*-Go idiomatic than 
added a *when* command.
That said, I am not personally advocating for a *when* command, I was just 
comparing *when err != nil goto * with the OP and proposer's *when 
err handle *. #fwiw -Mike P.S. I think there is a approach similar to 
that proposed that simplify error handling even more as it would not 
require any code where this proposal requires *when* — a proposal that 
could also kill another bird with the one stone — but as the tendency of 
online programming communities is to shoot down proposals that present new 
ideas before their benefits can be fully understood I have been trying to 
find a way to introduce the idea without it falling victim to that fate. 


On Saturday, July 1, 2023 at 8:42:14 AM UTC-4 Sven Anderson wrote:


Mike Schinkel <...> schrieb am Fr. 30. Juni 2023 um 07:04:

*when err!=nil goto  *


What is the difference to `if err != nil { goto  }` ?

Go is awesome, because it does _not_ more and more syntax, especially with 
subtle nuances that one has to remember.

-- 
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/daa56174-b570-4d73-91b8-f6bfa5ec1693n%40googlegroups.com.


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

2023-07-01 Thread Sven Anderson
Mike Schinkel  schrieb am Fr. 30. Juni 2023 um 07:04:

*when err!=nil goto  *


What is the difference to `if err != nil { goto  }` ?

Go is awesome, because it does _not_ more and more syntax, especially with
subtle nuances that one has to remember.

>

-- 
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/CAFwXxZRRvrUbD%3DnR65RJMqK_qsZeyb4eW8fXnVba6%2Br2%2BZeOvw%40mail.gmail.com.


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

2023-06-29 Thread Mike Schinkel
There are many aspects of this proposal that I really like, and a few that 
I think need to be reconsidered.

In general I like that it:

   1. Does not try to handle errors *above *where the errors occurred, 
   which is the pattern when using both *defer* and *recover(). *I 
   personally find having to jump back much harder to reason about than 
   jumping forward to find the error handler.
   2. Does not require handling the error in a closure or other *func* as 
   the former adds a lot of visual noise and the latter complicates by 
   creating a different variable scope. 


It is in many ways similar to a proposal I have been planning on preparing 
but have no found the right opportunity. Possibly this is the right 
opportunity and maybe taking aspects of this and aspects of mine we could 
find a solution beneficial enough that Ian Lance Taylor would consider it a 
big enough improvement. I'll try to follow up on that soon.

As for the specifics of this proposal:

1. I think *when err handle * is a bit too much magic.  I think it 
would be more Go-like if it were instead:

   *when err!=nil handle *

I know this makes for more repeated syntax, but within the scope of this 
proposal I do not think you can avoid it without it adding magic.  I do 
think that could be addressed, and what I have in mind addresses that. But 
I wanted to first comment on your proposal, not introduce mine.

2. As for *check* as you have proposed it — handling zero return values — 
it seems to add more magic, and that it would only work in selected 
use-cases so it might be best to omit this from the proposal?

3. I do like the concept of labels that do not fall through to the code in 
the next label.  However, it is not exactly clear how they should work.  Do 
your handlers always have to have a *return* themselves?

   
*func foo()error {*
* ...*
* when err != nil handle cleanup*
* ...*
* return nil*

   :*cleanup:*
 *doCleanup()*
* return err*
   *}*

4. When you are in a handler, is there any way to correct the problem and 
*resume* or *retry* the code where you left off without resorting to using 
*goto* and labels?

5. I do not think you need the new keyword *handle*, i.e. I think this 
would be sufficient to use *goto* instead since the syntax of your handler 
label with the preceding colon should be sufficient to distinguish between 
the two:

   
*when err!=nil goto *
6. If you use *goto* instead of *handle* then you actually have two 
orthogonal features, the latter one being labels that do not fall through 
that can be used without when. Those could be proposed as a feature in 
their own right.

7. How would your proposal handle shared cleanup?  As we can see from the 
following example I have to call *db.Rollback()* for every error case, and 
I would really rather only have to call it in one place in the case.  Does 
your proposal have a solution for this that I missed?

   
*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/5e180c59-9761-40e7-8fdf-10fb5fc1492en%40googlegroups.com.


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

2023-06-28 Thread Jan
Thanks for the pointer Sven!

I think I was once told not to use panic/defer/recover to implement generic 
exceptions in Go, and never reconsidered it. I think I'm taking up on your 
suggestion for my library.


On Wednesday, June 28, 2023 at 7:30:41 PM UTC+2 Sven Anderson wrote:

> I think for what you want to do you don't need any language extension. You 
> can implement all that within the current language. Look at this example: 
> https://go.dev/play/p/aqjwzknrArH
>
> If you want to catch errors also in nested functions, you can also skip 
> the ErrorChecker type and do it like this: 
> https://go.dev/play/p/3Fk-82zxtUJ
>
> If you don't like the named return parameter, you can use a wrapper 
> function:
> https://go.dev/play/p/C54vQThPUnq
>
> I thought about putting something like that in a package on github. But it 
> is such a small code, that I think copy and paste is just fine. :-)
>
> Cheers
>
>
> On Sun, Jun 4, 2023 at 6:17 PM Shulhan  wrote:
>
>> Dear gophers,
>>
>> I have been reading several proposals about error handling couple of
>> months ago and today a light bulb come upon me, and then I write as much
>> as I can think.  I am not sure if its good or bad idea or even possible
>> to implement.
>>
>> In this post, I will try as concise as possible.
>> The full and up to date proposal is available at
>> https://kilabit.info/journal/2023/go2_error_handling/ .
>>
>> Any feedback are welcome so I can see if this can move forward.
>> Thanks in advance.
>>
>> ==  Background
>>
>> This proposal is based on "go2draft Error Handling".
>>
>> My critics to "go2draft Error Handling" is the missing correlation
>> between handle and check.
>> If we see one of the first code in the design,
>>
>> 
>> ...
>> handle err {
>> return fmt.Errorf("copy %s %s: %v", src, dst, err)
>> }
>>
>> r := check os.Open(src)
>> ...
>> 
>>
>> There is no explicit link between check keyword and how it will trigger
>> handle err later.
>> It is also break the contract between the signature of os.Open, that
>> return an error in the second parameter, and the code that call it.
>>
>> This proposal try to make the link between them clear and keep the code
>> flow explicit and readable.
>>
>> The goals is not to reduce number of lines but to minimize repetitive
>> error handling.
>>
>>
>> == Proposal
>>
>> This proposal introduces two new keywords and one new syntax for
>> statement.
>>
>> The two new keywords are “WHEN” and “HANDLE”.
>>
>> 
>> When = "when" NonZeroValueStmt HandleCallStmt .
>> NonZeroValueStmt = ExpressionStmt
>>  ; I am not quite sure how to express non-zero value
>>  ; expression here, so I will describe it below.
>>
>> HandleCallStmt   = "handle" ( HandleName | "{" SimpleStmt "}" ) .
>> HandleName   = identifier .
>> 
>>
>> The HandleCallStmt will be executed if only if the statement in
>> NonZeroValueStmt returned non-zero value of its type.
>> For example, given the following variable declarations,
>>
>> 
>> var (
>> err   = errors.New(`error`)
>> slice = make([]byte, 1)
>> no1   = 1
>>
>> no2 int
>> ok  bool
>> )
>> 
>>
>> The result of when evaluation are below,
>>
>> 
>> when err // true, non-zero value of type error.
>> when len(slice) == 0 // true, non-zero value of type bool.
>> when no1 // true, non-zero value of type int.
>> when no2 // false, zero value of int.
>> when ok  // false, zero value of bool.
>> 
>>
>> The HandleCallStmt can jump to handle by passing handle name or provide
>> simple statement directly.
>> If its simple statement, there should be no variable shadowing happen
>> inside them.
>>
>> Example of calling handle by name,
>>
>> 
>> ...
>> when err handle myErrorHandle
>>
>> :myErrorHandle:
>> return err
>> 
>>
>> Example of calling handle using simple statement,
>>
>> 
>> ...
>> when err handle { return err }
>> 
>>
>> The new syntax for statement is to declare label for handle and its body,
>>
>> 
>> HandleStmt  = ":" HandleName ":" [SimpleStmt] [ReturnStmt | 
>> HandleCallStmt] .
>> 
>>
>> Each of `HandleStmt` MUST be declared at the bottom of function block.
>> An `HandleStmt` can call other `HandleStmt` as long as the handle is 
>> above the
>> current handle and it is not itself.
>> Any statements below `HandleCallStmt` MUST not be executed.
>>
>> Unlike goto, each `HandleStmt` is independent on each other, one 
>> `HandleStmt`
>> end on itself, either by calling `return` or `handle`, or by other
>> `HandleStmt` and does not fallthrough below it.
>>
>> Given the list of handle below,
>>
>> 
>> :handle1:
>> S0
>> S1
>> :handle2:
>> handle handle1
>> S3
>> 
>>
>> A `handle1` cannot call `handle2` because its below it.
>> A `handle2` cannot call `handle2`, because its the same handle.
>> A 

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

2023-06-28 Thread Sven Anderson
I think for what you want to do you don't need any language extension. You
can implement all that within the current language. Look at this example:
https://go.dev/play/p/aqjwzknrArH

If you want to catch errors also in nested functions, you can also skip the
ErrorChecker type and do it like this:
https://go.dev/play/p/3Fk-82zxtUJ

If you don't like the named return parameter, you can use a wrapper
function:
https://go.dev/play/p/C54vQThPUnq

I thought about putting something like that in a package on github. But it
is such a small code, that I think copy and paste is just fine. :-)

Cheers


On Sun, Jun 4, 2023 at 6:17 PM Shulhan  wrote:

> Dear gophers,
>
> I have been reading several proposals about error handling couple of
> months ago and today a light bulb come upon me, and then I write as much
> as I can think.  I am not sure if its good or bad idea or even possible
> to implement.
>
> In this post, I will try as concise as possible.
> The full and up to date proposal is available at
> https://kilabit.info/journal/2023/go2_error_handling/ .
>
> Any feedback are welcome so I can see if this can move forward.
> Thanks in advance.
>
> ==  Background
>
> This proposal is based on "go2draft Error Handling".
>
> My critics to "go2draft Error Handling" is the missing correlation
> between handle and check.
> If we see one of the first code in the design,
>
> 
> ...
> handle err {
> return fmt.Errorf("copy %s %s: %v", src, dst, err)
> }
>
> r := check os.Open(src)
> ...
> 
>
> There is no explicit link between check keyword and how it will trigger
> handle err later.
> It is also break the contract between the signature of os.Open, that
> return an error in the second parameter, and the code that call it.
>
> This proposal try to make the link between them clear and keep the code
> flow explicit and readable.
>
> The goals is not to reduce number of lines but to minimize repetitive
> error handling.
>
>
> == Proposal
>
> This proposal introduces two new keywords and one new syntax for
> statement.
>
> The two new keywords are “WHEN” and “HANDLE”.
>
> 
> When = "when" NonZeroValueStmt HandleCallStmt .
> NonZeroValueStmt = ExpressionStmt
>  ; I am not quite sure how to express non-zero value
>  ; expression here, so I will describe it below.
>
> HandleCallStmt   = "handle" ( HandleName | "{" SimpleStmt "}" ) .
> HandleName   = identifier .
> 
>
> The HandleCallStmt will be executed if only if the statement in
> NonZeroValueStmt returned non-zero value of its type.
> For example, given the following variable declarations,
>
> 
> var (
> err   = errors.New(`error`)
> slice = make([]byte, 1)
> no1   = 1
>
> no2 int
> ok  bool
> )
> 
>
> The result of when evaluation are below,
>
> 
> when err // true, non-zero value of type error.
> when len(slice) == 0 // true, non-zero value of type bool.
> when no1 // true, non-zero value of type int.
> when no2 // false, zero value of int.
> when ok  // false, zero value of bool.
> 
>
> The HandleCallStmt can jump to handle by passing handle name or provide
> simple statement directly.
> If its simple statement, there should be no variable shadowing happen
> inside them.
>
> Example of calling handle by name,
>
> 
> ...
> when err handle myErrorHandle
>
> :myErrorHandle:
> return err
> 
>
> Example of calling handle using simple statement,
>
> 
> ...
> when err handle { return err }
> 
>
> The new syntax for statement is to declare label for handle and its body,
>
> 
> HandleStmt  = ":" HandleName ":" [SimpleStmt] [ReturnStmt |
> HandleCallStmt] .
> 
>
> Each of `HandleStmt` MUST be declared at the bottom of function block.
> An `HandleStmt` can call other `HandleStmt` as long as the handle is above
> the
> current handle and it is not itself.
> Any statements below `HandleCallStmt` MUST not be executed.
>
> Unlike goto, each `HandleStmt` is independent on each other, one
> `HandleStmt`
> end on itself, either by calling `return` or `handle`, or by other
> `HandleStmt` and does not fallthrough below it.
>
> Given the list of handle below,
>
> 
> :handle1:
> S0
> S1
> :handle2:
> handle handle1
> S3
> 
>
> A `handle1` cannot call `handle2` because its below it.
> A `handle2` cannot call `handle2`, because its the same handle.
> A `handle2` can call `handle1`.
> The `handle1` execution stop at statement `S1`, not fallthrough below it.
> The `handle2` execution stop at statement "`handle handle1`", any
> statements
> below it will not be executed.
>
>
> The following function show an example of using this proposed error
> handling.
> Note that the handlers are defined several times here for showing the
> possible cases on how it can be used, the actual handlers probably only
> two or
> 

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

2023-06-17 Thread Shulhan
On Sun, 4 Jun 2023 12:36:20 -0700
Ian Lance Taylor  wrote:

> On Sun, Jun 4, 2023 at 9:17 AM Shulhan  wrote:
> >
> > I have been reading several proposals about error handling couple of
> > months ago and today a light bulb come upon me, and then I write as
> > much as I can think.  I am not sure if its good or bad idea or even
> > possible to implement.
> >
> > In this post, I will try as concise as possible.
> > The full and up to date proposal is available at
> > https://kilabit.info/journal/2023/go2_error_handling/ .
> >
> > Any feedback are welcome so I can see if this can move forward.
> 
> Thanks.  Perhaps I misunderstand, but this seems to provide a
> different way of writing an if statement and a goto statement.
> Instead of writing
> 
> if err != nil {
> goto parseError
> }
> 
> I can write
> 
> when err handle parseError
> 

In some sense yes, it is identical to writing and combining if and goto
statements.
The semantic of `when` different on the condition that they evaluate.

The `if` statement only continue if expression evaluate to true, the
`when` condition only continue if the expression evaluate to non-zero
value.
So, the "when" statement provide a connection with the handle label.

The goto imply that the statements before it fall-through after it.
For example,

S0
goto1:
S1
goto2:
S2

Statement S1 will be executed after S0, statement S2 will be executed
after S1.
Case in example, the following goto example will loop forever,

if true { goto goto2 }

goto1:
println("goto1")
goto2:
println("goto2")
goto goto1


While handle ":name:" scope only on that handle body.

The following properties describes how handle and its label are
different with goto and its label,

*  Each of `HandleStmt` MUST be declared at the bottom of function
   block.
*  An `HandleStmt` can call other `HandleStmt` as long as the handle is
   above the current handle and it is not itself.
*  Any statements below `HandleCallStmt` MUST not be executed.
*  Unlike goto, each `HandleStmt` is independent on each other, one
   `HandleStmt` end on itself, either by calling `return` or `handle`,
   or by other `HandleStmt` and does not fall-through below it.

For example,

S0
:handle1:
S1
:handle2:
S2

Statement S0 stop and never fall-through :handle1:.
Statement S1 stop and never fall-through :handle2:.
Case in example, the following handle will not end with infinite loop,

...
when err handle handle2

:handle1:
println("handle1")
:handle2:
println("handle2")
handle handle1


> Any change to error handling is going to affect all Go code
> everywhere.  If we change anything it needs to be a big improvement.
> It's not worth changing all Go code everywhere for a small
> improvement.  After all, Go does work OK today for most people.

Agree with that.

The original purpose of this proposal in the Abstract [1] is that its
not only can be use for handling error but also for handling other
control flow.

The goals is not to reduce number of lines but to minimise repetitive
error handling.

> It's
> not clear to me that this proposal is a big enough improvement.
> Thanks.

I am shooting in the dark here and see if it make sense from other
perspective.
Thanks for reviewing.

--
[1] https://kilabit.info/journal/2023/go2_error_handling/#abstract

-- 
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/20230617134702.1b136cf0%40inspiro.localdomain.


pgpnP3sjfGS3P.pgp
Description: OpenPGP digital signature


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

2023-06-04 Thread Ian Lance Taylor
On Sun, Jun 4, 2023 at 9:17 AM Shulhan  wrote:
>
> I have been reading several proposals about error handling couple of
> months ago and today a light bulb come upon me, and then I write as much
> as I can think.  I am not sure if its good or bad idea or even possible
> to implement.
>
> In this post, I will try as concise as possible.
> The full and up to date proposal is available at
> https://kilabit.info/journal/2023/go2_error_handling/ .
>
> Any feedback are welcome so I can see if this can move forward.

Thanks.  Perhaps I misunderstand, but this seems to provide a
different way of writing an if statement and a goto statement.
Instead of writing

if err != nil {
goto parseError
}

I can write

when err handle parseError

Any change to error handling is going to affect all Go code
everywhere.  If we change anything it needs to be a big improvement.
It's not worth changing all Go code everywhere for a small
improvement.  After all, Go does work OK today for most people.  It's
not clear to me that this proposal is a big enough improvement.
Thanks.

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/CAOyqgcWWCFHG%2B0Ahf6qtCgRrEFe%3DrdAt78ZzpUvY_thXvz8vdA%40mail.gmail.com.


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

2023-06-04 Thread Shulhan
Dear gophers,

I have been reading several proposals about error handling couple of
months ago and today a light bulb come upon me, and then I write as much
as I can think.  I am not sure if its good or bad idea or even possible
to implement.

In this post, I will try as concise as possible.
The full and up to date proposal is available at
https://kilabit.info/journal/2023/go2_error_handling/ .

Any feedback are welcome so I can see if this can move forward.
Thanks in advance.

==  Background

This proposal is based on "go2draft Error Handling".

My critics to "go2draft Error Handling" is the missing correlation
between handle and check.
If we see one of the first code in the design,


...
handle err {
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}

r := check os.Open(src)
...


There is no explicit link between check keyword and how it will trigger
handle err later.
It is also break the contract between the signature of os.Open, that
return an error in the second parameter, and the code that call it.

This proposal try to make the link between them clear and keep the code
flow explicit and readable.

The goals is not to reduce number of lines but to minimize repetitive
error handling.


== Proposal

This proposal introduces two new keywords and one new syntax for
statement.

The two new keywords are “WHEN” and “HANDLE”.


When = "when" NonZeroValueStmt HandleCallStmt .
NonZeroValueStmt = ExpressionStmt
 ; I am not quite sure how to express non-zero value
 ; expression here, so I will describe it below.

HandleCallStmt   = "handle" ( HandleName | "{" SimpleStmt "}" ) .
HandleName   = identifier .


The HandleCallStmt will be executed if only if the statement in
NonZeroValueStmt returned non-zero value of its type.
For example, given the following variable declarations,


var (
err   = errors.New(`error`)
slice = make([]byte, 1)
no1   = 1

no2 int
ok  bool
)


The result of when evaluation are below,


when err // true, non-zero value of type error.
when len(slice) == 0 // true, non-zero value of type bool.
when no1 // true, non-zero value of type int.
when no2 // false, zero value of int.
when ok  // false, zero value of bool.


The HandleCallStmt can jump to handle by passing handle name or provide
simple statement directly.
If its simple statement, there should be no variable shadowing happen
inside them.

Example of calling handle by name,


...
when err handle myErrorHandle

:myErrorHandle:
return err


Example of calling handle using simple statement,


...
when err handle { return err }


The new syntax for statement is to declare label for handle and its body,


HandleStmt  = ":" HandleName ":" [SimpleStmt] [ReturnStmt | HandleCallStmt] .


Each of `HandleStmt` MUST be declared at the bottom of function block.
An `HandleStmt` can call other `HandleStmt` as long as the handle is above the
current handle and it is not itself.
Any statements below `HandleCallStmt` MUST not be executed.

Unlike goto, each `HandleStmt` is independent on each other, one `HandleStmt`
end on itself, either by calling `return` or `handle`, or by other
`HandleStmt` and does not fallthrough below it.

Given the list of handle below,


:handle1:
S0
S1
:handle2:
handle handle1
S3


A `handle1` cannot call `handle2` because its below it.
A `handle2` cannot call `handle2`, because its the same handle.
A `handle2` can call `handle1`.
The `handle1` execution stop at statement `S1`, not fallthrough below it.
The `handle2` execution stop at statement "`handle handle1`", any statements
below it will not be executed.


The following function show an example of using this proposed error handling.
Note that the handlers are defined several times here for showing the
possible cases on how it can be used, the actual handlers probably only two or
three.


func ImportToDatabase(db *sql.DB, file string) (error) {
when len(file) == 0 handle invalidInput

f, err := os.Open(file)
when err handle fileOpen
// Adding `== nil` is OPTIONAL, the WHEN operation check for NON zero
// value of returned function or instance.

data, err := parse(f)
when err handle parseError

err = f.Close()
// Inline error handle.
when err handle { return fmt.Errorf(`%s: %w`, file, err) }

tx, err := db.Begin()
when err handle databaseError

// One can join the statement with when using ';'.
err = doSomething(tx, data); when err handle databaseError

err = tx.Commit()
when err handle databaseCommitError

var outofscope string
_ = outofscope

// The function body stop here if its not expecting RETURN, otherwise
//