Operator > not defined for T - go

trying to check if a given number is less than the other or not, so wrote the below:
package main
import "fmt"
type T interface {}
func Less(i, j T) bool {
return i > j
}
But got the below error:
# command-line-arguments
.\hashmap.go:23:11: invalid operation: i > j (operator > not defined on interface)
How can I add such mathematical operations to general type element (number or string)?

interface is not a type, nor is it a generic value representing intersection of all types like string and int. When you ask for whether a is greater than or equal to b, you'll have to also specify which exact types those two belong (implicitly, they should have the same type), to answer that question. Similarly, Go also needs that information. Doing that for interface can be come a little cumbersome. However, there are a couple of ways:
Define the Less function individually on both types:
func LessString(n1, n2 string) bool {
return strings.Compare(n1, n2) == -1
}
// no need to define a less function, but whatever
func LessInt(n1, n2 int) bool {
return n1 < n2
}
Or, using type aliases:
type Name string
type Age int
func (name Name) Less(compare string) bool {
return strings.Compare(string(name), compare) == -1
}
func (age Age) LessInt(compare int) bool {
return int(age) < compare
}
A second way to implement Less functionality on interface would be to do type assertions:
// This isn't all that useful, but whatever
type T interface{}
func main() {
fmt.Println(Less(10, 20))
fmt.Println(Less("10", "20"))
}
func Less(t1, t2 T) bool {
switch v1 := t1.(type) {
case string:
return strings.Compare(v1, t2.(string)) < 0 // import "strings"
// return v1 < t2.(string)
case int:
return v1 < t2.(int)
}
return false
}
There is no way in Go to define operators over types. It prefers adding functions to achieve that. Many standard library modules follow similar patterns.

Related

sorting a GO struct by date which is defined via proto message

I have defined a message in proto file:
my.proto
--------
message Holiday {
string title = 1;
google.protobuf.Timestamp date = 2;
}
After compiling, it creates my.pb.go
Now in my go code, I have an slice of Holiday.
main.go
-------
holidays := []my.Holiday{...}
I have to sort this slice by Holiday.date. As per the doc if I want to sort using sort.Sort then I have to implement Len, Swap & Less method. But I cannot define these receiver method in my go code because Holiday is coming from the different package (my.pb.go).
Is there any way to sort this?
Thanks,
You could just use sort.Slice, which doesn't require implementing sort.Interface.
Slice sorts the slice x given the provided less function. It panics if x is not a slice.
sort.Slice(holidays, func(i, j int) bool {
return holidays[i].GetDate().Before(holidays[j].GetDate())
})
The SortKeys example in the sort.Sort documentation shows how to accomplish this by using an ad-hoc struct:
// A Planet defines the properties of a solar system object.
type Planet struct {
name string
mass earthMass
distance au
}
// By is the type of a "less" function that defines the ordering of its Planet arguments.
type By func(p1, p2 *Planet) bool
// Sort is a method on the function type, By, that sorts the argument slice according to the function.
func (by By) Sort(planets []Planet) {
ps := &planetSorter{
planets: planets,
by: by, // The Sort method's receiver is the function (closure) that defines the sort order.
}
sort.Sort(ps)
}
// planetSorter joins a By function and a slice of Planets to be sorted.
type planetSorter struct {
planets []Planet
by func(p1, p2 *Planet) bool // Closure used in the Less method.
}
// Len is part of sort.Interface.
func (s *planetSorter) Len() int {
return len(s.planets)
}
// Swap is part of sort.Interface.
func (s *planetSorter) Swap(i, j int) {
s.planets[i], s.planets[j] = s.planets[j], s.planets[i]
}
// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
func (s *planetSorter) Less(i, j int) bool {
return s.by(&s.planets[i], &s.planets[j])
}
Given that sort.Sort only takes a sort.Interface, it doesn't care about what data structure you are using or what type you are actually swapping.
The sort package documentation shows two examples that answer the question.
The first package example declares a slice type with the required methods:
type Person struct {
Name string
Age int
}
type ByAge []Person
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
...
sort.Sort(ByAge(people))
Notice that the Len, Swap and Less methods are on the slice type defined for sorting, not on the struct type. You can define that type in your own package.
The sort.Slice example shows how to sort with a less function only:
sort.Slice(people, func(i, j int) bool { return people[i].Name < people[j].Name })
In this example, there's no need to define types for the purpose of soring.

Building an interface

I wrote the below code that is working fine:
package main
import "fmt"
type hashMap interface {
}
type hashMap struct {
m map[hashable]hashable
k []hashable
}
type hashMap struct {
m map[T]T
k []T
}
// Methods required to enable sort: Len, Less, Swap > start
func (h *hashMap) Len() int {
return len(h.m)
}
func (h *hashMap) Less(i, j int) bool {
switch v := h.m[h.k[i]].(type) {
case int:
return v > h.m[h.k[j]].(int)
case float32:
return v > h.m[h.k[j]].(float32)
case float64:
return v > h.m[h.k[j]].(float64)
case string:
return v > h.m[h.k[j]].(string)
default:
return false
}
}
func (h *hashMap) Swap(i, j int) {
h.k[i], h.k[j] = h.k[j], h.k[i]
}
// Methods required to enable sort: Len, Less, Swap > end
// Build Ordered Map methods
func (h *hashMap) from(m map[T]T) hashMap {
h.m = m
h.k = make([]T, 0, len(m))
for key := range m {
h.k = append(h.k, key)
}
return *h
}
func main() {
inv := new(hashMap).from(map[T]T{"first:": 1, "second": 2})
fmt.Printf("%v", inv)
}
I would like to replace the empty interface type T interface {} using something like:
type T interface {
Len() int
Less() bool
Swap()
}
How can I do it?
You cannot do that in general.
Your hashMap contains a map[T]T. From https://golang.org/ref/spec#Map_types :
The comparison operators == and != must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice. If the key type is an interface type, these comparison operators must be defined for the dynamic key values; failure will cause a run-time panic.
(emphasis added).
So this works only if your implementation of T has == and != defined. As these operators are not userdefinable only the builtin/predeclared types which define them can be used. So the only types you can use as Ts are the one you can use as normal map keys anyway. So you gain nothing.
(But honestly I have no idea what your interface T is good for, especially given that you cannot use that interface for sorting; or what your code is trying to do. This looks like a XY problem.)

What's the reason for having methods outside the definition of the struct?

Why do we have the methods declared outside the type definition of the struct? E.g.:
type antenna struct {
name string
length float32
girth float32
bloodtype string
}
func (p *antenna) extend() {
p.length += 10
}
It seems to me that the method could be part of the struct? (Let's ignore for now that structs are supposed to be value types)
type antenna struct {
name string
length float32
girth float32
bloodtype string
func extend() {
length += 10
}
}
This would be more similar to traditional OOP. I didn't find any good explanations of why it is done the way it is besides "structs are value-types and classes are reference-types". I know the difference, but it's not a satisfactory answer to me. In any way the method has to be called like this:
var x = antenna()
x.extend()
So what's the point of separating the the struct and methods? Having them visually grouped together in the code - as in typical OOP languages - seems useful to me?
TLR: Code reuse, and Consistency.
1 - This enables to reuse methods:
This is the key design principle of the interface type in Go - let me make it more clear with an example: Consider you need to sort an slice of int (try it here):
a := []int{1, 3, 2, 5, 4}
sort.Ints(a) // sort.Sort(sort.IntSlice(a))
fmt.Println(a) // [1 2 3 4 5]
You simply call sort.Ints(a) which then calls Sort(IntSlice(a)) inside the standard library:
type IntSlice []int
func (x IntSlice) Len() int { return len(x) }
func (x IntSlice) Less(i, j int) bool { return x[i] < x[j] }
func (x IntSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
sort.IntSlice attaches the 3 methods of sort.Interface: Len, Less, and Swap to the type []int, to call:
// Sort sorts data in ascending order as determined by the Less method.
// It makes one call to data.Len to determine n and O(n*log(n)) calls to
// data.Less and data.Swap. The sort is not guaranteed to be stable.
func Sort(data Interface) {
n := data.Len()
quickSort(data, 0, n, maxDepth(n))
}
So you are able to reuse methods from the standard library, and you don't need to reimplement it again.
2- You may define your own types, See this example - There is no inside here for this named type - so methods must be outside of this type:
package main
import "fmt"
type num int32
func (p *num) inc() {
*p++
}
func main() {
p := num(100)
p.inc()
fmt.Println(p) // 101
}
The above named type num versus this user defined type: By design this makes the Go language consistent for both types:
type Animal struct {
Name string
moves []move.Direction
}
func (p *Animal) Walk(dir move.Direction) {
p.moves = append(p.moves, dir)
}
See also:
In Go is naming the receiver variable 'self' misleading or good practice?

How to avoid re-implementing sort.Interface for similar golang structs

There is one problem bothering me in Golang.
Say I have 2 structs:
type Dog struct {
Name string
Breed string
Age int
}
type Cat struct {
Name string
FavoriteFood string
Age int
}
And when I try to sort []*Dog and []*Cat by Age, I have to define 2 different sort struct like:
type SortCat []*Cat
func (c SortCat) Len() int {//..}
func (c SortCat) Swap(i, j int) {//..}
func (c SortCat) Less(i, j int) bool {//..}
type SortDog []*Dog
func (c SortDog) Len() int {//..}
func (c SortDog) Swap(i, j int) {//..}
func (c SortDog) Less(i, j int) bool {//..}
A natural thought is to implement some SortableByAge interface and create a Less function using the interface function. Like:
type SortableByAge interface {
AgeValue() int
}
And then:
type SortAnimal []SortableByAge
func (c SortDog) Less(i, j int) bool {
return c[i].AgeValue() < c[j].AgeValue()
}
However, according to:
http://golang.org/doc/faq#convert_slice_of_interface
dogs := make([]*Dogs, 0 , 1)
//add dogs here
sort.Sort(SortAnimal(dogs))
Above is not possible.
So I wonder what is the best practice for this case and
Is there any other technique that can reduce the need for implementing the sort.Interface for similar structs again and again that I have missed?
EDIT:
I realized that my examples are terrible :(
In real life case, these 2 structs are very different, the only thing in common between them is that I wish to sort them by a common numeric value.
A better example would be:
type Laptop {//...}
type Pizza {//...}
And the only thing these 2 structs share in common is that I wish to sort a slice(agh... should not have used Pizza in example) of them by price.
So, combining them to a common struct is not really working for a lot of cases.
But will look into go generate.
This Specific Case
In this specific case you shouldn't use 2 different types as they are identical, just use a common Animal type:
type Animal struct {
Name string
Age int
}
func (a Animal) String() string { return fmt.Sprintf("%s(%d)", a.Name, a.Age) }
type SortAnim []*Animal
func (c SortAnim) Len() int { return len(c) }
func (c SortAnim) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c SortAnim) Less(i, j int) bool { return c[i].Age < c[j].Age }
func main() {
dogs := []*Animal{&Animal{"Max", 4}, &Animal{"Buddy", 3}}
cats := []*Animal{&Animal{"Bella", 4}, &Animal{"Kitty", 3}}
fmt.Println(dogs)
sort.Sort(SortAnim(dogs))
fmt.Println(dogs)
fmt.Println(cats)
sort.Sort(SortAnim(cats))
fmt.Println(cats)
}
Output (Go Playground):
[Max(4) Buddy(3)]
[Buddy(3) Max(4)]
[Bella(4) Kitty(3)]
[Kitty(3) Bella(4)]
General Case
In general you can only use a common sorting implementation if you're willing to give up concrete types and use interface types instead.
Create the interface type you want your slice to hold:
type Animal interface {
Name() string
Age() int
}
You can have a common implementation of this:
type animal struct {
name string
age int
}
func (a *animal) Name() string { return a.name }
func (a *animal) Age() int { return a.age }
func (a animal) String() string { return fmt.Sprintf("%s(%d)", a.name, a.age) }
Your specific animal types:
type Dog struct {
animal // Embed animal (its methods and fields)
}
type Cat struct {
animal // Embed animal (its methods and fields)
}
You implement sort.Interface on SortAnim:
type SortAnim []Animal
func (c SortAnim) Len() int { return len(c) }
func (c SortAnim) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c SortAnim) Less(i, j int) bool { return c[i].Age() < c[j].Age() }
Using it:
dogs := SortAnim{&Dog{animal{"Max", 4}}, &Dog{animal{"Buddy", 3}}}
cats := SortAnim{&Cat{animal{"Bella", 4}}, &Cat{animal{"Kitty", 3}}}
fmt.Println(dogs)
sort.Sort(SortAnim(dogs))
fmt.Println(dogs)
fmt.Println(cats)
sort.Sort(SortAnim(cats))
fmt.Println(cats)
Output (Go Playground):
[Max(4) Buddy(3)]
[Buddy(3) Max(4)]
[Bella(4) Kitty(3)]
[Kitty(3) Bella(4)]
Note: as illustrated in commit ad26bb5, in Go 1.8 (Q1 2017), you won't have to implement Len() and Swap() and Less() since issue 16721 was resolved. Only Less() is needed, the rest is done by reflection.
The problem was:
Vast majority of sort.Interface uses a slice
Have to define a new top level type
Len and Swap methods are always the same
Want to make common case simpler with least hit to performance
See the new sort.go:
// Slice sorts the provided slice given the provided less function.
//
// The sort is not guaranteed to be stable. For a stable sort, use
// SliceStable.
//
// The function panics if the provided interface is not a slice.
func Slice(slice interface{}, less func(i, j int) bool) {
rv := reflect.ValueOf(slice)
swap := reflect.Swapper(slice)
length := rv.Len()
quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
}
So as long as you have a Less() function comparing two instances respecting an interface, you can sort any number of struct respecting said common interface.
Go 1.18 generics will add another option, as illustrated in nwillc/genfuncs/container/sort.go.
// Sort sorts a slice by the LessThan order.
func (s GSlice[T]) Sort(lessThan genfuncs.BiFunction[T, T, bool]) {
n := len(s)
s.quickSort(0, n, maxDepth(n), lessThan)
}
With BiFunction:
// BiFunction accepts two arguments and produces a result.
type BiFunction[T, U, R any] func(T, U) R
This is just an example illustrating how a generic sort could be implemented: it is not an official one (since generics are, at the ime of writing, Q1 2022, still very new).
The best practice for this case would be to define
type Animal struct{
Species,Name string
Age int
}
as suggested by twotwotwo. If cat and dog are similar enough to be sorted in the same way, they are also similar enough to be the same struct. If they are different in some way, then you should reimplement the interface for each type.
An alternative could be to copy all pointers from your []*Cat slice into a []SortableByAge slice of the same size. If you are going to sort the slice, that will take O(n*log(n)) so an extra O(n) shouldn't be a performance issue.
A third alternative, in the rare event that you have many types that for some reason have to be distinct but still have very simple sorting functions, you can look at autogenerating them with go generate.

Is there a way to avoid the implementation of the full sort.Interface for slices of structs?

If I have an array/slice of structs in Go and want to sort them using the sort package it seems to me that I need to implement the whole sort interface which contains 3 methods:
Len
Swap
Less
It seems that Len and Swap should always have the same implementation no matter the type of struct is in the array.
Is there a way to avoid having the implement Len and Swap every time or is this just a limitation from the lack of Generics in Go?
If you are implementing several different comparison operations on the same slice type, you can use embedding to avoid redefining Len and Swap each time. You can also use this technique to add parameters to the sort, for example to sort in reverse or not depending on some run-time value.
e.g.
package main
import (
"sort"
)
type T struct {
Foo int
Bar int
}
// TVector is our basic vector type.
type TVector []T
func (v TVector) Len() int {
return len(v)
}
func (v TVector) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
// default comparison.
func (v TVector) Less(i, j int) bool {
return v[i].Foo < v[j].Foo
}
// TVectorBarOrdered embeds TVector and overrides
// its Less method so that it is ordered by the Bar field.
type TVectorBarOrdered struct {
TVector
}
func (v TVectorBarOrdered) Less(i, j int) bool {
return v.TVector[i].Bar < v.TVector[j].Bar
}
// TVectorArbitraryOrdered sorts in normal or reversed
// order depending on the order of its Reversed field.
type TVectorArbitraryOrdered struct {
Reversed bool
TVector
}
func (v TVectorArbitraryOrdered) Less(i, j int) bool {
if v.Reversed {
i, j = j, i
}
return v.TVector[i].Foo < v.TVector[j].Foo
}
func main() {
v := []T{{1, 3}, {0, 6}, {3, 2}, {8, 7}}
sort.Sort(TVector(v))
sort.Sort(TVectorBarOrdered{v})
sort.Sort(TVectorArbitraryOrdered{true, v})
}
Your own answer is right. In your case of an array or slice the implementations of Len() and Swap() are simple. Like len() Go could provide a native swap() here. But the interface which is used now can also be used for more complex data structures like BTrees. It still allows the Sort() function to work (like my parallel quicksort, which uses the same sort interface).
If you want to sort slices (for which Len and Swap always have the same implementation), the sort package now has a function that only requires an implementation of Less:
func Slice(slice interface{}, less func(i, j int) bool)
Although this is an old question, I'd like to point out
the github.com/bradfitz/slice
package.
But as an example or proof of concept only, I would not recommend this actually be used (it's documented with the word "gross"):
It uses gross, low-level operations to make it easy to sort arbitrary slices with only a less function, without defining a new type with Len and Swap operations.
In actual code, I find it completely trivial, quick, short, readable, and non-distracting to just do something like:
type points []point
func (p []points) Len() int { return len(p) }
func (p []points) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p []points) Less(i, j int) bool {
// custom, often multi-line, comparison code here
}
Here gofmt insists on a blank line between the type and func lines
but it has no problem with
multiple one-line functions with no blank lines
and it nicely lines up the function bodies.
I find this a nice readable compact form for such things.
As for your comment that:
It seems that Len and Swap should always have the same implementation no matter the type of struct is in the [slice]
just the other week I need a sort that kept pairs of elements in a slice together (for input to strings.NewReplacer) that required a trivial variation like:
type pairByLen []string
func (p pairByLen) Len() int { return len(p) / 2 }
func (p pairByLen) Less(i, j int) bool { return len(p[i*2]) > len(p[j*2]) }
func (p pairByLen) Swap(i, j int) {
p[i*2], p[j*2] = p[j*2], p[i*2]
p[i*2+1], p[j*2+1] = p[j*2+1], p[i*2+1]
}
This is not supported by an interface like the one in github.com/bradfitz/slice.
Again, I find this layout easy, compact, and readable.
Although (perhaps more so in this case), others may disagree.

Resources