What is a good set of rules for a Golang Drinking Game?
-
I've come up with 16 so far: Take a drink when... You have to define a basic operation on a built-in data type yourself. e.g. membership test in a list or slice /* sort.Search() and friends only work on sorted slices; * it takes less (CPU and developer) time, * (RAM and developer) memory, and code than adding * boilerplate at each call site to make a copy, sort it, * and call sort.Search() */ func IntSliceHas(haystack []int, needle int) bool { for _, x := range haystack { if needle == x { return true } } return false } Every additional time you have to re-implement #1 for a new type. e.g. func StringSliceHas(haystack []string, needle string) bool { // exactly the same code as IntSliceHas: for _, x := range haystack { if needle == x { return true } } return false } You try to work around the lack of parametric polymorphism by making an awkward and/or needlessly verbose generic construct that operates on interface{}. Take another drink every time you need to write helpers or boilerplate to use the generic version. /* take a drink: replacing IntSliceHas and StringSliceHas * with SliceHas on interface{}s */ func SliceHas(haystack []interface{}, needle interface{}, equals func(interface{},interface{})bool) bool { for _, x := range haystack { if equals(x, needle) { return true } } return false } // take a drink: writing a helper function to support []int in SliceHas func BoxedIntsEqual(a, b interface{}) bool { aInt, aOk := a.(int) bInt, bOk := b.(int) return aOk && bOk && aInt == bInt } // ... // take a drink: boilerplate to convert an []int to []interface{}, // since []interface{}(items) and items.([]interface{}) don't work var boxedItems []interface{} for _, item := range items { boxedItems = append(boxedItems, item) } if SliceHas(boxedItems, itemOfInterest, BoxedIntsEqual) { // ... } Line continuations that use only one indent hurt readability or trip up auto-indentation in your editor. e.g. from the example to #2 func SliceHas(haystack []interface{}, needle interface{}, equals func(interface{}, interface{})bool) bool { // previous line uses same indentation as the body // ... } // auto indentation uses the same level as open bracket You use range values in the wrong order, or forget that the single-value range on lists and slices iterates over indices instead of values. e.g. values := []int{ 10, 20, 30 } fmt.Print("values:") for value, _ := range values { // wrong order; "value" is the index fmt.Printf(" %d", value) } fmt.Println() // prints "values: 0, 1, 2" e.g. values := []int{ 10, 20, 30 } // search for 0 in values (should not be found) hasZero := false for value := range values { if value == 0 { // will always be true on the first element hasZero = true } } You lament the fact that range can't be extended to support more containers, or vice-versa. You use a standard library function that defies Go's philosophy of avoiding in-band errors by returning multiple values. e.g. sort.Search() and friends return only one int which is -1 if the element is not found, instead of (int,bool) You use a map with dummy values because you need a set. The safety of Go's strong, static type system is undermined by interface{} (i.e. void* in a Groucho Marx disguise). e.g. every time you get a runtime panic due to a failed type assertion You have to use semantically meaningless dummy values in a return statement whose only meaningful return value is an error. e.g. func CreateFoo() (Foo, error) { if /* ... */ { return Foo{}, errors.New("you must construct additional pylons") } // ... } You or a coworker/peer ignores an error return value that could plausibly be non-nil. The compiler fails to warn you about unhandled cases after updating a struct. e.g. a newly-added field ends up as a zero-value because you've forgotten to initialize it type Node struct { Value interface{} Next *Node Context *NodeContext // newly added } // elsewhere: func MergeNodes(a, b Node, mergeValues func(interface{},interface{})interface{}) Node { return Node{ Value: mergeValues(a.Value, b.Value), Next: a.Next, // you forgot to update Context here } } // elsewhere: a := GetNode(foo, bar, baz) if b != nil { a = MergeNodes(a, b) } header := a.Context.Header // potentially dereferencing nil pointer You curse the lack of enums. e.g. because the compiler can't distinguish one set of const definitions from another of the same type const ( SIZE_SMALL = iota SIZE_MEDIUM SIZE_LARGE ) const ( COLOR_RED = iota COLOR_GREEN COLOR_BLUE ) foo.Size = COLOR_RED e.g. a newly-added "enum" is unaccounted for const ( DL_METHOD_HTTP = iota DL_METHOD_FTP DL_METHOD_SFTP DL_METHOD_RSYNC // newly added ) // elsewhere: switch (method) { case DL_METHOD_HTTP: // ... case DL_METHOD_FTP: // ... case DL_METHOD_SFTP: // ... // forgot to consider the new DL_METHOD_RSYNC case default: return nil, errors.New("invalid download method") } You have to go spelunking through Go docs or source code to discover the interfaces a type implements, or to determine whether it implements a particular interface, since none of this is ever specified except, maybe, in some comments. You are forced to let the machine's resources go to waste because you're unable to kill a resource-intensive goroutine. A package in the standard library cannot be used to accomplish something simple you'd expect any decent package to be capable of. e.g. net/http is weirdly global and makes it hard to stop and restart a server within the process' lifetime e.g. encoding/json gives no way to check for missing fields that could distinguish them from false negatives e.g. flags only handles the most simplistic argument parsing needs and forces a particular (non-GNU) style on you
-
Answer:
Sameer Ajmani at Quora Visit the source
Related Q & A:
- What's a good mobile phone plan for a study abroad student?Best solution by internationalstudentinsurance.com
- What is a good way to break in a snowboard?Best solution by answers.yahoo.com
- What is a good quality universal remote for a reasonable price?Best solution by thewirecutter.com
- What is a good score to get on a college placement test?Best solution by Yahoo! Answers
- What is a good thing to put on a job application when they ask whats the reason for leaving the position?Best solution by Yahoo! Answers
Just Added Q & A:
- How many active mobile subscribers are there in China?Best solution by Quora
- How to find the right vacation?Best solution by bookit.com
- How To Make Your Own Primer?Best solution by thekrazycouponlady.com
- How do you get the domain & range?Best solution by ChaCha
- How do you open pop up blockers?Best solution by Yahoo! Answers
For every problem there is a solution! Proved by Solucija.
-
Got an issue and looking for advice?
-
Ask Solucija to search every corner of the Web for help.
-
Get workable solutions and helpful tips in a moment.
Just ask Solucija about an issue you face and immediately get a list of ready solutions, answers and tips from other Internet users. We always provide the most suitable and complete answer to your question at the top, along with a few good alternatives below.