Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: Go 2: Use `?<variable>` simplify handling of multiple-return-values #33074

Open
gorexlv opened this issue Jul 12, 2019 · 9 comments

Comments

@gorexlv
Copy link

commented Jul 12, 2019

I think the essence of simplifying error handling is to simplifying the handling of multi-return-value.

For example:

// Original 
r, err := os.Open(src)
if err != nil {
   return err
}

// Simplified. 
r := os.Open(src) ?err return err

// If You want to Handle error
r := os.Open(src) ?err handle(err)

// more complicated handling
r := os.Open(src) ?err { handle(err); return err}

// Original
major, minor, ok := http.ParseHTTPVersion("http1.1") 
if !ok {
    os.Exit(1)
}
// To
major, minor := http.ParseHTTPVersion("http1.1") !ok os.Exit(1)

here, importing two special flag: !var and ?var
! means:
assert(var != (zero value) )
if failed, then execute the short circuit logic.

? means:
assert(var == (zero value) )
if failed, then execute the short circuit logic.

	_, ok := imap[key]
       if !ok { 
            imap[key] = make(map[string]interface{}) 
       }
      // ==>
      imap[key] !ok { imap[key] = make(map[string]interface{})}

      if _, err := fn1(); err != nil { return nil, err }
      // ==>
      tt := fn1() ?err return nil, err

       if _, ok := fn2(); !ok { return }
       // ==>
       fn2() !ok return

      for _, s := range []string{...} {
		ret, err := do(s)
               if err != nil { break}
               do2(ret)
	}
       // ==>
       for _, s := range []string{...} {
              ret := do(s) ?err break
              do2(ret)
       }

One of the most common example:

func CopyFile(src, dst string) error {
	r := os.Open(src) ?err return err
	defer r.Close()
	w := os.Create(dst) ?err return err
	defer w.Close()
	io.Copy(w, r) ?err return os.Remove(dst)
	w.Close() ?err return err
}

@gopherbot gopherbot added this to the Proposal milestone Jul 12, 2019

@gopherbot gopherbot added the Proposal label Jul 12, 2019

@afanda0

This comment has been minimized.

Copy link

commented Jul 12, 2019

please leave the "if err != nil" alone !

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Jul 12, 2019

Similar to #33029.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Jul 12, 2019

I don't get this one:

major, minor := http.ParseHTTPVersion("http1.1") ?ok os.Exit(1)

In the examples with err ?err means something like "run the next statement if err != nil". In this example, it seems to mean "run the next statement if !ok". That is, for err it runs the statement if the last result is not the zero value of its type, but for ok it runs the statement if the last result is the zero value of its type. What is the exact rule here?

@gorexlv

This comment has been minimized.

Copy link
Author

commented Jul 12, 2019

I don't get this one:

major, minor := http.ParseHTTPVersion("http1.1") ?ok os.Exit(1)

In the examples with err ?err means something like "run the next statement if err != nil". In this example, it seems to mean "run the next statement if !ok". That is, for err it runs the statement if the last result is not the zero value of its type, but for ok it runs the statement if the last result is the zero value of its type. What is the exact rule here?

@ianlancetaylor
Sorry, actually, here is !ok,
! means:
assert(var != )
if failed, then execute the short circuit logic.

? means:
assert(var == )
if failed, then execute the short circuit logic.

major, minor := http.ParseHTTPVersion("http1.1") !ok os.Exit(1)
@gorexlv

This comment has been minimized.

Copy link
Author

commented Jul 12, 2019

@Allenyn

please leave the "if err != nil" alone !

There are a number of error handling proposals out there, such as check/try/catch, that are heavily modified at the language level or look ugly. I think the error returned by each expression should be taken seriously and should not be changed, but there is a real need to reduce if err != nil { }, It's too ugly, or there wouldn't be so much controversy😀

@gorexlv

This comment has been minimized.

Copy link
Author

commented Jul 12, 2019

@ianlancetaylor
yes, it's similar to #33029. But I want to solve the problem from the perspective of optimizing multi-return value processing. Generally, when multiple values are returned, the last one usually carries the control information. when !ok or err != nil, the workflow is usually break or fix. so maybe it's not bad for adding some syntax sugar for quick break or fix without affecting the main workflow.

@mvndaai

This comment has been minimized.

Copy link

commented Jul 18, 2019

I love that the err variable doesn't need to live outside of when it should be handled.

I am concerned that inlining the handling would make it harder to know the flow of a function.
Would you be okay with gofmt formatting it like this?

r := os.Open(src) ?err {
    return err
}

Which would keep the ability to ignore indented code on a first pass of reading a function. See Mat Ryer's presentation on why he avoids else.

@DongchengWang

This comment has been minimized.

Copy link

commented Jul 20, 2019

The problem is not about err != nil. The problem is about error handling. The ?err is not clear as err != nil.

@gorexlv

This comment has been minimized.

Copy link
Author

commented Jul 24, 2019

r := os.Open(src) ?err {
    return err
}

@mvndaai yeah, maybe it looks confusing.
But I think the key of ?<variable> is simplify handling of multiple-return-values. The statements behinds ?<variable> I call it short-circuit-logic which is usually break or fix current workflow, so it could be ok if only supporting one single (line) function, like:

// return err
r := os.Open(src) ?err return nil, err
// handle err
r := os.Open(src) ?err handle(err)
// handle then return
r := os.Open(src) ?err return nil, handle(err)
// example
io.Copy(w, r) ?err return nil, os.Remove(dst)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants
You can’t perform that action at this time.