In go language, may I define allowed values of a string in a struct and/or force creation only via constructor? Or avoid direct creation of a struct? [duplicate] - go

This question already has answers here:
Creating a Constant Type and Restricting the Type's Values
(2 answers)
What is an idiomatic way of representing enums in Go?
(14 answers)
Closed 8 months ago.
I have a struct Direction with a value of type string. Direction should be N, S, W or E.
type Direction struct {
value string
}
Inspired by an answer of this question: Does Go have "if x in" construct similar to Python? I guess a good way to create Direction in a valid manner can be this one:
func NewDirection(direction string) Direction {
switch direction {
case "N","S","W","E": return Direction{direction}
}
panic("invalid direction")
}
But this is not enough for me because I can still create invalid Direction:
d := Direction{"X"}
I also found this interesting article about enforcing the use of constructor in go. Reading this article I can see that is necessary the usage of another package. May I have a "protected" struct in, for example, main package?

You've already done almost everything you should do by convention:
make the field unexported
provide a constructor
put a comment on the type stating that the constructor should be used, and explain how zero-values are treated (if that matters)
Now users of the package can't modify the field, and the existence of the constrictor makes it clear that it should be called to create valid instances. This is the convention that is set by the standard library.
Sure, there are other ways that you can make it even harder to invalidate values but this is essentially just wasting time and overcomplicating your code for the sake of an unwinnable arms race against an imaginary opponent.
If someone doesn't understand the language and doesn't read documentation, then they're always going to find a way to misuse it. If they are actively trying to sabotage themselves, there's nothing you can do to stop them and no reason to either.
Packages are the smallest functional unit of code organization in Go. There is no way to protect field at, for example, the file level. Even files within the same package effectively operate as if all their code was in the same file. Therefore, any code in the same package as the constructor will have the same privileges as the constructor.

Related

What's the difference between generic and non-generic use of interfaces? [duplicate]

This question already has answers here:
What are the benefits of replacing an interface argument with a type parameter?
(2 answers)
Closed 8 months ago.
In the new Type Parameters Design Draft, you can now apply an interface constraint to a generic function:
func prettyPrint[T Stringer](s T) string {
...
}
But, this was already possible by using an interface parameter without generics:
func prettyPrint(s Stringer) string {
...
}
What's the difference between using the first and using the second?
I assume the question refers to the latest draft of the Type Parameters proposal, which may end up in Go in 1.18.
The first is parametric polymorphism. The compiler verifies that the constraint is satisfied, and then generates code that takes a statically-known type. Importantly, it's not boxed.
The second is runtime polymorphism. It takes a type that's unknown at compile time (the only thing known is that it implements the interface) and works on a boxed interface pointer.
Performance considerations aside, in this simple case you can use either approach. Generics really help with the more complicated cases where the current tools don't work well.

How do you implement a container for different types in Go? [duplicate]

This question already has answers here:
Any type and implementing generic list in go programming language
(2 answers)
Generic Structs with Go
(1 answer)
Closed 5 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
The following code implements a List of ints in Go:
package main
import "fmt"
type List struct {
Head int
Tail *List
}
func tail(list List) *List {
return list.Tail
}
func main() {
list := List{Head: 1, Tail:
&List{Head: 2, Tail:
&List{Head: 3, Tail:
nil}}}
fmt.Println(tail(list).Head)
}
Problem is this only works for int. If I wanted a list of strings, I'd need to re-implement every list method (such as tail) again! That's obviously not practical, so, this can be solved by using an empty interface:
type List struct {
Head interface{} // Now works for any type!
Tail *List
}
Problem is, 1. this seems to be much slower because of type casts, 2. it throws aways type safety, allowing one to type-check anything:
// This type-checks!
func main() {
list := List{Head: 123456789 , Tail:
&List{Head: "covfefe" , Tail:
&List{Head: nil , Tail:
&List{Head: []int{1,2}, Tail:
nil}}}}
fmt.Println(tail(list).Head)
Obviously that program should not type-check in a statically typed language.
How can I implement a List type which doesn't require me to re-implement all List methods for each contained type, but which keeps the expected type safety and performance?
Go doesn't have generic types, so you're stuck with the options you listed. Sorry.
Meanwhile, Go's built-in maps and slices, plus the ability to use the empty interface to construct containers (with explicit unboxing) mean in many cases it is possible to write code that does what generics would enable, if less smoothly.
If you know more about the elements you want to store in the container, you may use a more specialized interface type (instead of the empty interface interface{}), which
could help you avoid using type assertions (keep good performance)
and still keep type safety
and it can be used for all types that (implicitly) implement your interface (code "re-usability", no need to duplicate for multiple types).
But that's about it. See an example of this here: Why are interfaces needed in Golang?
Also just in case you missed it, the standard library already has a doubly linked list implementation in the container/list package (which also uses interface{} type for the values).
It's important to acknowledge that we expect generic types to be slower, not faster. The excellent fastutil library for Java outperforms the more flexible classes from the standard library by using concrete implementations.
Russ Cox (one of Go's authors) summarises the situation like this:
(The C approach.) Leave them out.
This slows programmers.
(The C++ approach.) Compile-time specialization or macro expansion.
This slows compilation.
(The Java approach.) Box everything implicitly.
This slows execution.
You may be interested in this living document which has a lot of the pros and cons outlined.
As the other answer points out, Go does not support the design you're trying to achieve here. Personally, I'd just duplicate the code - it's not much, the tests are cheap, and most of the time you don't actually need the generic behaviour you want to implement.

Variable declaration shortcut outside of function [duplicate]

This question already has answers here:
Why isn't short variable declaration allowed at package level in Go?
(3 answers)
Closed 8 years ago.
Coming from a background in Java and C# I am very pleased with the brevity of Golang's ability to use the shortcut method for variable declaration for private variables within functions, which allows me to write:
x := 1.5
It reminds me of duck typing in a dynamic language such as Python. However, in declaring global variables outside of the scope of a function you still need to use the more verbose syntax of:
var x float64 = 1.5
I'm just wondering why the shortcut method works for private variables and not globals? I know that the designers of the language are quite experienced so I'm assuming that this isn't reflective of a feature overlooked. Is there a technical reason why this kind of type inference (and I realize that the := shortcut is not the same as proper type inference) wouldn't work at the global scope? It just seems somewhat inconsistent in terms of the design, and as an inexperienced Gopher I must admit to being thrown off by this on a couple of occasions. On the whole however I'm really enjoying Go.
See the Ian's answer in this thread:
https://groups.google.com/forum/#!msg/golang-nuts/qTZemuGDV6o/IyCwXPJsUFIJ
At the top level, every declaration begins with a keyword. This
simplifies parsing.
Actually you don't need to specify type in many cases.
var x = 1.5
should work fine. It's probably as short as it can get and it's not much longer than local variable shortcut.
So there is a shortcut for global.
As to why := can't be used, I would guess that calling out var makes code structure more consistent as other global constructs start with a keyword - func, const, import, type.

By reference or value

if i had an instance of the following struct
type Node struct {
id string
name string
address string
conn net.Conn
enc json.Encoder
dec json.Decoder
in chan *Command
out chan *Command
clients map[string]ClientNodesContainer
}
i am failing to understand when i should send a struct by reference and when should i send it by value(considering that i do not want to make any changes to that instance), is there a rule of thumb that makes it easier to decide?
all i could find is send a struct by value when its small or inexpensive to copy, but does small really mean smaller than 64bit address for example?
would be glad if someone can point some more obvious rules
The rule is very simple:
There is no concept of "pass/send by reference" in Go, all you can do is pass by value.
Regarding the question whether to pass the value of your struct or a pointer to your struct (this is not call by reference!):
If you want to modify the value inside the function or method: Pass a pointer.
If you do not want to modify the value:
If your struct is large: Use pointer.
Otherwise: It just doesn't matter.
All this thinking about how much a copy costs you is wasted time. Copies are cheap, even for medium sized structs. Passing a pointer might be a suitable optimization after profiling.
Your struct is not large. A large struct contains fields like wholeWorldBuf [1000000]uint64.
Tiny structs like yours might or might not benefit from passing a pointer and anybody who gives advice which one is better is lying: It all depends on your code and call patterns.
If you run out of sensible options and profiling shows that time is spent copying your structs: Experiment with pointers.
The principle of "usually pass values for small structs you don't intend to mutate" I agree with, but this struct, right now, is 688 bytes on x64, most of those in the embedded json structs. The breakdown is:
16*4=64 for the three strings (pointer/len pairs) and the net.Conn (an interface value)
208 for the embedded json.Encoder
392 for the embedded json.Decoder
8*3=24 for the three chan/map values (must be pointers)
Here's the code I used to get that, though you need to save it locally to run it because it uses unsafe.Sizeof.
You could embed *Encoder/*Decoder instead of pointers, leaving you at 104 bytes. I think it's reasonable to keep as-is and pass *Nodes around, though.
The Go code review comments on receiver type say "How large is large? Assume it's equivalent to passing all its elements as arguments to the method. If that feels too large, it's also too large for the receiver." There is room for differences of opinion here, but for me, nine values, some multiple words, "feels large" even before getting precise numbers.
In the "Pass Values" section the review comments doc says "This advice does not apply to large structs, or even small structs that might grow." It doesn't say that the same standard for "large" applies to normal parameters as to receivers, but I think that's a reasonable approach.
Part of the subtlety of determining largeness, alluded to in the code review doc, is that many things in Go are internally pointers or small, reference-containing structs: slices (but not fixed-size arrays), strings, interface values, function values, channels, maps. Your struct may own a []byte pointing to a 64KB buffer, or a big struct via an interface, but still be cheap to copy. I wrote some about this in another answer, but nothing I said there prevents one from having to make some less-than-scientific judgement calls.
It's interesting to see what standard library methods do. bytes.Replace has ten words' worth of args, so that's at least sometimes OK to copy onto the stack. On the other hand go/ast tends to pass around references (either * pointers or interface values) even for non-mutating methods on its not-huge structs. Conclusion: it can be hard to reduce it to a couple simple rules. :)
Most of the time you should use passing by reference. Like:
func (n *Node) exampleFunc() {
...
}
Only situation when you would like to use passing instance by value is when you would like to be sure that your instance is safe from changes.

Getting a reflect.Type from a name

If I have a name of a type (i.e "container/vector"), is there a way to lookup the reflect.Type that has the given name? I'm trying to write a simple database-backed workqueue system and this it would be very difficult without this feature.
I can't see how this would be possible in any trivial way (or at all), since name resolution is part of the compiler/linker, not the runtime.
However, http://github.com/nsf/gocode might offer up some ideas. Though I'm pretty sure that works by processing the .a files in $GOROOT, so I still don't see how you'd get the reflect.Type. Maybe if the exp/eval package was more mature?
Of course if you know all the possible types you'll encounter, you could always make a map of the reflect.Type. But I'm assuming you're working with unpredictable input, or you would've thought of that.
Only way to create a reflect.Type is by having a concrete value of the intended type first. You can't even create composite-types, such as a slice ([]T), from a base type (T).
The only way to go from a string to a reflect.Type is by entering the mapping yourself.
mapping := map[string]reflect.Type {
"string": reflect.Typeof(""),
"container/vector": reflect.Typeof(new(vector.Vector)),
/* ... */
}

Resources