Re: [go-nuts] Type assertion: panic: value method time.Time.String called using nil *Time pointer"

2021-06-10 Thread 'Axel Wagner' via golang-nuts
On Thu, Jun 10, 2021 at 2:50 PM Markus Heukelom 
wrote:

> Question 1:
>
> I don't understand when the type assertion succeeds here, as the receiver
> for time.Time.String() is (t time.Time), not (t *time.Time).
>

The method set of `*Time` includes all methods declared on `Time` (but not
vice-versa):
https://golang.org/ref/spec#Method_sets
So even though the receiver of `String() string` is not a pointer, `*Time`
still has a `String() string` method.

Does this mean that I should read "dynamic type of x" as "the actual type
> of x" or the "dereferenced type of x if x is a pointer"? Is there a formal
> definition of "dynamic type of x"? Or should I look at a different part of
> the spec?
>

The dynamic type is explained here: https://golang.org/ref/spec#Variables

The static type (or just type) of a variable is the type given in its
> declaration, the type provided in the new call or composite literal, or the
> type of an element of a structured variable. *Variables of interface type
> also have a distinct dynamic type, which is the concrete type of the value
> assigned to the variable at run time* (unless the value is the
> predeclared identifier nil, which has no type). The dynamic type may vary
> during execution but values stored in interface variables are always
> assignable to the static type of the variable.


(emphasis mine)

Question 2:
>
> Accepting that I get "true" on a pointer to a type that implements
> fmt.Stringer, how can I check that I can actually safely call
> stringer.String()?
>

You can't. Any Go code might panic. That is, no matter what check you do,
the `String()` method could just call `panic("oh well")`.


> I.e. how can I prevent the runtime panic?
>

The, probably unsatisfactory, but only really true answer is "by not
assigning a nil `*time.Time` to a `fmt.Stringer` and then call `String()`
on that". The runtime panic tells you that your code has a bug. The
solution to that is to fix the bug.
Note that `time.Time` documents that you shouldn't use it as a pointer in
any case.

If it's any consolation: Even if there was a check that's correct,
remembering to do that check would be just as hard (if not harder) as
remembering not to call the method on a nil-pointer or storing a
nil-pointer in a `fmt.Stringer` to begin with :)

Without using reflection. Please note: I do not mean checking if there is a
> nil pointer in x: the error is not raised by the time.String()
> implementation, in fact it might work fine with nil pointers were it
> defined using a pointer receiver. It seems the error is thrown by the
> runtime.
>
> Thanks,
>
> Markus
>
> --
> 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.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CAMoB8rV%3DQTcHXRC4KvJfcHC9zo8oAE0LR9%3D4ywVb_s-iejX14A%40mail.gmail.com
> 
> .
>

-- 
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.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAEkBMfH53Of8mhvyigdXbmYgWfLRujkbWOLM6QheVcqoYqZnZQ%40mail.gmail.com.


[go-nuts] Type assertion: panic: value method time.Time.String called using nil *Time pointer"

2021-06-10 Thread Markus Heukelom
Code:

package main

import (
"fmt"
"time"
)

func main() {

var my *time.Time
var any interface{}
any = my

stringer, ok := any.(fmt.Stringer)
println(ok) // "true", but I expected "false", as the receiver for
time.Time.String() is (t time.Time), not (t *time.Time)
println(stringer.String()) // "panic: value method time.Time.String called
using nil *Time pointer"
}

playground: https://play.golang.org/p/qVyr_u11Tku

Question 1:

I don't understand when the type assertion succeeds here, as the receiver
for time.Time.String() is (t time.Time), not (t *time.Time). The language
specification states:

"If T is an interface type, x.(T) asserts that the dynamic type of x
implements the interface T."

(from: https://golang.org/ref/spec#Type_assertions)

Does this mean that I should read "dynamic type of x" as "the actual type
of x" or the "dereferenced type of x if x is a pointer"? Is there a formal
definition of "dynamic type of x"? Or should I look at a different part of
the spec?

Question 2:

Accepting that I get "true" on a pointer to a type that implements
fmt.Stringer, how can I check that I can actually safely call
stringer.String()? I.e. how can I prevent the runtime panic? Without using
reflection. Please note: I do not mean checking if there is a nil pointer
in x: the error is not raised by the time.String() implementation, in fact
it might work fine with nil pointers were it defined using a pointer
receiver. It seems the error is thrown by the runtime.

Thanks,

Markus

-- 
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.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAMoB8rV%3DQTcHXRC4KvJfcHC9zo8oAE0LR9%3D4ywVb_s-iejX14A%40mail.gmail.com.