Correct way of handling an error when implementing Less() - go

I'm writing a sort function for a specific type. When writing the receiver "Less()" I call another function that might return an error. As Less() itself returns a bool what is the right way to handle this scenario? I don't want to panic, but I'd like to indicate that the attempt at sorting has failed, such that the function calling sort.Sort() can decide what to do with the error. However, sort.Sort() does not seem to return an error either so I'm guessing there is another way to go about this.
func (t MyType) Less(i, j int) bool {
retval, err := myOtherFunc(t[i])
// How do I handle err?
}

You can't; the closest solution would be to use sort.Slice instead, with a closure you can use to trap the error(s) in the outer scope:
errs := make([]error)
sort.Slice(mySlice, func(i, j int) bool {
retval, err := myOtherFunc(mySlice[i])
if err != nil {
errs = append(errs, err)
}
return retval
})
if len(errs) > 0 {
// do something about errors
}
This won't stop sorting at the first error (you can't), but it at least lets you collect them. The sort package is meant for typical sorting heuristics like alphabetical, numeric, or alpha/numeric on a struct field or the like; not for more complex processes with the possibility of failure.

Related

Can 'map' and 'reduce' be implemented in Go with generics

I decided that now that generics have been introduced into Go that something like map/reduce should be possible. So, I took a naive stab at it and I get the error:
./prog.go:18:36: cannot use thing (variable of type int) as type I in argument to mapper
Which doesn't explain if the problem is fundamental or I am simply doing something wrong syntactically. Can generic map/reduce be implemented in Go?
package main
import "fmt"
func main() {
things := []int{1, 2, 3, 4}
results := Map(things, func(t int) int {
return t + 1
})
fmt.Printf("%v", results)
}
func Map[I interface{}, O interface{}](things []I, mapper func(thing I) O) []O {
results := make([]O, 0, len(things))
for thing := range things {
results = append(results, mapper(thing))
}
return results
}
You have incorrect use of range. A single variable extracted from range will be the index (type int), not the value (type I, which is only coincidentally int in this case).
Try
for _, thing := range things{...}
This can be done quite easily. You have an error in your code, though right here:
for thing := range things {
You are iterating over the index values (int), not the values of type I. You're also specifying 2 constraints (types I and O) both set to be interface{}. You can just use any instead (it's shorthand for interface{})
So simply write:
func Map[T any, O any](things []T, mapper func(thing T) O) []O {
result := make([]O, 0, len(things))
for _, thing := range things {
result = append(result, mapper(thing))
}
return result
}
Demo
This is quite closely related to some code I reviewed on codereview exchange here. After going through the code, and writing snippets with a ton of suggestions, I decided to just create a package and throw it up on github instead. You can find the repo here.
In it, there's some examples that may come in handy, or help you work through some other quirks WRT generics in golang. I wsa specifically thinking about this bit, where you can filter a generic map type using callbacks like so:
// given the sMap type
type sMap[K comparable, V any] struct {
mu *sync.RWMutex
m map[K]V
}
// Filter returns a map containing the elements that matched the filter callback argument
func (s *sMap[K, V]) Filter(cb func(K, V) bool) map[K]V {
s.mu.RLock()
defer s.mu.RUnlock()
ret := make(map[K]V, len(s.m))
for k, v := range s.m {
if cb(k, v) {
ret[k] = v
}
}
return ret
}

Extracting Generic Struct Values by Reflection

I'm trying to extract all of the values for a struct into a string slice.
func structValues(item Item) []string {
values := []string{}
e := reflect.ValueOf(&item).Elem()
for i := 0; i < e.NumField(); i++ {
fieldValue := e.Field(i).Interface()
values = append(values, fmt.Sprintf("%#v", fieldValue))
}
return values
}
I'd like to use this function with any struct, so I thought I could just change the type signature to func structValues(item interface{}) but then I got a panic:
panic: reflect: call of reflect.Value.NumField on interface Value
Working example: https://repl.it/#fny/stackoverflow61719532
I'd like to use this function with any struct ...
You can do this, but note that it gives up type-safety. Moreover, the only way to do this is to allow a call with any type, not just any type that is some structure type, so you have to check that what you got was in fact some struct type:
func structValues(item interface{}) {
if reflect.ValueOf(item).Kind() != reflect.Struct {
... do something here ...
}
Having made that check—or deferring it slightly, or omitting it to allow reflect to panic instead—you then need to replace reflect.ValueOf(&item).Elem() with the simpler reflect.ValueOf(item).
If you wish to allow pointers to structures as well as actual structures, you can make that happen pretty simply by using reflect.Indirect first. The result is:
func structValues(item interface{}) []string {
e := reflect.Indirect(reflect.ValueOf(item))
if e.Kind() != reflect.Struct {
panic("not a struct")
}
values := []string{}
for i := 0; i < e.NumField(); i++ {
fieldValue := e.Field(i).Interface()
values = append(values, fmt.Sprintf("%#v", fieldValue))
}
return values
}
Leave out the reflect.Indirect if you want to make sure that callers do their own indirection when they have a pointer.
(Note that the panic here is not very friendly. If you want proper debugging, consider either just printing the struct directly with %v or %#v, or for something much more thorough, the spew package.)
Complete example here on the Go Playground uses your type Item struct from your own link.

Function types in Go - particular type casting to more general type

What cast / assertion need I do in Go in order to pass to a function expecting a generic function like func(interface{}) interface{}, a more specific function like func(int) int instead?
For example, in code like this, fooA can be passed to MakeExclamer, but not fooB:
func MakeExclamer(foo func (interface{}) interface{}, n int) func () {
return func() {
fmt.Printf("%v!!!", foo(n))
}
}
func fooA(x interface{}) interface{} {
return x.(int)*2
}
func fooB(x int) int {
return x * 10
}
func main() {
exclamerA := MakeExclamer(fooA, 12)
exclamerA()
exclamerB := MakeExclamer(fooB, 66)
// >> cannot use fooB (type func(int) int) as type func(interface {}) interface {} in argument to MakeExclamer
exclamerB()
}
(Go Playground link: https://play.golang.org/p/xGzfco0IAG)
I'm not interested much in alternative code structure patterns, since this is how I want it to work: a specific function should be passed to a general function transformer (accepting function of type Any -> Any) that will return another general function (Any -> Any). This may not be idiomatic in Go, but it is the pattern that I want my code to follow.
To use type assertions, every possible type must be enumerated in MakeExclamer:
func MakeExclamer(fn interface{}, arg interface{}) func() {
switch fn := fn.(type) {
case func(int) int:
return func() {
fmt.Printf("%v!!!\n", fn(arg.(int)))
}
case func(interface{}) interface{}:
return func() {
fmt.Printf("%v!!!\n", fn(arg))
}
default:
panic("not supported")
}
}
To accept a function of any type, the fn argument is declared as type interface{}. The code uses a type switch to handle the different function types.
playground example
Reflection can be used to write a more general function.
func MakeExclamer(fn interface{}, arg interface{}) func() {
fnr := reflect.ValueOf(fn)
argr := reflect.ValueOf(arg)
return func() {
resultr := fnr.Call([]reflect.Value{argr})
fmt.Printf("%v!!!\n", resultr[0].Interface())
}
}
playground example
First things first : When it comes to typing in Go, everything is theoretically possible. That's because even though the compiler does a lot of checks at compile-time, it is possible to change the runtime... at runtime. So-called runtime hacks, where you dynamically manipulate runtime structs that you're NOT supposed to handle.
Now, you have an interesting question, whose answer doesn't include the need to use the 'unsafe' package. However, the way I found of generalizing a function involves heavy reflection.
How to call a function (via reflection) ?
The documentation for the reflect package can be found here.
So, like all elements in Golang, functions have a Type. Without going through all fields, functions do take an array of arguments and produce an array of results. It is possible to investigate the Type of arguments and results through the In(int) and Out(int) method.
func investigate(fn interface{}) {
fnType := reflect.TypeOf(fn)
for idx := 0; idx < fnType.NumIn(); idx ++ {
fmt.Printf("Input arg %d has type %v\n", idx, fnType.In(idx))
}
for idx := 0; idx < fnType.NumOut(); idx ++ {
fmt.Printf("Output arg %d has type %v\n", idx, fnType.Out(idx))
}
}
We won't use this code. However, two important things are to be noted at this point :
The generic type under which a function can be passed around without caring about its type is interface{}. Something like "func(interface{}) interface{}" is not a generalization of a function, it is already a concrete type. Hence, "func(interface{}) interface{}" is not a generalization of "func(int) int", those are two different function types entirely. This is why you can't use type assertions/cast to convert from one function type to another.
A function can be represented as something that takes an input array and produces and output array.
Now, in order to call a function, you have to get not its Type, but its Value. Once you get its value, you can call it using an array of arguments, which must all be Values.
The prototype is:
func (v Value) Call(in []Value) []Value
Using this method, it is possible to call any function.
The code
So, the only thing you need is to convert whichever arguments array you have to an array of Values, then you will be able to call your function.
Here is your code:
package main
import (
"fmt"
"reflect"
)
func MakeExclamer(foo interface{}, n int) func() {
exclamer := generalize(foo, n)
return func() {
fmt.Printf("%v!!!\n", exclamer())
}
}
func fooA(x interface{}) interface{} {
return x.(int) * 2
}
func fooB(x int) int {
return x * 10
}
func generalize(implem interface{}, args ...interface{}) func() interface{} {
valIn := make([]reflect.Value, len(args), len(args))
fnVal := reflect.ValueOf(implem)
for idx, elt := range args {
valIn[idx] = reflect.ValueOf(elt)
}
ret := func() interface{} {
res := fnVal.Call(valIn)
// We assume the function produces exactly one result
return res[0].Interface()
}
return ret
}
func main() {
exclamerA := MakeExclamer(fooA, 12)
exclamerA()
exclamerB := MakeExclamer(fooB, 66)
exclamerB()
}
Playground
The important bit is the generalize function which makes the translation between your arguments and an array of Values, then returns a new function whith all parameters already filled.
Do not hesitate if you need any precision !

Should true or false terminate callback iteration?

In some languages it's necessary or cleaner to do iteration by providing a callback function that receives items and returns a boolean that indicates whether to continue or stop the iteration.
Which is the preferred value to indicate desire to stop/continue? Why? What precedents exist?
Example in Go:
func IntSliceEach(sl []int, cb func(i int) (more bool)) (all bool) {
for _, i := range sl {
if !cb(i) {
return false
}
}
return true
}
Which is the preferred value to indicate desire to stop/continue?
true for continue
Why?
Example 1:
func example(i interface{}) {
if w, ok := i.(io.Writer); ok {
// do something with your writer, ok indicates that you can continue
}
}
Example 2:
var sum int = 0
it := NewIntStatefulIterator(int_data)
for it.Next() {
sum += it.Value()
}
In both cases true (ok) indicates that you should continue. So I assume that it would be way to go in your example.
Foreword: The following answer applies to a callback function which decides based on the current item(s) whether the loop should terminate early - this is what you asked.
This is not to be confused with a function that progresses and reports if there are more elements to process, where a true return value is generally accepted to signal that there are more elements (for which a good example is Scanner.Scan()), and whose typical use is:
scanner := bufio.NewScanner(input)
for scanner.Scan() {
// Process current item (line):
line := scanner.Text()
fmt.Println(line) // Do something with line
}
Sticking to bool return type
Usually returning true to indicate termination results in code that is easier to read. This is due to the nature of for: if you do nothing, for continues, so you have to explicitly break if you want to terminate early, so having a clean termination condition is more common.
But it's a matter of taste. You may go whichever you like, but what's important is to name your callback function in a meaningful way that will clearly state what its return value means, and thus looking at the code (the condition in which it is used) will be easily understandable.
For example the following names are good and the return value is unambiguous:
// A return value of true means to terminate
func isLast(item Type) bool
func terminateAfter(item Type) bool
func abort(item Type) bool
// A return value of true means to continue (not to terminate)
func keepGoing(item Type) bool
func carryOn(item Type) bool
func processMore(item Type) bool
Using these results in easily understandable code:
for i, v := range vals {
doSomeWork()
if terminateAfter(v) {
break // or return
}
}
for i, v := range vals {
doSomeWork()
if !keepGoing(v) {
break // or return
}
}
// Or an alternative to the last one (subjective which is easier to read):
for i, v := range vals {
doSomeWork()
if keepGoing(v) {
continue
}
break
}
As negative examples, the following callback function names are bad as you can't guess what their return value mean:
// Bad: you can't tell what return value of true means just by its name:
func test(item Type) bool
func check(item Type) bool
Having error return type
It's also common for the callback to not just test but also do some work with the passed item. In these cases it is meaningful to return an error instead of a bool. Doing so, obviously the nil return value indicates success (and to continue), and a non-nil value indicates error and that processing should stop.
func process(item Type) error
for i, v := range vals {
if err := process(v); err != nil {
// Handle error and terminate
break
}
}
Having enum-like return value
Also if multiple return values have meaning, you may choose to define constants for return values, which you can name meaningfully.
type Action int
const (
ActionContinue Action = iota
ActionTerminate
ActionSkip
)
func actionToTake(item Type) Action
for i, v := range vals {
switch actionToTake(v) {
case ActionSkip:
continue
case ActionTerminate:
return
}
doSomeWork()
}

In Golang, can I assign slice values as return values?

I am attempting to develop a passthrough function for error checking where certain arguments are evaluated, and the rest are returned. But I would like these to be returned as multiple return values rather than a slice. Is there any way to do this in Go? Here's an example:
func Check(args ...interface{}) ...interface{} {
last := len(args) - 1
err := args[last]
// Check for an error in the last argument
if err != nil {
panic(err)
}
// Return any args returned by the function we're checking
return ...args[:last]
}
I know this isn't quite formated right in the function declaration. This is just for the sake of argument. I would ideally like to be able to return a variable number of values, which could then be received on the other side via assignment. This would allow for simple inline error checking when I want to use the standard err/panic idiom.
I know that I could return the slice instead and then assign it's parts to individual variables, or I could create multiple such functions (e.g. Check0, Check1, Check2, etc.), each having a distinct number or return values, but neither of these solutions is very elegant. Any ideas on how to make something like this work gracefully? Or is it just not possible at this stage of Go?
On a related note, does anyone know if there are any plans to make slices unpackable into variables, something like the following?
one, two, three := []string{"one", "two", "three"}
You can't do that, I don't think that's even planned, which is a good thing IMO.
Your option is doing something like this (this is ugly, and shouldn't be used):
func Check(args ...interface{}) []interface{} {
if err := args[len(args)-1]; err != nil {
//do suff with err
}
args = args[:len(args)-1]
return args
}
func Check2i(args ...interface{}) (int, int) {
return args[0].(int), args[1].(int)
}
func main() {
fmt.Println(Check(10, 20, 30, nil)...)
a, b := Check2i(Check(10, 20, nil)...)
_, _ = a, b
}

Resources