On Thu, 29 Sep 2016 19:35:49 +0200
Axel Wagner <axel.wagner...@googlemail.com> wrote:

[...]
> > With type assertions, I really fail to see how returning the zero
> > value for the target type in case the type assertion failed can be
> > useful.
> >
> 
> For example: You are using context.Context, save a thing under a
> given key and then provide functions to extract it and do stuff to it
> (say, you have a logger saved in a context). You also make, as a good
> go citizen, the zero value of the thing useful.
> You can still write that, like this:
> 
> func Log(ctx context.Context, fmt string, v ...interface{}) {
>     l, _ := ctx.Value(loggerKey).(*Logger)
>     l.Printf(fmt, v...)
> }

Henrik tried to highlight a caveat of this approach:

--------8<--------
package main

type Logger struct {
}

func (l *Logger) Printf(args ...interface{}) {
        // Do nothing, intentionally to be OK with nils
}

func main() {
        var n int = 42

        var wi interface{} = n

        l, _ := wi.(Logger)
        l.Printf("whatever")
}
--------8<--------

(Playground link: <https://play.golang.org/p/MpZFXvHb3i>).

This program does not crash, it called a method on a Logger-typed value
which was "automagically produced" from an integer by actively abusing
the two-argument form of type assertion.

It's abusing because if you want to call functions on your logger while
not being interested whether it was set or not, you just don't need to
do anything besides type-asserting its container value to be *Logger.
That works because interface{} contains two things: the type and the
value of that type.  The latter can perfectly be nil for pointer types.

To demonstrate:

--------8<--------
package main

import "fmt"

type Logger struct {
}

func (l *Logger) Printf(args ...interface{}) {
        if l == nil {
                fmt.Println("I'm nil")
        } else {
                fmt.Println("I'm not nil")
        }
}

func main() {
        set := &Logger{}
        missing := (*Logger)(nil)

        var wi interface{}

        wi = set
        log(wi)

        wi = missing
        log(wi)
}

func log(wi interface{}) {
        l := wi.(*Logger)
        l.Printf()
}
--------8<--------

(Playground link: <https://play.golang.org/p/k908qwqad9>).

As you can see here, we "blindly" type-assert the value to be *Logger
in the log() function using it, and on the first call that
"decapsulates" a non-nil pointer value while on the second call it
fetches a nil value.  The point is: in both cases these values have
the type *Logger.

Maybe you forgot about the distinction between a nil value of interface
type and a nil value _contained_ in an interface value?
I mean <https://golang.org/doc/faq#nil_error>.

-- 
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.
For more options, visit https://groups.google.com/d/optout.

Reply via email to