How to modify fields in struct using methods from interface? - go

I'm writing a small project to learn some Google Go, but after few hours of coding I found that there's an issue I can't solve on my own, neither found on the internet. My project will be containing few algorithms operating on variables implementing one interface. The thing in common of all types is that I can rate them and compare by this rating so one of methods defined in Interface should be SetRating(x int) and the problem is, since Go is copying value - I can't modify any field in it. Here's example
http://play.golang.org/p/4nyxulwzNo
Trying to find out that people is using workarounds in this convention:
http://play.golang.org/p/PUuOBZ4uM-
but I think this solution is a ugly, because I need to know all implementations of my interface in invoke func (to cast types) and really want to avoid this and write some universal code that can get any types implementing my Interface, just knowing that every implementation have method setRating(x int) and getRating(x int).
Any hints?
(Sorry for poor English and problem's description, still learning.)

You need to use the pointer because otherwise you are not modifying the underlying structure: http://play.golang.org/p/l3X4gTSAnF
package main
type Setter interface {
Set(x int)
Print()
}
type S1 struct {
X int
}
func (this *S1) Set(x int) {
this.X = x
println("Setting value")
}
func (this *S1) Print(){
println(this.X)
}
func main() {
var s1 Setter
s1 = &S1{}
s1.Set(5)
s1.Print()
}

Related

Generic attribution to field X, present across multiples types

Currently, I'm working with a set of structures, which define multiple versions of a document. Most of the fields are shared across these different versions, and the actual differences are pretty subtle. What I'm trying to do is refactor the code that parses this document. For that, it would be really good if I could generalize some attributions, where I don't need to know exactly what type I'm working to know that the type will have a specific field.
I've thought about using reflection but if I can avoid it I would.
Lets say we have:
type v1 struct{
a int
}
and
type v2 struct{
a int
b string
}
what I would like to do is something like
func main(){
var v1 v1
var v2 v2
foo(v1)
foo(v2)
}
func foo (root interface{}){
root.a = x
}
is it possible? or is there any other way?
edit:
1 - this is not a duplicate of "Get all fields from an interface" as my problem is not to figure out what type I'm dealing with, but to manipulate/treat different types the same way.
2 - this could be a duplicate of "how to write a function to process two types of input data in golang" but the answer provided fails to solve my issue.
Use anonymous fields, methods and interfaces. You can define a new struct that contains all the common properties to all other structs. Then, an interface could be defined over this shared struct, that lists all the methods to handle the common properties. Finally, in the previous structs you only need to replace all the common fields with this new interface. At this point, you are able to write generic functions that take the interface as input and handle internal common fields through exposed methods.
type SettableA interface{
SetA(int)
A() int
}
type sharedA struct {
a int
}
func (s *sharedA) SetA(val int) {
s.a = val
}
func (s *sharedA) A() int {
return s.a
}
type v1 struct {
SettableA
}
type v2 struct {
SettableA
b string
}
func foo(root SettableA) {
root.SetA(5)
}
func main() {
v1var := v1{
SettableA: &sharedA{},
}
foo(v1var)
v2var := v2{
SettableA: &sharedA{},
b: "test",
}
foo(v2var)
fmt.Printf("V1: %v\nV2: %v\n", v1var.A(), v2var.A())
}
Here the interface is not strictly necessary, but it allows you to write a generic function that handles different concrete types.
https://play.golang.org/p/BgxYrbGE426

In golang, how do I re-assign an external reference from within a function?

I'm probably not expressing this correctly in the question, but perhaps this code will make it clearer:
package main
import "fmt"
type Blob struct {
Message string
}
func assign1(bb **Blob) {
*bb = &Blob{"Internally created by assign1"}
}
func (b *Blob) assign2() {
*b = Blob{"Internally created by assign2"}
}
func main() {
x1 := &Blob{"Hello World"}
assign1(&x1)
fmt.Printf("x1 = %+v\n", *x1)
x2 := Blob{"Hello World"}
x2.assign2()
fmt.Printf("x2 = %+v\n", x2)
}
Produces, as desired:
x1 = {Message:Internally created by assign1}
x2 = {Message:Internally created by assign2}
I want to pass a reference (pointer to a pointer) into a function and have the function assign a new value to the pointer such that the calling scope will see that new value.
I've figured out the above two ways of doing this, but I'd like to know if they are actually correct or if there is some hidden flaw. Also, are either of them more idiomatic than the other?
Coming from Java, assign2 just seems wrong but I'm sure I've seen something similar in the encoding/json package. What is that actually doing?
Thanks!
James answers the mechanics of assign2. I'll touch a bit on when to use it.
Let's take a simpler example, first.
type Counter uint
func (c *Counter) Increment() {
*c += 1
}
In the counter example the entire state of the receiver is changing. Similarly for the encoding/json package the entire state of the receiver is changing. That's really the only time I would use that style.
One major advantage of the style: you can define an interface for the change, just like the GobDecoder does.
When I first saw the assign2 style it was a little grating. But then I remembered that (c *Counter) Increment gets translated to Increment(c *Counter) in the machine code and it didn't bother me anymore. I personally prefer assign1-style. (Though, there is no need for the double pointers as orignally posted.)
package main
import "fmt"
type Blob struct {
Message string
}
func assign1(b *Blob) {
*b = Blob{"Internally created by assign1"}
}
func main() {
x1 := Blob{"Hello World"}
assign1(&x1)
fmt.Printf("x1 = %+v\n", *x1)
}
Both forms are valid Go, as you've discovered.
For the assign2 case, the compiler finds that assign2 does not appear in Blob's method set, but it is part of *Blob's method set. It then converts the method call to:
(&x2).assign2()
While it can be confusing if a method then goes and changes x2 like in your example, there are a number of places in the standard library where this pattern is used. Probably the most common one is implementing custom decoding for a type with the encoding/json module: you implement the DecodeJSON method with a pointer receiver, and update the value being pointed to.

Can embedded methods access "parent" fields?

Background
I've done a fair amount of spec reading and code testing and I think the answer is no, but I want to make sure I'm not missing anything.
Goal
Basically, I'm trying to create a Active Record style ORM for Go, because I like how readable it is and how abstracted it is from its back end data store. I'd rather write user.Save() than data.Save(user) by embedding common CRUD methods on the user struct.
Example
package main
import (
"fmt"
"reflect"
)
func main() {
test := Foo{Bar: &Bar{}, Name: "name"}
test.Test()
}
type Foo struct {
*Bar
Name string
}
func (s *Foo) Method() {
fmt.Println("Foo.Method()")
}
type Bar struct {
}
func (s *Bar) Test() {
t := reflect.TypeOf(s)
v := reflect.ValueOf(s)
fmt.Printf("model: %+v %+v %+v\n", s, t, v)
fmt.Println(s.Name)
s.Method()
}
http://play.golang.org/p/cWyqqVSKGH
Question
Is there a way to make top-level fields (not sure what the correct term in Go is for these) accessible from embedded methods (eg: s.Name or s.Method()?
Thank you donating your time to a new Gopher.
Go doesn't provide any support for what you're after: the receiver of your Test method is a Bar pointer, and there is no way to tell whether it is embedded or not.
If you really want to go this route, one option would be to add an interface{} member to Bar and require that types that it be set to the containing type. Initialising this member could either be the responsibility of whoever created the value, or perhaps require callers to pass the value to some ORM method to set it. This isn't particularly pretty, but it's probably the best you can do.
With that out of the way, is it really that bad to structure the API as db.Save(user) rather than user.Save()? The former offers an obvious way to extend to multiple databases, while the latter seems more likely to rely on global state.
(If I understood your question correctly,) no, embedding isn't inheritance. It sounds like what you're actually after is an interface
type Saver interface {
Save() error
}
then the relevant parties can implement that.
You can have a common struct base or whatever that implements common methods and then each higher-level struct can embed base to allow them to share implementation.

Why create go types based on other?

what is the purpose of defining new types in go:
type NewType OldType
since NewType have only methods declarations, so:
var x NewType
can store also OldType 'objects'. Are there any advantages?
The reason behind naming types in general is fairly straightforward, and is much the same in most languages - being able to name complex types, like:
type Person struct{
name String
age uint8
}
However, naming a type like you described, which I'll call "type aliasing" (not sure if this is used by anyone else, but it's the term I tend to use), doesn't give you the above-mentioned advantage. What it does give you, however, is the ability to add methods to existing types. Go disallows you from adding methods to existing types that you did not define yourself (ie, built-in types or types defined in other packages), so aliasing allows you to pretend that you did define them yourself, and thus add methods to them. Another good way to think about it is like a much more concise version of creating a wrapper type (as you would in an OO language like Java, for example).
So, let's say that I wanted to be able use integers as errors. In Go, the error interface simply requires a method called "Error" which returns a string. Using type aliasing, I could do:
type errorCode int
func (e errorCode) Error() string {
return fmt.Sprintf("%d", e)
}
...and I could use integer error codes. By contrast, if I tried the following, I would get an error:
func (e int) Error() string {
return fmt.Sprintf("%d", e)
}
To demonstrate, check out this implementation:
http://play.golang.org/p/9NO6Lcdsbq
Just to clarify (because my use of the word "alias" may be misleading), two types which are otherwise equivalent (for example, int and errorCode in the above example) are not interchangeable. The Go type system treats them as fundamentally different types, although you may be able to type-cast between them.
The Go Programming Language Specification
Types
A type determines the set of values and operations specific to values
of that type.
You want identify a specific set of values and operations.
For example,
package main
import "fmt"
type Coordinate float64
type Point struct {
x, y Coordinate
}
func (p *Point) Move(dx, dy Coordinate) {
p.x += dx
p.y += dy
}
func main() {
var p = Point{3.14159, 2.718}
fmt.Println(p)
p.Move(-1, +1)
fmt.Println(p)
}
Output:
{3.14159 2.718}
{2.14159 3.718}

Enforcing type in "generic" code with empty interfaces

Sorry for the ambiguous title.
I'm reading this book http://algs4.cs.princeton.edu/home/ and I thought it would be good to implement the examples in Go as a learning exercise, however the book uses Java as its language to describe code in.
One of the first chapters discusses setting up some core datatypes/container style classes to re-use later on but I'm having trouble trying to hammer these into a Go setting, mainly because these datatypes seem to be enjoying the use of Java generics.
For example, I've written the following code
package bag
type T interface{}
type Bag []T
func (a *Bag) Add(t T) {
*a = append(*a, t)
}
func (a *Bag) IsEmpty() bool {
return len(*a) == 0
}
func (a *Bag) Size() int {
return len(*a)
}
This works in principle in the sense that I can add items to a Bag and check its size and everything. However this also means that the following code is legal
a := make(bag.Bag,0,0)
a.Add(1)
a.Add("Hello world!")
a.Add(5.6)
a.Add(time.Now())
I was just wondering if there was any way of enforcing the type so it conforms to a contract similar to
Bag<T> bagOfMyType = new Bag<T>()
e.g.
Bag<Integer> bagOfInts = new Bag<Integer>()
I know Go doesn't have generics and they're not really The Go Way, but I was just wondering if it is a possible to "enforce" anything at compile time (probably not)
Sorry for the long post
EDIT: OK so I've been looking into this a little further, I've pretty much given up with the generics side of things (I understand this is not on the roadmap for Go) so I'm thinking of doing something similar to Haskell typeclasses with interfaces, e.g.
type T interface{}
type Bag interface {
Add(t T)
IsEmpty() bool
Size() int
}
type IntSlice []int
func (i *IntSlice) Add(t T) {
*i = append(*i, t.(int)) // will throw runtime exception if user attempts to add anything other than int
}
func (i *IntSlice) IsEmpty() bool {
return len(*i) == 0
}
func (i *IntSlice) Size() int {
return len(*i)
}
The problem with this is the type enforcement is only enforced at runtime.
Anyone got any ideas how to improve on this?
I'm new to Go myself, so I'm curious if someone will have a better answer, but here's how I see it:
You want compile-time enforcement that when Add() is called on an IntSlice, its parameter is an int. Well, here's how you do that:
func (i *IntSlice) Add(t int) {
*i = append(*i, t)
}
Since there aren't generics, the Add() method is going to be different for every type of Bag, so the Bag interface, assuming you need it, becomes just:
type Bag interface {
IsEmpty() bool
Size() int
}
That makes sense to me, because you can't pass a Bag around and throw just anything in it. Knowing that something is a Bag isn't enough to know how to call Add() on it; you must know what type of Bag you're dealing with.
You could make the interface specific to the type, like IntBag, but since only one type is actually going to satisfy that interface, you might as well get rid of the interface and change the name of IntSlice to IntBag.
Basically that means giving up entirely on anything generic-like, and just creating a type with some methods that do what you want:
type IntBag []int
func (b *IntBag) Add(i int) {
*b = append(*b, i)
}
func (b IntBag) IsEmpty() bool {
return len(b) == 0
}
func (b IntBag) Size() int {
return len(b)
}
Update: Sometimes generics really would come in handy. It seems to me we're left choosing on a case-by-case basis what exactly is best for a given problem. With empty interfaces and reflection, you can get some generic-like behavior, but it tends to be ugly and you give up some compile-time type checking. Or you give up on generics and have some code-duplication. Or you just do it a totally different way.
I asked a question a few weeks ago about how I should use Go to handle problems that look to me like they need class hierarchies. The answer was basically that there is no general solution; it's all case-by-case. I think the same applies for generics: there are no generics in Go, and there's no general solution for translating generics-based solutions to Go.
There are many cases where you might use generics in another language but interfaces are perfectly adequate (or truly shine) in Go. Your example here is one where interfaces aren't really a proper replacement. See also: Go Vs. Generics.
I'm pretty well-versed with Go. Generics are a hotly-debated topic, and there is currently nothing analogous to Java generics or C++ templates. The convention at the moment is to implement a "generic" type with an empty interface and then wrap it with a specific type implementation that makes sure only elements of that type are used. Here's an example with container/list from the Go standard library.
http://play.golang.org/p/9w9H1EPHKR
package main
import (
"container/list"
"fmt"
)
type IntList struct {
innerList *list.List
}
func NewIntList() *IntList {
return &IntList{list.New()}
}
func (l *IntList) Add(i int) {
// this is the only way to add an element to the list,
// and the Add() method only takes ints, so only ints
// can be added
l.innerList.PushBack(i)
}
func (l *IntList) Last() int {
lastElem := l.innerList.Back()
// We can safely type-assert to an int, because Add()
// guarantees that we can't put a non-int into our list
return lastElem.Value.(int)
}
func main() {
l := NewIntList()
l.Add(5)
l.Add(4)
l.Add(3)
l.Add(2)
l.Add(1)
fmt.Println("Expecting 1; got:", l.Last())
}

Resources