phpc.social is one of the many independent Mastodon servers you can use to participate in the fediverse.
A server for PHP programmers & friends. Join us for discussions on the PHP programming language, frameworks, packages, tools, open source, tech, life, and more.

Administered by:

Server stats:

801
active users

Rafael Kassner

Honestly, still confuses me daily.

This snippet compiles but segfaults, but removing the embedded interface on line 8 actually makes compilation fail, as one would expect. What is going on here? Why does *adding* an interface to the struct makes it less safe?

go.dev/play/p/F73QSt9d-m1

go.devGo Playground - The Go Programming Language

@kassner `a.Perform()` is shorthand for `a.Action.Perform()` -- in other words, "Action" is a field in ActionA and it happens to be nil because no value has been assigned to it.

@serickson I understand that from the structs. But what is the rationale to have the same behavior for interfaces, given they can't have implementations themselves?

@serickson I understand that.

My questioning is why my initial code segfaults instead of doing the proper type-check. If interfaces must be implemented, why isn't the compiler validating this?

@kassner @serickson That's how the methods are referenced but as you noted, interfaces doing have implementations. You have to implement the method. In your case, you're defining a struct that contains an interface but is nil, and calling a method on a nil pointer will fail.

@heaths @kassner To explain the runtime error: `a.Action` has no value assigned to it. In the case of interface values, the zero-value is a nil pointer, so` a.Action.Perform()` is a "nil pointer dereference."

@kassner The compiler doesn't check whether you initialised all your fields with non-nil values, that's a runtime thing, not type checking. The way you create an instance of ActionA leaves the Action field of the struct nil.

If you write it like this it perhaps becomes clearer:

go.dev/play/p/pC4dR0pW6oy

go.devGo Playground - The Go Programming Language

@kassner Another hint:

Interfaces consist of two parts, a type and a value. At least the type must be non-nil for interface methods to be callable. All that is inherently runtime-checked. Look at this:

go.dev/play/p/dueTNk-REYF

Even a nil-value but a concrete type can make it work (depending on whether Perform can cope with nil-values).

go.devGo Playground - The Go Programming Language