Note that there are some explanatory texts on larger screens.

plurals
  1. POIs Google's "Go" language multi-value return statement an alternative to exceptions?
    primarykey
    data
    text
    <p>It seems to me Google's alternatives to exceptions are</p> <ul> <li>GO: multi-value return "return val, err;"</li> <li>GO, C++: nil checks (early return)</li> <li>GO, C++: "handle the damn error" (my term)</li> <li><p>C++: assert(expression) </p></li> <li><p><strong>GO: defer/panic/recover are language features added after this question was asked</strong></p></li> </ul> <p>Is multi-value return useful enough to act as an alternative? Why are "asserts" considered alternatives? Does Google think it O.K. if a program halts if an error occurs that is not handled correctly?</p> <p><strong><a href="http://golang.org/doc/effective_go.html#multiple-returns" rel="noreferrer" title="Effective GO: Multiple return values">Effective GO: Multiple return values</a></strong></p> <blockquote> <p>One of Go's unusual features is that functions and methods can return multiple values. This can be used to improve on a couple of clumsy idioms in C programs: in-band error returns (such as -1 for EOF) and modifying an argument.</p> <p>In C, a write error is signaled by a negative count with the error code secreted away in a volatile location. In Go, Write can return a count and an error: “Yes, you wrote some bytes but not all of them because you filled the device”. The signature of *File.Write in package os is:</p> <p><code>func (file *File) Write(b []byte) (n int, err Error)</code></p> <p>and as the documentation says, it returns the number of bytes written and a non-nil Error when n != len(b). This is a common style; see the section on error handling for more examples.</p> </blockquote> <p><strong><a href="http://golang.org/doc/effective_go.html#named-results" rel="noreferrer" title="GO: Named result parameters">Effective GO: Named result parameters</a></strong></p> <blockquote> <p>The return or result "parameters" of a Go function can be given names and used as regular variables, just like the incoming parameters. When named, they are initialized to the zero values for their types when the function begins; if the function executes a return statement with no arguments, the current values of the result parameters are used as the returned values.</p> <p>The names are not mandatory but they can make code shorter and clearer: they're documentation. If we name the results of nextInt it becomes obvious which returned int is which.</p> <p><code>func nextInt(b []byte, pos int) (value, nextPos int) {</code></p> <p>Because named results are initialized and tied to an unadorned return, they can simplify as well as clarify. Here's a version of io.ReadFull that uses them well:</p> </blockquote> <pre><code>func ReadFull(r Reader, buf []byte) (n int, err os.Error) { for len(buf) &gt; 0 &amp;&amp; err == nil { var nr int; nr, err = r.Read(buf); n += nr; buf = buf[nr:len(buf)]; } return; } </code></pre> <p><strong><a href="http://golang.org/doc/go_faq.html#exceptions" rel="noreferrer" title="Why does Go not have exceptions?">Why does Go not have exceptions?</a></strong></p> <blockquote> <p>Exceptions are a similar story. A number of designs for exceptions have been proposed but each adds significant complexity to the language and run-time. By their very nature, exceptions span functions and perhaps even goroutines; they have wide-ranging implications. There is also concern about the effect they would have on the libraries. They are, by definition, exceptional yet experience with other languages that support them show they have profound effect on library and interface specification. It would be nice to find a design that allows them to be truly exceptional without encouraging common errors to turn into special control flow that requires every programmer to compensate.</p> <p>Like generics, exceptions remain an open issue. </p> </blockquote> <p><strong><a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Exceptions#Exceptions" rel="noreferrer" title="Google C++ Style Guide: Exceptions">Google C++ Style Guide: Exceptions</a></strong></p> <blockquote> <p>Decision:</p> <p>On their face, the benefits of using exceptions outweigh the costs, especially in new projects. However, for existing code, the introduction of exceptions has implications on all dependent code. If exceptions can be propagated beyond a new project, it also becomes problematic to integrate the new project into existing exception-free code. Because most existing C++ code at Google is not prepared to deal with exceptions, it is comparatively difficult to adopt new code that generates exceptions.</p> <p>Given that Google's existing code is not exception-tolerant, the costs of using exceptions are somewhat greater than the costs in in a new project. The conversion process would be slow and error-prone. We don't believe that the <strong>available alternatives to exceptions, such as error codes and assertions,</strong> introduce a significant burden.</p> <p>Our advice against using exceptions is not predicated on philosophical or moral grounds, but practical ones. Because we'd like to use our open-source projects at Google and it's difficult to do so if those projects use exceptions, we need to advise against exceptions in Google open-source projects as well. Things would probably be different if we had to do it all over again from scratch.</p> </blockquote> <p><strong><a href="http://blog.golang.org/2010/08/defer-panic-and-recover.html" rel="noreferrer" title="GO: Defer, Panic and Recover">GO: Defer, Panic and Recover</a></strong></p> <blockquote> <p>Defer statements allow us to think about closing each file right after opening it, guaranteeing that, regardless of the number of return statements in the function, the files will be closed.</p> <p>The behavior of defer statements is straightforward and predictable. There are three simple rules:</p> <p><strong>1. A deferred function's arguments are evaluated when the defer statement is evaluated.</strong></p> <p>In this example, the expression "i" is evaluated when the Println call is deferred. The deferred call will print "0" after the function returns.</p> <pre><code> func a() { i := 0 defer fmt.Println(i) i++ return } </code></pre> <p><strong>2. Deferred function calls are executed in Last In First Out order after the surrounding function returns.</strong> This function prints "3210":</p> <pre><code> func b() { for i := 0; i &lt; 4; i++ { defer fmt.Print(i) } } </code></pre> <p><strong>3. Deferred functions may read and assign to the returning function's named return values.</strong> </p> <p>In this example, a deferred function increments the return value i after the surrounding function returns. Thus, this function returns 2: </p> <pre><code> func c() (i int) { defer func() { i++ }() return 1 } </code></pre> <p>This is convenient for modifying the error return value of a function; we will see an example of this shortly.</p> <p><strong>Panic is a built-in function that stops the ordinary flow of control and begins panicking.</strong> When the function F calls panic, execution of F stops, any deferred functions in F are executed normally, and then F returns to its caller. To the caller, F then behaves like a call to panic. The process continues up the stack until all functions in the current goroutine have returned, at which point the program crashes. Panics can be initiated by invoking panic directly. They can also be caused by runtime errors, such as out-of-bounds array accesses.</p> <p><strong>Recover is a built-in function that regains control of a panicking goroutine.</strong> Recover is only useful inside deferred functions. During normal execution, a call to recover will return nil and have no other effect. If the current goroutine is panicking, a call to <strong>recover will capture the value given to panic and resume normal execution</strong>.</p> <p>Here's an example program that demonstrates the mechanics of panic and defer: </p> <pre><code>&lt;snip&gt; </code></pre> <p>For a real-world example of panic and recover, see the json package from the Go standard library. It decodes JSON-encoded data with a set of recursive functions. When malformed JSON is encountered, the parser calls panic is to unwind the stack to the top-level function call, which recovers from the panic and returns an appropriate error value (see the 'error' and 'unmarshal' functions in decode.go). There is a similar example of this technique in the Compile routine of the regexp package. The convention in the Go libraries is that even when a package uses panic internally, its external API still presents explicit error return values.</p> <p>Other uses of defer (beyond the file.Close() example given earlier) include releasing a mutex:</p> <pre><code>mu.Lock() defer mu.Unlock </code></pre> </blockquote>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload