-
-
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 | |
} |
Seems that this comment before me is sarcastic and maybe not helpful...
If a partial write is a type of error then can you handle it within the handle block? When the handle block doesn't return, does the function continue to execute?
It looks like you are trying to ask about the order of assignment vs error checking.
In the future if you don't present introductory text, a comment above the two functions would be much easier to read.
I wasn't trying to be sarcastic, but I was trying to point out that attempting to communicate in this way is somewhat annoying. I could have done better. I'm sorry.
Looks like @bmizerany is asking whether the handle block returns just an error, or if it has to return every return value defined by its inner function.
Take a look at the line marked "handler A" in this example from the detailed design draft.
func process(user string, files chan string) (n int, err error) {
handle err { return 0, fmt.Errorf("process: %v", err) } // handler A
for i := 0; i < 3; i++ {
handle err { err = fmt.Errorf("attempt %d: %v", i, err) } // handler B
handle err { err = moreWrapping(err) } // handler C
check do(something()) // check 1: handler chain C, B, A
}
check do(somethingElse()) // check 2: handler chain A
}
Based on this, my understanding is that any return statement defined inside a handler would need to include the entire return signature. To me, this is less surprising and results in code which is easier to read.
@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.
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.
@elimisteve your version returns n = 22, not 23, right?
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.
ItLooksLikeYouAreTryingToAskAboutTheOrderOfAssignmentVsErrorChecking.