Building an interface - go

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.)

Related

Operator > not defined for T

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.

How do you use the heap package in Go?

I've been trying to use the Heap package in Go and I am not sure on how to initialize it.
package main
import "container/heap"
type PriorityMessage struct {
Priority int
Message string
}
func priorityQueue() {
//WOULD THIS not initialize the heap?
h := heap.Init(h PriorityMessage)
}
I've been trying to find examples online of how other's initialized their heaps and all of them seem to create their own versions of the Go heap package everytime. Would calling the heap.Init(h Interface) function from the heap package not work?
There is the heap.Interface what you should implement first.
type Interface interface {
sort.Interface
Push(x interface{}) // add x as element Len()
Pop() interface{} // remove and return element Len() - 1.
}
This means you should have the necessary methods for your PriorityMessage struct. After you pass the instance of the struct into the heap.Init(&pm).
You can find details in the godoc as linked in the comments.
Just to clarify the confusion. Go is a strongly typed language with lack of generics. So the heap package designed on the way that it's type independent. You can create your own implementation for all of the types what you want to implement. Any type implements the heap.Interface can be used by the heap package.
//https://cs.opensource.google/go/go/+/refs/tags/go1.16.6:src/container/heap/example_intheap_test.go
// This example demonstrates an integer heap built using the heap interface.
//package heap_test
import (
"container/heap"
"fmt"
)
// An IntHeap is a min-heap of ints.
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) {
// Push and Pop use pointer receivers because they modify the slice's length,
// not just its contents.
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
// This example inserts several ints into an IntHeap, checks the minimum,
// and removes them in order of priority.
func Example_intHeap() {
h := &IntHeap{2, 1, 5}
heap.Init(h)
heap.Push(h, 3)
fmt.Printf("minimum: %d\n", (*h)[0])
for h.Len() > 0 {
fmt.Printf("%d ", heap.Pop(h))
}
// Output:
// minimum: 1
// 1 2 3 5
}

A function that search for an interface{} over a slice of interface{} in Go

I'm trying to implement a function that takes an element of any type and a slice of the same type and search the first inside the second, giving it's position as result or -1 otherwise.
I'm not a Go expert, so my first thought was to pass the element to search as interface{} and the slice as []interface{}, but it didn't really work.
Here's what I tried:
package main
import (
"fmt"
)
func IsElementInListWithPos(element interface{}, list []interface{}) int {
for i := range list {
if list[i] == element {
return i
}
}
return -1
}
func main() {
list1 := []int{1, 2, 3, 4, 5, 6}
list2 := []string{"a", "b", "c", "d"}
pos1 := IsElementInListWithPos(3, list1)
pos2 := IsElementInListWithPos("a", list2)
fmt.Println(pos1, pos2)
}
It gives me the following errors:
cannot use list (type []int) as type []interface {} in argument to IsElementInListWithPos
cannot use list2 (type []string) as type []interface {} in argument to IsElementInListWithPos
Any idea how I could solve this issue without actually using two different functions?
Thanks in advance.
The sort package demonstrates how interfaces can be used to implement algorithms in a type-independent way.
Linear search requires two essential operations that depend on the haystack element type, Len and Equal. So we can write the following Haystack interface and a Search function that using it:
type Haystack interface {
Len() int
Equal(int, interface{}) bool
}
func Search(haystack Haystack, needle interface{}) int {
for i := 0; i < haystack.Len(); i++ {
if haystack.Equal(i, needle) {
return i
}
}
return -1
}
This makes writing implementations for Haystack simple, but not type-safe:
type Strings []string
func (s Strings) Len() int { return len(s) }
func (s Strings) Equal(i int, x interface{}) bool { return s[i] == x.(string) }
type Ints []int
func (s Ints) Len() int { return len(s) }
func (s Ints) Equal(i int, x interface{}) bool { return s[i] == x.(int) }
func main() {
strings := []string{"b", "a", "c", "d"}
fmt.Println(Search(Strings(strings), "c")) // 2
fmt.Println(Search(Strings(strings), "e")) // -1
ints := []int{2, 1, 3, 4}
fmt.Println(Search(Ints(ints), 3)) // 2
fmt.Println(Search(Ints(ints), 5)) // -1
}
Note the type assertions in the Equal methods. To make this type-safe we have to get rid of the interface{} argument to Equal:
type Haystack interface {
Len() int
Equal(int) bool
}
func Search(haystack Haystack) int {
for i := 0; i < haystack.Len(); i++ {
if haystack.Equal(i) {
return i
}
}
return -1
}
type Strings struct {
hs []string
needle string
}
func (s Strings) Len() int { return len(s.hs) }
func (s Strings) Equal(i int) bool { return s.hs[i] == s.needle }
type Ints struct {
hs []int
needle int
}
func (s Ints) Len() int { return len(s.hs) }
func (s Ints) Equal(i int) bool { return s.hs[i] == s.needle }
func main() {
strings := []string{"b", "a", "c", "d"}
fmt.Println(Search(Strings{strings, "c"})) // 2
fmt.Println(Search(Strings{strings, "e"})) // -1
ints := []int{2, 1, 3, 4}
fmt.Println(Search(Ints{ints, 3})) // 2
fmt.Println(Search(Ints{ints, 5})) // -1
}
This made both the interface implementations and using the Search function much more complicated.
The moral of the story is that using interfaces this way requires a sufficiently complicated algorithm to be worth the trouble. If writing the interface implementation for a particular type is more work than writing the concrete implementation for the algorithm, well, then just write the concrete functions you need:
func SearchStr(haystack []string, needle string) int {
for i, x := range haystack {
if x == needle {
return i
}
}
return -1
}
func SearchInt(haystack []int, needle int) int {
for i, x := range haystack {
if x == needle {
return i
}
}
return -1
}
func main() {
strings := []string{"b", "a", "c", "d"}
fmt.Println(SearchStr(strings, "c")) // 2
fmt.Println(SearchStr(strings, "e")) // -1
ints := []int{2, 1, 3, 4}
fmt.Println(SearchInt(ints, 3)) // 2
fmt.Println(SearchInt(ints, 5)) // -1
}
Currently, it is not possible to build a solution that respects all your criteria. It will be possible once generics are implemented. Or you could try building one using reflect, but that will yield a complex and potentially slow solution... so I generally advise against using reflect for something as simple as this (see second snippet below).
What you can do right now is to use something like:
func FindFirst(n int, f func(int) bool) int {
for i := 0; i < n; i++ {
if f(i) {
return i
}
}
return -1
}
// in your code (s is the slice, e the value you are searching for)
i := FindFirst(len(s), func(i int) bool {
return s[i] == e
})
if i != -1 {
// i is the index of the element with value e
}
This, as you can imagine, does not make much sense... as it's arguably simpler, faster, and more idiomatic to simply write out the loop explicitly:
// in your code (s is the slice, e the value you are searching for)
for i, v := range s {
if v == e {
_ = i // i is the index of the element with value e
break
}
}
Obviously, this whole approach (linear scan) is only reasonable if the number of elements in the slice is small. If your slice is big and changes rarely, it would arguably make more sense (from a time complexity perspective) to sort it (sort.Slice) first and then do binary searches (sort.Search) on the sorted slice. Or, alternatively, you could use a map instead: in which case (assuming keys are small) lookup would be O(1).

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?

Idiomatic way of implementing nested matrices in golang

I am trying to represent a hypergraph in memory. Are there any better data structures for this task beside nested matrices? A nested matrix is a matrix which can have elements of both the "native" type (let's say int for the sake of simplicity) and matrices.
This is the beginning of such a matrix. Are there any rough edges in the code, to make it look more idiomatic? How to make it look more idiomatic?
The code:
package main
import "fmt"
type Matricial interface {
Put(interface{}, ...int)
Get(...int) interface{}
}
type Matrix struct {
Matricial
values map[int]interface{}
}
func NewMatrix() *Matrix {
m := &Matrix{}
m.values = make(map[int]interface{})
return m
}
func (m *Matrix) Set(atom interface{}, pos ...int) {
firstdim := pos[0]
if val, ok := m.values[firstdim]; ok {
fmt.Println("map key exists", val)
switch converted := val.(type) {
case int:
m.values[firstdim] = converted
default:
fmt.Println("ERR: unknown type: %T", val)
}
} else {
if len(pos[1:]) > 0 {
newm := NewMatrix()
m.values[firstdim] = newm
newm.Set(atom, pos[1:]...)
} else {
m.values[firstdim] = atom
}
}
}
func (m *Matrix) Get(pos ...int) interface{} {
if len(pos) == 1 {
return m.values[pos[0]]
} else {
switch accessor := m.values[pos[0]].(type) {
case Matricial:
return accessor.Get(pos[1:]...)
default:
return nil
}
}
return nil
}
func main() {
m := NewMatrix()
m.Set(42, 2, 3, 4)
m.Set(43, 0)
fmt.Println(m.Get(2, 3))
fmt.Println(m.Get(2, 3, 4))
fmt.Println(m.Get(0))
}
The data structure must allow connecting hyperedges with other hyperedges (i.e. handling hyperedges as though they were nodes).
A nested matrix (adopting your definition of the term) seems a reasonable representation for hypergraph, not knowing anything more about your application anyway. An example Go implementation is the power set example at Rosetta code.
It is not idiomatic to embed an interface. For example, if you rename the Put method of Matricial to be Set, which is what I think you meant, then you can just delete the Matricial field of Matrix and your program produces the same output.

Resources