Skip to content

Instantly share code, notes, and snippets.

@bmizerany
Last active December 1, 2018 22:47
Show Gist options
  • Save bmizerany/fcd0348bda96edce05a4fc7426e47751 to your computer and use it in GitHub Desktop.
Save bmizerany/fcd0348bda96edce05a4fc7426e47751 to your computer and use it in GitHub Desktop.
package question
func whatsTheEquivalentOfThisWithHandleCheckQuestionMark(w io.Writer) (rN int, err error) {
w = LimitedWriter{w, 23}
n, err := io.WriteString(w, "some data 1") // 11 bytes written
rN += n
if err != nil {
return err
}
n, err := io.WriteString(w, "some data 2") // 22 bytes written
rN += n
if err != nil {
return err
}
n, err := io.WriteString(w, "some data 3") // 23 bytes written: BOOM!!!
rN += n
return rN, err
}
func canItBeThisQuestionMark(w io.Writer) (n int, err error) {
handle err { return n, err }
w = LimitedWriter{w, 23}
n += check io.WriteString(w, "some data 1") // 11 bytes written
n += check io.WriteString(w, "some data 2") // 22 bytes written
n += check io.WriteString(w, "some data 3") // 23 bytes written: BOOM!!!
return nil
}
@bmizerany
Copy link
Author

bmizerany commented Sep 6, 2018

@kalexmills I'm wondering if the addition is performed before the error passed to handle. If it isn't the case that the addition is performed, then will the code I wrote compile? It seems to me this could be something the compiler will aid in catching.

@elimisteve
Copy link

elimisteve commented Sep 8, 2018

My hope is that canItBeThisQuestionMark would not compile, and that instead we'd have to write

func canItBeThisQuestionMark(w io.Writer) (n int, err error) {
	handle err { return n, err }
	w = LimitedWriter{w, 23}
	nb := check io.WriteString(w, "some data 1") // 11 bytes written
	n += nb
	nb = check io.WriteString(w, "some data 2") // 22 bytes written
	n += nb
	nb = check io.WriteString(w, "some data 3") // 23 bytes written: BOOM!!!
	n += nb
	return n, nil
}

even though it is not as clean.

@nigeltao
Copy link

@elimisteve your version returns n = 22, not 23, right?

@baryluk
Copy link

baryluk commented Dec 1, 2018

I do not see a problem.

With handle err { return n, err }, it will return 22, err

With handle err { return n, err }, it will return 0, err

Programmer is in control. Sometimes it might be exactly what you want. I.e. what if you are consuming data from a socket or pipe, or parsing, and you find an error only at position x. Similarly if the WriteString is to a socket. You can't unread / unwrite this data.

If you are asking about whatever n will be updated, in a situation where WriteString returns (1, SomeError), then this 1 will be ignored, and n += 1, will not be performed.

In a situation like this you would write:

n3, err = io.WriteString(w, "some data 3")
n += n3
check err

maybe?

This is because n += check X()

is rewritten to:

``
temp, err := X()
if err != nil { call handler with err; return; }
n += temp


This is the same as using normal `:=` operator:

``
temp, err := X()
if err != nil { call handler with err; return; }
n := temp

Notice that in Go you can't express assignment to err, and increment of n in a single statement anyway.

It does mean however than

n = check X()

and

n, err = X()
if err != nil { return err; }

do have different semantic (and the first one would use extra register / stack space). This probably only applies to return values tho. In other cases, compiler should be able to do the same as before.

I did not see the semantic explained precisely in current drafts tho.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment