Implementing Mixins and an Inconsistency in Compiler Behavior - go

Mixins can be implemented in Go (1.4.1) using embedding and since struct{} occupies no memory (as I understand) it fits for the situations that we want to add some functionality or just add a method to a type that may actually has nothing to do with it's state, but we like to avoid ParseThing(...) and instead write thing.Parse(...).
So having:
type X struct{}
func (x X) F() {
fmt.Println("functionality in X.F()")
}
type Y struct{ X }
type Z struct{ Y }
Then if we do:
var z Z
z.F()
Will give us:
functionality in X.F()
So far so good.
Now let's add another type OX with method F() and embed it in Z:
type Z struct {
Y
OX
}
type OX struct{} // overriding X
func (x OX) F() {
fmt.Println("functionality in OX.F()")
}
Interesting! Now we get functionality in OX.F() which shows us that Go compiler searches for the method, starting from type it self and then the last embedded type. We can check that by adding F() to Z:
func (x Z) F() {
fmt.Println("functionality in Z.F()")
}
The output is functionality in Z.F(). Now if we remove the Z.F() method and add F() to Y:
//func (x Z) F() {
// fmt.Println("functionality in Z.F()")
//}
func (x Y) F() {
fmt.Println("functionality in Y.F()")
}
Then we see this error ambiguous selector z.F; redirecting via pointers makes no difference.
Question 1: Why that's so?
The extra level of indirection Y meant for something else, but brought me to this. And as I've guessed func (t T) String() string{} is an exception. This code:
type X struct{}
func (x X) String() string {
return "in X.String()"
}
type Y struct{ X }
type Z struct {
Y
OX
}
type OX struct{} // overriding X
func (x OX) String() string {
return "in OX.String()"
}
func (x Y) String() string {
return "in Y.String()"
}
And then this:
var z Z
fmt.Println(z)
Gives us:
{in Y.String() in OX.String()}
Which is logical. But if we use pointer receivers:
import (
"fmt"
"testing"
)
func TestIt(t *testing.T) {
var z Z
fmt.Println(z)
}
type X struct{}
func (x *X) String() string {
return "in X.String()"
}
type Y struct{ X }
type Z struct {
Y
OX
}
type OX struct{} // overriding X
func (x *OX) String() string {
return "in OX.String()"
}
func (x *Y) String() string {
return "in Y.String()"
}
Will print out:
{{{}} {}}
Question 2: Why is that so?

Question 1
The compiler is correct. How should it decide, which of OX.F and Y.F should it use? It can't. So it's up to you to call the desired method directly: either with
z.Y.F()
or
z.OX.F()
Edit: As for why your example worked until you've defined F on Y, this is mentioned in the Spec:
For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.
(Emphasis added.)
Before you defined the method, the shallowest implementation was OX.F. After you've defined Y.F, there became two Fs on the same level, which is illegal.
Question 2
Again, the compiler is correct. You have embedded types Y and OX into Z, not *Y and *OX. As written in the Spec,
The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T).
*T has all methods of T, but not the other way around. Methods sets of OX and Y are empty, so obviously, fmt.Println just prints them as if they were any other kind of struct with no String() method defined.

Ainar-G write neat answer
Spec:
For a value x of type T or *T where T is not a pointer or interface
type, x.f denotes the field or method at the shallowest depth in T
where there is such an f. If there is not exactly one f with
shallowest depth, the selector expression is illegal.
I'd like to add a bit
Spec:
If S contains an anonymous field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
So things would work if you just use referencing to promote methods like
fmt.Println(&z)
But this will cause ambiguity in selection cause of there are few possibilities for String method and so selector String is illegal due to spec. Compiler must complain, but it doesn't. This behaviour looks unspecified and can be only explained as special case for common printing operation to my mind.
This will work as expected
var y Y
fmt.Println(&y)
Here is working example
Playground

Related

Type definition - cannot use basic type as custom type even though basic type is source of custom type

In the below code, we are using type definition syntax in Line 5,6,7:
package math
// Constructors and Selectors
type RationalNumber []int // Line 5
type Numerator int
type Denominator int
// Constructor - Construct a rational number x that represents n/d
func NewRationalNumber(n int, d int) RationalNumber {
g := gcd(n, d)
return []int{n / g, d / g} // Line 12
}
//Selector
func numer(x RationalNumber) Numerator {
return x[0] // Line 17
}
//Selector
func denom(x RationalNumber) Denominator {
return x[1]
}
return []int{n / g, d / g} does not give error,
where as,
return x[0] & return x[1] give error:
math/numbers.go:17:10: cannot use x[0] (type int) as type Numerator in return argument
math/numbers.go:22:10: cannot use x[1] (type int) as type Denominator in return argument
For given 3 type definitions in Line 5,6,7, I understand the reason behind error on Line 17, but,
Why Line 12 does not give similar error?
How to resolve this error? without changing the signature of functions?
The defined type RationalNumber was created from a slice with elements of type int, therefore subscription on an instance of the defined type gives an int, not any of the newly defined types created from int.
The compiler does not complain about line 12 since the syntax is the slice literal appropriate for creating the defined type (hint: elements of new slice type are int).
You are returning a type different from what was specified in the function definitions.
Take numer(x RationalNumber) Numerator for example
numer(x RationalNumber) Numerator accepts a variable of type RationalNumber and is expected to return a variable of type Numerator.
The problem is that you are returning a type int (as RationalNumber is a slice of ints) but a type Numerator is expected.
You can refactor your code to cast the int returned by RationalNumber to the appropriate types.
type RationalNumber []int
type Numerator int
type Denominator int
func NewRationalNumber(n int, d int) RationalNumber {
g := gcd(n, d)
return []int{n / g, d / g}
}
func numer(x RationalNumber) Numerator {
return Numerator(x[0])
}
func denom(x RationalNumber) Denominator {
return Denominator(x[1])
}
I know that, my question is why there is no necessity to do RationalNumber([]int{n / g, d / g})?
You do not need to do so because []int{n/g, d/g} is already a slice of ints.
type Numerator = int syntax is resolving the error. Am not sure, how type Numerator = int different from type Numerator int? No need to Numerator(x[0])
type Numerator = int is a type alias for int. This does not create a new type that is distinct from int.
Whereas type Numerator int creates a new custom type called Numerator which has a source type of int. Numerator can be cast to int but it is distinct from int
You can refer to Type definitions vs Type Alias for more explanations
This question bothered me as well, so here is answer that i came up with.
Take your function as an example:
func NewRationalNumber(n int, d int) RationalNumber {
g := gcd(n, d)
return []int{n / g, d / g}
}
According to function signature, it should return RationalNumber type, but in fact it returns int slice. Reason why it works is that type []int is assignable to type RationalNumber. Specifically it satisfies second condition, mentioned in language spec:
x's type V and T have identical underlying types and at least one of V or T is not a defined type.
This condition is satisfied, because in that case, we have only one defined type(RationalNumber) and another one is composite type([]int).
So, why do we get error when we define following function?:
func numer(x RationalNumber) Numerator {
return x[0]
}
Type Numerator has int as underlying type and we return int, which is predeclared type, so it should work, right? No) Thing is, although int is predeclared, it's still defined type. As it's stated in language spec:
To avoid portability issues all numeric types are defined types
In fact, all predeclared types, except error, are defined types.

Constructing instances of types with pointer and value receivers [duplicate]

This question already has answers here:
X does not implement Y (... method has a pointer receiver)
(4 answers)
Closed 4 years ago.
Lets take this very small example, having a function that modify value inside the struct:
package learn
type Point struct {
x int
y int
}
func (p *Point) Set(x int, y int) {
p.x = x
p.y = y
}
this works properly, used like this for instance:
package main
import (
"NewPattern/learn"
"fmt"
)
func main() {
p := learn.Point{}
p.Set(5, 6)
fmt.Print(p)
}
it outputs the expected value: {5,6}
Now let's say I don't want the user having a constructor, I can change the code by adding this function:
func NewPoint(x int, y int) Point {
return Point{x, y}
}
then I can use in main like this:
func main() {
p := learn.NewPoint(3, 8)
fmt.Print(p)
p.Set(5, 6)
fmt.Print(p)
}
and it works as expected returning {3 8}{5 6}.
Well now we want to prevent creating point without calling the constructor - not really the case here, but can make sense for complex classes - so we avoid exporting Point and we create an interface instead, so I refactored the code like this: (this is not working!)
package learn
type point struct {
x int
y int
}
type Point interface {
Set(x int, y int)
}
func (p *point) Set(x int, y int) {
p.x = x
p.y = y
}
func NewPoint(x int, y int) Point {
return point{x, y} //error here
}
This says:
cannot use point literal (type point) as type Point in return argument:
point does not implement Point (Set method has pointer receiver)
I can "fix" this by modifying the method in:
func NewPoint(x int, y int) point {
return point{x, y}
}
but this just move the error in main, that is refactored like:
func main() {
var p learn.Point
p = learn.NewPoint(3, 8) //error here!
fmt.Print(p)
p.Set(5, 6)
fmt.Print(p)
}
and the error is:
cannot use learn.NewPoint(3, 8) (type learn.point) as type learn.Point in assignment:
learn.point does not implement learn.Point (Set method has pointer receiver)
by googling I managed to solve in this way:
func NewPoint(x int, y int) *point {
return &point{x, y}
}
but as a result in the main we are obtaining: &{3 8}&{5 6} as a print, ad as well I don't get actually what is happening behind the scenes.
I guess this is somehow related by having things passed and maybe "returned" by value, is this the case? But I don't know how the first examples without interface worked without effort. Can please someone clarify these details that I think are essential to Go understanding.
point and *point (i.e the pointer to point) are two different types. In your code the interface Point is implemented by *point type. You can implement the constructor as:
func NewPoint(x int, y int) Point {
return &point{x, y}
}
The printing will show & befor the points value as the underlying value is a pointer.

About method implementation for an interface

Can anyone explain why the calling of a.Abs() works?
In my opinion, 'a' is a variable of type *Vertex, but the type *Vertex doesn't implement the method Abs.
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs() float64
}
func main() {
var a Abser
v := Vertex{3, 4}
a = &v // a *Vertex implements Abser
// In the following line, v is a *Vertex (not Vertex)
// and does NOT implement Abser, but why does this calling work?
fmt.Println(a.Abs())
}
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
From the fine specification:
Method sets
[...] The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T). [...]
Your Abs function is in the method sets of both Vertex and *Vertex so *Vertex is an Abser just like Vertex is.
Other related sections:
Method values
Selectors
In general, pointers are automatically dereferenced when possible so you can say x.M() and x.V without worrying about whether or not x is a pointer and there is no need for C's -> or manual dereferencing (i.e. (*x).M() or (*x).V).

Methods with a Pointer Receiver

I am newbie in computer science.I just read the code snippet below from The Go programming language and got the following error log.
func (p *Point) ScaleBy(factor float64){
p.X *= 2
p.Y *= 2
}
Point{1, 2}.ScaleBy(2)
# error log
cannot call pointer method on point literal
cannot take the address of point literal
point literal.scaleby(2) used as value
The book explained that we can not call a *Point method on a non-addressable Point receiver, because there's no way to obtain address of a temporary value.
However, if I print &Point{1, 2}, this would not throw error. Accordingly, why Point{1,2} is a non-addressable Point receiver?
By using Point{1, 2}.ScaleBy(2) you are trying to call pointer receiver method ScaleBy with value: Point{1, 2}:
The method set of any other type T consists of all methods declared
with receiver type T.
but if you use addressable type:
The method set of the corresponding pointer type *T is the set of all
methods declared with receiver *T or T (that is, it also contains the
method set of T).
then it is possible: meaning you or the compiler should get the address of temporary value (Taking the address of a composite literal):
Address operators:
For an operand x of type T, the address operation &x generates a
pointer of type *T to x. The operand must be addressable, that is,
either a variable, pointer indirection, or slice indexing operation;
or a field selector of an addressable struct operand; or an array
indexing operation of an addressable array. As an exception to the
addressability requirement, x may also be a (possibly parenthesized)
composite literal. If the evaluation of x would cause a run-time
panic, then the evaluation of &x does too.
ref: https://golang.org/ref/spec#Address_operators
You may call (&Point{1, 2}).ScaleBy(2)
like this working sample code (pointer receiver):
package main
import "fmt"
func main() {
p := (&Point{1, 2}).ScaleBy(2)
fmt.Println(p) // &{2 4}
}
type Point struct {
X, Y int
}
func (p *Point) ScaleBy(factor float64) *Point {
p.X *= 2
p.Y *= 2
return p
}
you may call Point{1, 2}.ScaleBy(2)
like this working sample code (value receiver):
package main
import "fmt"
func main() {
p := Point{1, 2}.ScaleBy(2)
fmt.Println(p) // &{2 4}
}
type Point struct {
X, Y int
}
func (p Point) ScaleBy(factor float64) *Point {
p.X *= 2
p.Y *= 2
return &p
}
output:
&{2 4}
also see this working sample code (pointer receiver):
package main
import "fmt"
func main() {
p := Point{1, 2}
p.ScaleBy(2)
fmt.Println(p) // {2 4}
}
type Point struct {
X, Y int
}
func (p *Point) ScaleBy(factor float64) {
p.X *= 2
p.Y *= 2
}
output:
{2 4}
When you write Point{1,2} you simply declaring and initializing a value of type Point. If you don't assign it to a variable, it is discarded.
Go disallows this behavior of calling a pointer method on a simple value since a pointer method states an intent of object (pointed to by the pointer) modification. A pointer method called with a value would be useless in most of the cases since a value is passed by copy to the method. Any modifications made to the value will be done to that copied value and no actual modification would occur.
If you tried this, it would work:
type Point struct {
x, y int
}
func (p Point) X() {
fmt.Println(p.x)
}
Point{1, 2}.X() // 1
You can read more about it here: https://golang.org/doc/effective_go.html#pointers_vs_values

Method receivers ambiguity

Working on the go tour today. I noticed that I could pass struct literals to methods associated with pointer to structs, and vice versa. Why is this allowed?
package main
import (
"fmt"
)
type Vertex struct {
X, Y float64
}
func (v Vertex) Scale (f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func (v *Vertex) ScaleP(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := &Vertex{3, 4}
vLiteral := Vertex{3, 4}
v.Scale(5)
fmt.Println(v)
v.ScaleP(5)
fmt.Println(v)
vLiteral.Scale(5)
fmt.Println(vLiteral)
vLiteral.ScaleP(5)
fmt.Println(vLiteral)
}
Output:
&{3 4}
&{15 20}
{3 4}
{15 20}
See Method sets:
A type may have a method set associated with it (§Interface types, §Method declarations). The method set of an interface type is its interface. The method set of any other type T consists of all methods with receiver type T. The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T). Further rules apply to structs containing anonymous fields, as described in the section on struct types. Any other type has an empty method set. In a method set, each method must have a unique method name.
The method set of a type determines the interfaces that the type implements and the methods that can be called using a receiver of that type.
EDIT:
See also Calls:
A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m():

Resources