Hi,

assume that method values were not promoted to pointer types.
And pointer receiver methods can obviously not get promoted to value types:
If you pass
var v T; f(v)
you don't expect `v` to be modified. But pointer methods would expect that.
You'd get hard to find, confusing bugs.
So the method set of a type is exactly the set of methods declared with
that receiver type.

Now consider flag.Value <https://pkg.go.dev/flag#Value>.
Obviously, the Set method requires a pointer receiver *T.
If String would have a value receiver T, then neither T nor *T would
implement flag.Value: Neither type has *both* methods.
So String also needs to have a pointer receiver.
But that means, if you do e.g.
var t time.Time; fmt.Println(t)
the String method would not get called - it would format as something like
{42,23,0xdeadbeef}.

The promotion of value receiver methods to pointer types means it is
possible for a type to mix receiver kinds. Methods that make more sense on
a value - like String - can use a value receiver, while methods that
require a pointer - like Set - can still use a pointer receiver.
Yes, this means the program will panic if you call String on a nil-pointer.
But… well, don't do that, then. It would panic if the receiver was a
pointer receiver as well, as soon as it tries to access on of the receivers
fields (which it needs to do to stringify).

What is a little bit confusing is, that while pointer receiver methods are
not promoted to value types, you can still do
var b strings.Builder; b.WriteString("foo")
despite WriteString having a pointer receiver. That's because the selector
expression becomes syntactic sugar for (&b).WriteString under these
circumstances.
Personally, I kind of feel this was a mistake, but c'est la vie.

On Tue, 10 Jun 2025 at 22:06, Alexander Shopov <a...@kambanaria.org> wrote:

> Does anyone have any idea why method sets were designed like this?
>
> Method sets of pointer types include the methods defined on the type
> that the pointer points to (Explicitly pointed out in spec
> https://go.dev/ref/spec#Method_sets)
>
> I get the idea that having a pointer means that one can mutate the
> value - so in essence it may be useful to have the pointer method set
> contain the value method set.
> But having a pointer to a value does not guarantee the existence of value.
>
> Let's have a look at this trivial example:
> https://go.dev/play/p/ztNRPYfoAuk
>
> type num interface {
>
> num() int
> }
>
> type example struct{}
>
> func (e example) num() int {
>   return 42
> }
>
> func useNum(n num) {
>   fmt.Println(n == nil)
>   v := reflect.ValueOf(n)
>   fmt.Println(v.Kind() == reflect.Ptr && v.IsNil())
>   fmt.Println(n.num())
> }
>
> func main() {
>   var e1 example
>   var e2 *example
>   useNum(e1)
>   useNum(e2)
> }
>
> useNum has no safe way to call the num() method, even though we are
> sure it is safe to call on a nil, in essence it never accesses the
> state of the example struct.
> However a caller can substitute a value with a pointer. Within the
> useNum function we cannot guard with a n != nil since it receives an
> interface and it will not be nil.
> The only way to guard is with reflection.
>
> This same method is also used in Go standard library:
> - https://go.dev/src/fmt/print.go#L592
> - https://go.dev/src/log/slog/handler.go#L564
>
> So given this - is there any source on why method sets were designed this
> way?
>
> Kind regards:
> al_shopov
>
> --
> 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 visit
> https://groups.google.com/d/msgid/golang-nuts/CAP6f5Mm1eF4XZw5sJMvrP4-sb2DkppoFuAtzbwUcbdXQyP1J8w%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 visit 
https://groups.google.com/d/msgid/golang-nuts/CAEkBMfH%2Bj14F0pQmaih4MqwNFvCSj23OKTyg9qH_kLipDTG2-w%40mail.gmail.com.

Reply via email to