
The Updated Draft Design for Go 2 Contracts - saturn_vk
https://go.googlesource.com/proposal/+/4a54a00950b56dd0096482d0edae46969d7432a6/design/go2draft-contracts.md
======
Animats
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); 
           ...
        }

~~~
sseth
The terminology comes from a proposal for C++ which has been under discussion
for a long time.

~~~
detaro
C++ contracts are what Animats describes. Constraints and concepts are more
like what's described in the article:
[https://en.cppreference.com/w/cpp/language/constraints](https://en.cppreference.com/w/cpp/language/constraints)

~~~
Animats
"Contract" terminology is from Eiffel, from 1986.[1]

[1]
[https://en.wikipedia.org/wiki/Design_by_contract](https://en.wikipedia.org/wiki/Design_by_contract)

------
suddengunter
Contracts seems to me like Generic interfaces in C#. Why not just call this
thing "interface"
[https://gist.github.com/SuddenGunter/bb105556fde9678abbd97cb...](https://gist.github.com/SuddenGunter/bb105556fde9678abbd97cb890ed6b33)
instead of adding yet another keyword?

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

------
whateveracct
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 :)

------
gigatexal
I still don’t get contracts. Can someone explain it for the slow like me?

~~~
marcus_holmes
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

~~~
dilap
> 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?)

~~~
ithkuil
"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"

~~~
dilap
Good way to think of it.

