Golang Operator Overloading - go

I understand that golang does not provide operator overloading, as it believe that it is increasing the complexity.
So I want to implement that for structures directly.
package main
import "fmt"
type A struct {
value1 int
value2 int
}
func (a A) AddValue(v A) A {
a.value1 += v.value1
a.value2 += v.value2
return a
}
func main() {
x, z := A{1, 2}, A{1, 2}
y := A{3, 4}
x = x.AddValue(y)
z.value1 += y.value1
z.value2 += y.value2
fmt.Println(x)
fmt.Println(z)
}
https://play.golang.org/p/1U8omyF8-V
From the above code, the AddValue works as I want to. However, my only concern is that it is a pass by value and hence I have to return the newly added value everytime.
Is there any other better method, in order to avoid returning the summed up variable.

Yes, use pointer receiver:
func (a *A) AddValue(v A) {
a.value1 += v.value1
a.value2 += v.value2
}
By using a pointer receiver, the address of a value of type A will be passed, and therefore if you modify the pointed object, you don't have to return it, you will modify the "original" object and not a copy.
You could also simply name it Add(). And you could also make its argument a pointer (for consistency):
func (a *A) Add(v *A) {
a.value1 += v.value1
a.value2 += v.value2
}
And so using it:
x, y := &A{1, 2}, &A{3, 4}
x.Add(y)
fmt.Println(x) // Prints &{4 6}
Notes
Note that even though you now have a pointer receiver, you can still call your Add() method on non-pointer values if they are addressable, so for example the following also works:
a, b := A{1, 2}, A{3, 4}
a.Add(&b)
fmt.Println(a)
a.Add() is a shorthand for (&a).Add(). Try these on the Go Playground.

Related

Go generics in methods [duplicate]

This question already has answers here:
How to create generic method in Go? (method must have no type parameters)
(2 answers)
Is there a way to map an array of objects in golang?
(1 answer)
Closed last year.
Thanks to the new 1.18 beta release of Go, we can use new Generic feature. First thing I tried to do is to implement Map / Filter / Reduce to any slice.
So with a Generic Slice Type defined as :
type Slice[T any] []T
I can implements my two first methods Map and Filter as follows:
func (s Slice[T]) Map(callback func(item T, indice int, arr Slice[T]) T) Slice[T] {
temp := make([]T, 0)
for i, v := range s {
temp = append(temp, callback(v, i, s))
}
return temp
}
func (s Slice[T]) Filter(callback func(item T, indice int, arr Slice[T]) bool) Slice[T] {
temp := make([]T, 0)
for i, v := range s {
if callback(v, i, s) {
temp = append(temp, v)
}
}
return temp
}
This works fine as follows:
s := Slice[int]{1, 2, 3}
mapped := s.Map(func(item int, indice int, arr Slice[int]) int {
return item*2 + len(arr) + indice
})
fmt.Println(mapped) // Print : [5 8 11]
filtered := s.Filter(func(item int, _ int, _ Slice[int] ) bool {
return item%2==0
})
fmt.Println(filtered) // Print : [2]
Now, I'd like to implements my "Reduce" function, in the same way the Javascript Reduce works... In the Javascript version, we pass a callback with the accumulator, the current element, the index of the current element in the array and the array itself. It should return the accumulator; and a second argument: the initial value.
So, the slice should be generic over T, but the accumulator could be another generic value
I tried to code something like:
func (s Slice[T]) Reduce[V any](callback func(accumulator V, current T) V, initial V) V {
...
}
With this signature, based on a slice of T, my method will take a callback and an initial value of another generic type V. The callback accumulator is from this second generic V (and will return V) based on each current element of type T.
Unfortunately this code produces:
syntax error: method must have no type parameters
It seems we can't use any other type parameter except one declared on the receiver.
Is there any solution for this use case?

What's the reason for having methods outside the definition of the struct?

Why do we have the methods declared outside the type definition of the struct? E.g.:
type antenna struct {
name string
length float32
girth float32
bloodtype string
}
func (p *antenna) extend() {
p.length += 10
}
It seems to me that the method could be part of the struct? (Let's ignore for now that structs are supposed to be value types)
type antenna struct {
name string
length float32
girth float32
bloodtype string
func extend() {
length += 10
}
}
This would be more similar to traditional OOP. I didn't find any good explanations of why it is done the way it is besides "structs are value-types and classes are reference-types". I know the difference, but it's not a satisfactory answer to me. In any way the method has to be called like this:
var x = antenna()
x.extend()
So what's the point of separating the the struct and methods? Having them visually grouped together in the code - as in typical OOP languages - seems useful to me?
TLR: Code reuse, and Consistency.
1 - This enables to reuse methods:
This is the key design principle of the interface type in Go - let me make it more clear with an example: Consider you need to sort an slice of int (try it here):
a := []int{1, 3, 2, 5, 4}
sort.Ints(a) // sort.Sort(sort.IntSlice(a))
fmt.Println(a) // [1 2 3 4 5]
You simply call sort.Ints(a) which then calls Sort(IntSlice(a)) inside the standard library:
type IntSlice []int
func (x IntSlice) Len() int { return len(x) }
func (x IntSlice) Less(i, j int) bool { return x[i] < x[j] }
func (x IntSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
sort.IntSlice attaches the 3 methods of sort.Interface: Len, Less, and Swap to the type []int, to call:
// Sort sorts data in ascending order as determined by the Less method.
// It makes one call to data.Len to determine n and O(n*log(n)) calls to
// data.Less and data.Swap. The sort is not guaranteed to be stable.
func Sort(data Interface) {
n := data.Len()
quickSort(data, 0, n, maxDepth(n))
}
So you are able to reuse methods from the standard library, and you don't need to reimplement it again.
2- You may define your own types, See this example - There is no inside here for this named type - so methods must be outside of this type:
package main
import "fmt"
type num int32
func (p *num) inc() {
*p++
}
func main() {
p := num(100)
p.inc()
fmt.Println(p) // 101
}
The above named type num versus this user defined type: By design this makes the Go language consistent for both types:
type Animal struct {
Name string
moves []move.Direction
}
func (p *Animal) Walk(dir move.Direction) {
p.moves = append(p.moves, dir)
}
See also:
In Go is naming the receiver variable 'self' misleading or good practice?

Is it possible to alter members of a struct stored in an empty interface

I have this:
type pair struct {
a, b int
}
Then I define two variables:
x := pair{ 3, 4 }
var y interface{} = x
I realize that y doesn't store a reference of x but a copy of it via the following code:
x.b = 7
fmt.Println(x)
fmt.Println(y)
// got:
// {3 7}
// {3 4}
Also see: https://github.com/golang/go/blob/master/src/runtime/iface.go#L359
Is there any way to modify pair.y member of the copied struct in y?
Tried this: (fail)
// cannot assign to y.(pair).b
y.(pair).b = 7
Tried this: (also fail)
// panic: reflect: reflect.Value.SetInt using value obtained using unexported field
v := reflect.ValueOf(y).FieldByName("b")
v.SetInt(33)
Change "b" to "B": (also fail)
type pair {
a, B int
}
// panic: reflect: reflect.Value.SetInt using unaddressable value
v := reflect.ValueOf(y).FieldByName("B")
v.SetInt(33)
Update:
I'm not going to change x.b using y. I want to change y's field b alone.
Thanks for your help, but this is not a simple question about values and references.
You need to know the pointer and address first.Use the pointer can change the value deeply.If you want y to have the same value as x, they need to point to the same address.
I found a solution:
package main
import (
"unsafe"
"fmt"
)
type pair struct {
a, b int
}
func main() {
x := pair{ 3, 4 }
var y interface{} = x
var z interface{} = y
// change x.b
x.b = 7
// change y.b
addr := (*(*[2]uintptr)(unsafe.Pointer(&y)))[1]
pp := (*pair)(unsafe.Pointer(addr))
pp.b = 8
fmt.Println(x) // {3 7}
fmt.Println(y) // {3 8}
fmt.Println(z) // {3 8}
}
It's really hack.
Can anybody provide a more natural/idiomatic one?
Summary:
assigning a concrete value to an empty interface copies the value
assigning an empty interface to another empty interface causes them to share the same underlying value

swap function not working in golang

Actually i just start to learn golang . In the beginning i think that = and := are same . But then i understand that there is some difference between this two .
I learned swap function in golnag
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
But when i rewrite this function using var this is not working
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
var a, b string
a ="hello"
b="world"
swap(a, b)
fmt.Println(a, b)
}
what is the error in this program ?
Another solution is to use pointers:
package main
import "fmt"
func swap(x, y *string) {
*x, *y = *y, *x
}
func main() {
var a, b string
a ="hello"
b="world"
swap(&a, &b)
fmt.Println(a, b)
}
https://play.golang.org/p/-vxUMlaVmN
The reason is that in second case values returned from swap are ignored. SO nothing is changed.
Try: https://play.golang.org/p/uADEf5X15g
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
var a, b string
a = "hello"
b = "world"
a, b = swap(a, b) //// <----
fmt.Println(a, b)
}
To respond your initial question, you should assign the values returned by swap to a and b like so
a, b = swap(b, a)
Notice that this is simple assignment , without the : attached to the equal
also, instead of a swap function, you could just try inplace reassignment:
a, b = b, a
Variables declaration
var a string - declaration of a variable with null value
a := "spam" - declaration of a variable with a concrete value
func f(a, b string) (string, string) { - declaration of a function with value parameters. It means you have new variables with passed values as arguments each time you call a function.
func f(a, b *string) (*string, *string) { - declaration of a function with pointer arguments. In it's turn it means you have pointers to passed variables each time you call the function.
Also...
a := *string - declaration of a pointer variable.
*a - value of a pointer variable.
&a - pointer of a value
In-place swap
To swap in-place (without returning and reassigning) you should swap values between pointers.
func swap(a, b *string) {
*a, *b = *b, *a
}
p.s.
Take into account that strings is read-only slices of bytes. And slices are reference type it means that an array behind the sub-slices of a common array or slice is the same. It doesn't related to the question but should be considered in such cases.

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

Resources