Honestly, #golang 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?
@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.
@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:
@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:
https://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).