This proposal has been moved
It is unclear how to represent operators using interface methods. We considered syntaxes like +(T, T) T, but that is confusing and repetitive. Also, a minor point, but ==(T, T) bool does not correspond to the == operator, which returns an untyped boolean value, not bool. We also considered writing simply + or ==. That seems to work but unfortunately the semicolon insertion rules require writing a semicolon after each operator at the end of a line. Using contracts that look like functions gives us a familiar syntax at the cost of some repetition. These are not fatal problems, but they are difficulties.
Do these problems really justify creating an entirely new construct that has a very similar purpose to something we already have?
Is there really no other solution? We could do operator[<op>]
or something similar instead...
Some common interfaces people may be using
// Describes bool, complex, pointers, channels, interfaces,
// some structs, some arrays, strings, floats, and ints.
type Comparable interface {
operator[==]
operator[!=]
}
// describes strings, floats, ints
type Orderable interface {
Comparable
operator[<]
operator[>]
operator[<=]
operator[>=]
}
type Numeric interfacve
// describes floats and ints
type RealNumeric interface {
Comparable
operator[+]
operator[-]
operator[*]
operator[/]
operator[%]
}
// describes ints
type BinaryNumeric interface {
RealNumeric
operator[<<]
operator[>>]
operator[&]
operator[|]
operator[^]
operator[&^]
}
For a Graph
interface:
type Edge interface {
Nodes() (Node, Node)
}
type Node interface {
Edges() []EdgeInterface
}
type Graph(type N Node, E Edge) struct {
// ...
}
func (type N Node, E Edge) NewGraph(init []N) *Graph(N, E) {
// ....
}
For a Sum
method:
type Addable interface {
operator[+]
}
func (type T Addable) Sum(t ...T) {
var sum T
for _, elem := range t {
sum += elem // since + is defined for T, we may do this
}
return sum
}
func main() {
Sum(5, 6, 9) // returns 20
Sum("woah", "strings") // returns "woahstrings"
}
Doing this we could also redefine a lot of the things in builtin.go
type bool comparable
type complex64 comparable
type complex128 comparable
type string orderable
type float32 realnumeric
type float64 realnumeric
type int binarynumeric
type int8 binarynumeric
type int16 binarynumeric
type int32 binarynumeric
type int64 binarynumeric
type uint binarynumeric
type uint8 binarynumeric
type uint16 binarynumeric
type uint32 binarynumeric
type uint64 binarynumeric
type uintptr binarynumeric
type rune = int32
type byte = uint8
The only issue I can find now is that there is no way to generalize complex64
and complex128
,
or len
ables and cap
ables, etc.
You are able to do this with contracts using contract Complex(c C) { imag(c) }
, but there is no way to do this in Go.
But honestly, it might be best to just remove complex
, add operator functions, and create
a math/complex
package.
I think this proposal could be combined with this one, which uses pre-defined contracts for language primitives. Just make those contracts into special built-in interfaces. The compiler knows which operators are valid for a given interface, so there's no need to have any syntax for specifying them.