20 comments

[ 1.3 ms ] story [ 53.8 ms ] thread
I still don’t get contracts. Can someone explain it for the slow like me?
as I understand it (and I may be misunderstanding it), contracts are exactly like interfaces, except the type of parameters/return values is left to the implementation.

So an interface of "adder" would look like:

    type adder interface {
        Add(int) int
    }
and it would only be able to support adding an int to something, and returning an int. Doing this:

    func AddStrings(a adder, b string) string {
        return a.Add(b)
    }
will break

A contract for "adder" would look like:

    contract adder(T) {
        T Add (T) T
    }
You can then use this in a function by:

    func addTheThings(type T adder)(t1, t2 T) T {
        return t1.Add(t2)
    }
which can then use any type that has an Add method

    //can't extend native types, so we have to create an alias and extend that
    type Addstring string

    func (a Addstring)Add(b Addstring) Addstring {
        return a+b
    }

    func (a Banana)Add(b Banana) Banana {
        return Banana{a.Count + b.Count}
    }
then your "addTheThings" function can operate on strings (via the Addstring type) and Bananas, and anything else that fulfills the contract. So the original example:

    func AddStrings(a adder, b string) string {
        if as,ok := a.(Addstring); ok {
            return a.Add(b)
        }
        //raise an error here
    }
On a separate note, why is "contract" becoming a keyword instead of "type foo contract {}"? Making the common business concept of "contract" a keyword is likely to break backward compatibility for some code bases
> On a separate note, why is "contract" becoming a keyword instead of "type foo contract {}"?

I was wondering about this too. It also just feels really weird since it's a different construction than any of the other types.

Maybe the thinking is because a contract is not a type? But so what...

On first blush, it also feels weird that type is coming _before_ the type arguments, rather than after -- since types for normal arguments come after the argument.

E.g.,

    Map(T, U type)(t []T, f func(T) U) []U
feels much more consistent than

    Map(type T, U)(t []T, f func(T) U) []U
no? (Perhaps it complicates parsing, though?)
I think calling it a type would be confusing. It's not a type, it's a description of a behaviors of potential types.
"var n int" means "in this scope, declare variable n to be if type int".

"type T adder" means "in this scope, declare T to be a type adhering to the adder contract"

Good way to think of it.
They address backwards compatibility in the document. It will only be a keyword in certain contexts so that any valid go1 code will still be valid go2 code.
Well done. I understood that. Thank you.
The "no 0 value" part begs for type classes/traits, which for these Go contracts means not restricting contract functions to be methods.

  contract Zero(T) {
    Zero() T
  }
> We feel that more experience with this design is needed before deciding what, if anything, to do here.

Hopefully the more experience leads the Go designers to solutions some production-quality languages already have to solve this :)

I would already be more than happy if this proposal ends up in Go 2.

It looks quite sensible, and much better as the current //go: generate solution.

Why are these called "contracts"? It's just another generic type mechanism. "Contracts" are generally associated with entry and exit conditions for functions, and are not confined to single variables. A real contract looks like:

    func foo(a integer, b integer)
    {  entry(a>b); 
       ...
    }
Why not? They certainly define contracts for the type - at least that's my non-native speaker understanding of the english word.

It might seem weird if one used a different programming language which used the term for a slightly different concept - but that doesn't mean Go's usage is bad.

The concept is similar to what concepts are in C++ and traits in Rust. And from those terms I actually find contract to be the most understandable for people who are new to these things.

They want to avoid the term "generics" or "traits", same as how they avoided the word "exception" when they implemented "panic". golang likes to reinvent the wheel and call it something else just for the sake of it.
"When I use a word," Humpty Dumpty said, in rather a scornful tone, "it means just what I choose it to mean—neither more nor less." "The question is," said Alice, "whether you can make words mean so many different things." "The question is," said Humpty Dumpty, "which is to be master—that's all."