Sort with a function or method in Go? - sorting

The sort package provides these functions for sorting the builtin slice types:
sort.Ints(a []int)
sort.Float64s(a []float64)
sort.Strings(a []string)
It also provides these types for converting the builtin slice types to named types with Len(), Less(), Search(), Sort(), and Swap() methods:
sort.IntSlice
sort.Float64Slice
sort.StringSlice
That means I can sort a slice of ints like this...
// Function
slice := []int{5, 4, 3, 2, 1}
sort.Ints(slice) // sort in place
or like this...
// Method
slice := sort.IntSlice{5, 4, 3, 2, 1}
slice.Sort() // also sort in place
Is it preferable to sort with a function or a method? Are there times when one form should be preferred over the other?

The definition of sort.Ints(x) is literally sort.Sort(sort.IntSlice(x)) so it really doesn't matter. The former is shorter, so I'd use that.

Related

Do Go generics allow for a LINQ to Objects equivalent?

With the addition of generics in Go 1.18, would it now be possible to come up with an equivalent of C#'s LINQ to Objects?
Or are Go's generics lacking something in principle, compared to C# generics, that will make that difficult or impossible?
For example, the first of the original 101 LINQ samples ("LowNumbers") could now be implemented in Go with generics roughly like this:
package main
import (
"fmt"
)
type collection[T comparable] []T
func (input collection[T]) where(pred func(T) bool) collection[T] {
result := collection[T]{}
for _, j := range input {
if pred(j) {
result = append(result, j)
}
}
return result
}
func main() {
numbers := collection[int]{5, 4, 1, 3, 9, 8, 6, 7, 2, 0}
lowNums := numbers.where(func(i int) bool { return i < 5 })
fmt.Println("Numbers < 5:")
fmt.Println(lowNums)
}
Yes and no.
You can almost get there using a chained APIs.
This works for many of the standard LINQ methods, such as Skip, Take, Where, First, Last etc.
What doesn't work, is when you need to switch to another generic type within a flow/stream.
Go Generics does not allow methods to have other type argument than the interface/struct for which they are defined.
e.g. you cannot have a struct Foo[T any] that then has a method Bar[O any]
This is needed for methods like Select where you have one type for the input and another type for the output.
However, if you don't use chaining and just go for plain functions. then you can get pretty close functionality-wise.
I've done that here: https://github.com/asynkron/gofun
This is a fully lazy enumerable implementation by simulating co-routines.
What doesn't work here is functions like Zip which needs to enumerate two enumerables at the same time. (although there are ways to hack that. but nothing pretty)
(Disclaimer: I'm not a C# expert)
A conspicuous difference between Go's parametric polymorphism and the implementation of generics in C# or Java is that Go (still) has no syntax for co-/contra-variance over type parameters.
For example in C# you can have code that implements IComparer<T> and pass derived container classes; or in Java the typical Predicate<? super T> in the stream API. In Go, types must match exactly, and instantiating a generic type with different type parameters yields different named types that just can't be assigned to each other. See also: Why does Go not allow assigning one generic to another?
Also Go is not OO, so there's no concept of inheritance. You may have types that implement interfaces, and even parametrized interfaces. A contrived example:
type Equaler[T any] interface {
Equals(T) bool
}
type Vector []int32
func (v Vector) Equals(other Vector) bool {
// some logic
}
So with this code, Vector implements a specific instance of Equaler which is Equaler[Vector]. To be clear, the following var declaration compiles:
var _ Equaler[Vector] = Vector{}
So with this, you can write functions that are generic in T and use T to instantiate Equaler, and you will be able to pass anything that does implement that specific instance of Equaler:
func Remove[E Equaler[T], T any](es []E, v T) []E {
for i, e := range es {
if e.Equals(v) {
return append(es[:i], es[i+1:]...)
}
}
return es
}
And you can call this function with any T, and therefore with any T that has an Equals(T) method:
// some other random type that implements Equaler[T]
type MyString string
// implements Equaler[string]
func (s MyString) Equals(other string) bool {
return strings.Split(string(s), "-")[0] == other
}
func main() {
vecs := []Vector{{1, 2}, {3, 4, 5}, {6, 7}, {8}}
fmt.Println(Remove(vecs, Vector{6, 7}))
// prints [[1 2] [3 4 5] [8]]
strs := []MyString{"foo-bar", "hello-world", "bar-baz"}
fmt.Println(Remove(strs, "hello"))
// prints [foo-bar bar-baz]
}
The only problem is that only defined types can have methods, so this approach already excludes all composite non-named types.
However, to a partial rescue, Go has higher-order functions, so writing a stream-like API with that and non-named types is not impossible, e.g.:
func Where[C ~[]T, T any](collection C, predicate func(T) bool) (out C) {
for _, v := range collection {
if predicate(v) {
out = append(out, v)
}
}
return
}
func main() {
// vecs declared earlier
filtered := Where(vecs, func(v Vector) bool { return v[0] == 3})
fmt.Printf("%T %v", filtered, filtered)
// prints []main.Vector [[3 4 5]]
}
In particular here you use a named type parameter C ~[]T instead of just defining collection []T so that you can use it with both named and non-named types.
Code available in the playground: https://gotipplay.golang.org/p/mCM2TJ9qb3F
(Choosing the parametrized interfaces vs. higher-order functions probably depends on, among others, if you want to chain methods, but method chaining in Go isn't very common to begin with.)
Conclusion: whether that is enough to mimic LINQ- or Stream-like APIs, and/or enable large generic libraries, only practice will tell. The existing facilities are pretty powerful, and could become even more so in Go 1.19 after the language designers gain additional experience with real-world usage of generics.

Handle "Slice Struct" properly? (golang)

I have created a Slice Struct.
But why can't I append or output values?
package main
import "fmt"
type Slicestruct []struct {
num []int
emptynum []int
}
func main() {
slicestruct := &Slicestruct{
{[]int{1, 2, 3}, []int{}},
{[]int{4, 5, 6}, []int{}},
}
// is working:
fmt.Println(slicestruct)
// isn't working:
fmt.Println(slicestruct[0].num[0])
// isn't working:
slicestruct[0].emptynum = append(slicestruct[0].emptynum, 99)
}
The error message is: "invalid operation: slicestruct[0] (type *Slicestruct does not support indexing)"
You need to dereference the pointer before getting an element
(*slicestruct)[0]
Since it's the actual slice you're accessing an element from, not the pointer.
For pointers to arrays (not slices as you have here), this step would be done automatically.
Here's a related question about pointers to slices and arrays: Pointer to slice and array
Alternatively, you can remove the & when declaring your variable to make it not a pointer type. In the short sample we've seen here, there's nothing to necessitate a pointer. In general, legitimate uses of pointers to slices types are rare.

Any one can make sense of connStateInterface?

func (c *conn) setState(nc net.Conn, state ConnState) {
...
c.curState.Store(connStateInterface[state])
...
}
// connStateInterface is an array of the interface{} versions of
// ConnState values, so we can use them in atomic.Values later without
// paying the cost of shoving their integers in an interface{}.
var connStateInterface = [...]interface{}{
StateNew: StateNew,
StateActive: StateActive,
StateIdle: StateIdle,
StateHijacked: StateHijacked,
StateClosed: StateClosed,
}
I can't figure out the trick with connStateInterface, how exactly does it work?
There's a few things going on here...
The [...] declaration creates an actual array instead of a slice, so that indirection is removed. What's being declared here is an array of interface{} types... so you might wonder why the weird map-looking notation?
The StateXXX variables are simply constants declared further above, so they are ints... so the declaration is actually of the form index: value.
Here's a less obfuscated example of that using an array of ints:
var i = [...]int{4: 2, 2: 7}
This will allocate an array containing:
[0, 0, 7, 0, 2]
... note that index 2 has 7, index 4 has 2. Not a common way of declaring an array, but it's valid Go.
So going back to the original declaration, just take the example I gave above, and instead of int, make the array of type interface{}:
var i = [...]interface{}{4: 2, 2: 7}
And you'll get a similar array, but with nil interface values in place of zeroes.
Getting even closer to the original code, the StateXXX constants are just ints, only not literals like in my example.
So, what's the point of all this? Why all the obfuscation?
It's a performance hack. The function c.curState.Store() takes an argument of type interface{}. If you were to pass it an int, the compiled code would have to fumble about with converting the type on each call. A more clear (though obviously impractical) illustration of this might be:
var val interface{}
for i := 0; i < 1000000; i++ {
// the types are different, compiler has to fumble int vs. interface{}
val = i
// do something with val
}
Every time you do val = i a conversion between int and interface{} needs to happen. The code you posted avoids this by creating a static lookup table where all the values are already of type interface.
Therefore, this:
c.curState.Store(connStateInterface[state])
is more efficient than this:
c.curState.Store(state)
Since state would, in this case, need to undergo the int -> interface{} conversion. In the optimized code, state is merely an index looking up a value into an array, the result of which gets you an interface{}... so the int -> interface{} type conversion is avoided.
I'm not familiar with that code, but I'd imagine it's in a critical path and the nanoseconds or whatever savings shaved off likely makes a difference.

Is golang []interface{} cannot be function parameter? [duplicate]

This question already has answers here:
Type converting slices of interfaces
(9 answers)
Closed 7 years ago.
My code :
package sort_test
type SortList []interface{}
type SortFunc func(interface{}, interface{}) bool
func Do(list SortList, function SortFunc)
main package
package main
import (
"sort_test"
)
func main() {
list := []int{3, 4, 5, 6, 6, 77, 4, 4, 5, 6, 8, 345, 45, 424, 2, 67, 7, 830}
slice := list[:]
sort_test.Do(slice, function)
}
compile error
src/algorithm/algorithm.go:32: cannot use slice (type []int) as type sort_test.SortList in argument to sort_test.Do
src/algorithm/algorithm.go:32: cannot use function (type func(int, int) bool) as type sort_test.SortFunc in argument to sort_test.Do
make: *** [algorithm] Error 2
Cannot. Interface is interface.
interface{} is not some kind of "any" type.
But, any type implements interface{}. Interface is just a set of methods which should be implemented.
If you want to check whether the interface{} is slice or not, you can write it like this:
import "reflect"
t := reflect.TypeOf(list)
if t.Kind() == reflect.Slice {
...
}
I recommend you read this very helpful article: http://blog.golang.org/laws-of-reflection.
Additionally, it will be nice to read the code of sort package: https://golang.org/pkg/sort/. It is an example of golang-way implementation of sorting.
Edit: If you really really want use []interface{} as a parameter, actually you can do it like this:
vs := make([]interface{}, len(list))
for i, e := range list {
vs[i] = e
}
Do(vs, f)
In fact, []interface{} is not an empty interface. It's a slice type whose elements are interface{}; []int is not []interface{}, but just implements interface{}.
I guess you want to write some kind of a general sorting method, like you write it by using generics in Java. I think it is a bad code.
The errors are telling you that you are trying to pass an int array (the slice variable) to the function Do, which is expecting it's first argument as type SortList.
Also, your interface definition does not look right. You have array syntax in there. It should look like this:
type SortList interface{}
I suggest you take a look at the gobyexample page on interfaces.

Slice storage reference in Go

In the Go library source you often see that a slice is passed by creating a new slice storage reference like so
method(s[:])
What's the benefit of this, compared to just passing the original slice?
method(s)
The s[:] construct is normally used only to create a new slice referencing an existing array, not for "passing the original slice".
If s[:] is really used somewhere in the stdlib and s is a slice than it could be e.g. a refactoring leftover. Please report such place if known to you on the Go issue tracker.
The only case where you would see code like this is when s is an array, and you want to pass as a parameter to a function that takes a slice as its input. Take the following code.
package main
func main() {
x := [...]int{1, 2, 3, 4, 5}
someFunction(x) // type mismatch error : expecting [] int, passed [5] int
someFunction(x[:])// no error
}
func someFunction(input []int){
// use input
}
The thing to note here is that [] int and [5] int are entirely different types.

Resources