Polymorphism without methods in go - go

Note: I'm editing this question to a concrete example of why I want to do this, which is why some of the answers might no longer make sense in context.
I am writing a bit of code that passes data from an input. The data is in the form of tags that have an identifier of what kind of data they contain and then the data.
Unfortunately I have no control over the input and don't know in advance what tags will be in it, one might be an int another might be a string, yet another might be an array of ints.
The problem arises when I need to handle all tags like the same type, for instance if I have a slice of tags, of a function that either accepts or returns a tag.
The solutions I have so far seen to this is to define the slices/functions with an empty interface which would allow me to do so, however that is kinda undesirable as it would not tell anything to other people using the package about what types are expected and also kinda defies the point of having a typed language in the first place.
Interfaces does however seem to be the solution here, and i would love to have a Tag interface to pass around, that does require though that I define methods on them, and there are really no methods they need.
My current solution looks like this
type Tag interface{
implementTag()
}
type TagInt int
func (tag TagInt) implementTag() {}
type TagString string
func (tag TagInt) implementTag() {}
While this does indeed work and solves my problem, having to define dummy methods just for that feels very wrong.
So my question sums up in this: Are there any way that I can define that something is a Tag without having to define dummy methods?

And now want to make a slice that can hold both t1 and t2 but nothing else.
You cannot do that. Sorry.

What I would do in your scenario is accept any type in the parameters with an empty interface then use a type assertion inside to confirm that it's the type that you want.
if t1, ok := interfaceInput.(t1); !ok{
// handle it being the wrong type here
return
}
Also if you want the tight coupling between a data type and it's method, namely an object, what's so wrong with having it be a method of the object?

You can use []interface{} for a "slice of any type" but then it's up to you to use type assertions and/or type switches to discover the actual runtime types of that slice's members.
Learn more about empty interfaces in the Tour of Go
And now want to make a slice that can hold both t1 and t2 but nothing
else.
This is quite an unusual requirement and you're unlikely to need this in Go. But you could also do your own discriminated union with:
type item struct {
typeSelector int
t1Value t1
t2Value t2
}
And then use []item, checking typeSelector at runtime to see which value is populated.
Alternatively you could even use *t1 and *t2 and have nil signify "no value in this field".

Related

Structs with variations - idiomatic way to represent

What is the best idiomatic way to represent a struct which has variations for types ?
For example, say I have:
type A struct {
This []string
That int32
}
But I might also need to represent it as:
type A struct {
This string
That int32
}
Is there an idiomatic way to represent both variations with a single type ?
To me if your structure is able to accept a slice of This at any point in time then the first definition should always be the one you go for since a single item can be seen as a subset of a collection.
You could add functions to this structure to make it easier for the developers to interact with the structure though, but to me this looks fine as it is.

Initialize struct with global scope where type depends on boolean

I started using Golang recently and stumbled across a problem:
I have two structs, human and alien, which are both based on the creature struct. I want to initialize one of them based on the value of the isAlien boolean inside of an if-statement.
Using the human := human{} notation or the alien equivalent inside the if blocks to initialize, the instances aren't accessible from outside of the if-statement.
On the other hand, the usual solution of declaring the type and the name of the variable before the if-statement and initializing the variable inside the if-statement doesn't work, because there two are different types:
var h human //use human or alien here?
if isAlien {
h = alien{} //Error: incompatible types
} else {
h = human{}
}
//same when swapping human with alien at the declaration
I know that I could just declare both types before the if-statement but that solution doesn't seem elegant to me.
Is there some obvious solution that I'm missing here?
As you noted, the problem is clearly represented by this statement:
var h human //use human or alien here?
If you plan to use that h variable there after creating the objects, then the type of h must be one that can accept either a human or alien as a value.
The way to do this in Go is by using an ìnterface that both alien and human can fulfil.
So you should declare an interface like:
type subject interface {
// you should list all functions that you plan to use on "h" afterwards
// both "human" and "alien" must implement those functions
}
Then:
var h subject
Will do the trick.
So, I'm going to go out on a limb and say you're probably thinking about this the wrong way.
The first question that occurs to me looking at your example is: what's the return type of this function? In other words, what signature do you need h to be? If alien has an embedded struct creature (which seems to be the inheritance pattern you're trying to follow), and you return a human from your function after declaring h to be a creature, anything that consumes your function will only know that it's dealing with a creature, so there's no point in declaring it a human or an alien in the first place.
I suspect that what you really want to be doing is moving away from concrete structs here and instead using interfaces. In that world, you'd have a creature interface, and both human and alien would satisfy the creature interface. You wouldn't necessarily know which one you were dealing with downstream, but you'd be able to reliably call creature methods and the appropriate human or alien implementation would be invoked.

what should be used New() or var in go?

How a object should be created for a struct?
object := new(struct)
or
var object struct
I could not understatnd when to use what? and if both are same which one should be prefered?
The new syntax you're showing returns a pointer while the other one is a value. Check out this article here; https://golang.org/doc/effective_go.html#allocation_new
There's actually even one other option which I prefer. It's called composite literal and looks like this;
object := &struct{}
The example above is equivalent to your use of new. The cool thing about it is you can specify values for any property in struct within the brackets there.
When to use what is a decision you need to make on a case by case basis. In Go there are several reasons I would want one or the other; Perhaps only the pointer *myType implements some interface while myType does not, an instance myType could contain about 1 GB of data and you want to ensure you're passing a pointer and not the value to other methods, ect. The choice of which to use depends on the use case. Although I will say, pointers are rarely worse and because that's the case I almost always use them.
When you need a pointer object use new or composite literal else use var.
Use var whenever possible as this is more likely to be allocated in stack and memory get freed as soon as scope ends. I case of new memory gets allocated most likely in heap and need to be garbage collected.

using new vs. { } when initializing a struct in Go

So i know in go you can initialize a struct two different ways in GO. One of them is using the new keyword which returns a pointer to the struct in memory. Or you can use the { } to make a struct. My question is when is appropriate to use each?
Thanks
I prefer {} when the full value of the type is known and new() when the value is going to be populated incrementally.
In the former case, adding a new parameter may involve adding a new field initializer. In the latter it should probably be added to whatever code is composing the value.
Note that the &T{} syntax is only allowed when T is a struct, array, slice or map type.
Going off of what #Volker said, it's generally preferable to use &A{} for pointers (and this doesn't necessarily have to be zero values: if I have a struct with a single integer in it, I could do &A{1} to initialize the field). Besides being a stylistic concern, the big reason that people normally prefer this syntax is that, unlike new, it doesn't always actually allocate memory in the heap. If the go compiler can be sure that the pointer will never be used outside of the function, it will simply allocate the struct as a local variable, which is much more efficient than calling new.
Most people use A{} to create a zero value of type A, &A{} to create a pointer to a zero value of type A. Using newis only necessary for int and that like as int{} is a no go.

Go receiver methods calling syntax confusion

I was just reading through Effective Go and in the Pointers vs. Values section, near the end it says:
The rule about pointers vs. values for receivers is that value methods can be invoked on pointers and values, but pointer methods can only be invoked on pointers. This is because pointer methods can modify the receiver; invoking them on a copy of the value would cause those modifications to be discarded.
To test it, I wrote this:
package main
import (
"fmt"
"reflect"
)
type age int
func (a age) String() string {
return fmt.Sprintf("%d yeasr(s) old", int(a))
}
func (a *age) Set(newAge int) {
if newAge >= 0 {
*a = age(newAge)
}
}
func main() {
var vAge age = 5
pAge := new(age)
fmt.Printf("TypeOf =>\n\tvAge: %v\n\tpAge: %v\n", reflect.TypeOf(vAge),
reflect.TypeOf(pAge))
fmt.Printf("vAge.String(): %v\n", vAge.String())
fmt.Printf("vAge.Set(10)\n")
vAge.Set(10)
fmt.Printf("vAge.String(): %v\n", vAge.String())
fmt.Printf("pAge.String(): %v\n", pAge.String())
fmt.Printf("pAge.Set(10)\n")
pAge.Set(10)
fmt.Printf("pAge.String(): %v\n", pAge.String())
}
And it compiles, even though the document says it shouldn't since the pointer method Set() should not be invocable through the value var vAge. Am I doing something wrong here?
That's valid because vAge is addressable. See the last paragraph in Calls under the language spec:
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().
vAge is not considered as only a "value variable", because it's a known location in memory that stores a value of type age. Looking at vAge only as its value, vAge.Set(10) is not valid as an expression on its own, but because vAge is addressable, the spec declares that it's okay to treat the expression as shorthand for "get the address of vAge, and call Set on that" at compile-time, when we will be able to verify that Set is part of the method set for either age or *age. You're basically allowing the compiler to do a textual expansion on the original expression if it determines that it's necessary and possible.
Meanwhile, the compiler will allow you to call age(23).String() but not age(23).Set(10). In this case, we're working with a non-addressable value of type age. Since it's not valid to say &age(23), it can't be valid to say (&age(23)).Set(10); the compiler won't do that expansion.
Looking at the Effective Go example, you're not directly calling b.Write() at the scope where we know b's full type. You're instead making a temporary copy of b and trying to pass it off as a value of type interface io.Writer(). The problem is that the implementation of Printf doesn't know anything about the object being passed in except that it has promised it knows how to receive Write(), so it doesn't know to take a byteSlice and turn it into a *ByteSlice before calling the function. The decision of whether to address b has to happen at compile time, and PrintF was compiled with the precondition that its first argument would know how to receive Write() without being referenced.
You may think that if the system knows how to take an age pointer and convert it to an age value, that it should be able to do the reverse; t doesn't really make sense to be able to, though. In the Effective Go example, if you were to pass b instead of &b, you'd modify a slice that would no longer exist after PrintF returns, which is hardly useful. In my age example above, it literally makes no sense to take the value 23 and overwrite it with the value 10. In the first case, it makes sense for the compiler to stop and ask the programmer what she really meant to do when handing b off. In the latter case, it of course makes sense for the compiler to refuse to modify a constant value.
Furthermore, I don't think the system is dynamically extending age's method set to *age; my wild guess is that pointer types are statically given a method for each of the base type's methods, which just dereferences the pointer and calls the base's method. It's safe to do this automatically, as nothing in a receive-by-value method can change the pointer anyway. In the other direction, it doesn't always make sense to extend a set of methods that are asking to modify data by wrapping them in a way that the data they modify disappears shortly thereafter. There are definitely cases where it makes sense to do this, but this needs to be decided explicitly by the programmer, and it makes sense for the compiler to stop and ask for such.
tl;dr I think that the paragraph in Effective Go could use a bit of rewording (although I'm probably too long-winded to take the job), but it's correct. A pointer of type *X effectively has access to all of X's methods, but 'X' does not have access to *X's. Therefore, when determining whether an object can fulfill a given interface, *X is allowed to fulfill any interface X can, but the converse is not true. Furthermore, even though a variable of type X in scope is known to be addressable at compile-time--so the compiler can convert it to a *X--it will refuse to do so for the purposes of interface fulfillment because doing so may not make sense.

Resources