Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- This proposal is strictly about the contracts part of the generics proposal. It only describes a way to specify contracts using existing types, it does not add antyhing to the parameterized types discussion.
- # Types are contracts
- This is a parameterized function:
- ```
- func F(type T)(in T) T {
- }
- ```
- Structs and interfaces can also be parameterized:
- ```
- type listNode(type T) struct {
- payload T
- }
- type ListNode(type T) interface {
- GetPayload() T
- }
- ```
- Note: better syntax could be found for this
- Here T is a type. This information is not sufficient to compile the
- func, struct, and interface because nothing is know about T. To
- specify constraints on T, we add contracts.
- The idea of this proposal is to use existing types as a contract for
- T, as opposed to using an abstract contract syntax that describes
- operations and constraints on T.
- ```
- contract stringer interface {
- String() string
- }
- ```
- Here, the contract stringer is essentially an interface supporting
- String() function. A contract can also specify a struct:
- ```
- contract linkedListNode struct {
- next *linkedListNode
- }
- ```
- The above contract specifies that any type T satisfying the linked
- list contract must contain a member called 'next' of some type
- satisfying linkedListNode. A more restrictive form of this is:
- ```
- contract linkedListNode struct(type T linkedListNode) {
- next *T
- }
- ```
- This contract defines linkedListNode as any struct T containing a
- member 'next' of type T.
- ## Contracts with multiple types
- A contract can list multiple types. In that case, the concrete
- implementation must satisfy all types of the contract.
- ```
- contract linkedListNode {
- T struct {
- next *T
- }
- interface {
- GetNext() T
- }
- }
- ```
- This linkedListNode contract requires that the concrete type
- satisfying this contract must have a 'next' field pointing to the same
- struct type as well as a GetNext() T function.
- ## Mutually referential type parameters and parameterized contracts
- Since contracts are types, this is described in a way that's more
- go-like:
- Using interfaces only:
- ```
- package graph
- contract Node interface(type E Edge) {
- Edges() []E
- }
- contract Edge interface(type N Node) {
- Nodes() (N,N)
- }
- type Graph(type N Node, type E Edge) struct {
- nodes []N(E)
- }
- func New(type N Node,type E Edge)(nodes []N) *Graph(N,E) {
- }
- ```
- Above, Graph is a parameterized type with Node and Edge types that
- must satisfy the given contract. Since Node and Edge are contracts, we
- must define structs satisfying those contracts:
- ```
- type MyNode struct {
- edges []*MyEdge
- }
- func (m MyNode) Edges() []MyEdge {return m.edges}
- type MyEdge struct {
- from, to *MyNode
- }
- func (e MyEdge) Nodes() (*MyEdge,*MyEdge) {return e.from,e.to}
- func f() {
- var g:=graph.New(*MyNode,*MyEdge)(MyNode{...})
- }
- ```
- An alternative contract specification is:
- ```
- package graph
- contract Node(type E Edge) {
- struct {
- edges []*E
- }
- interface {
- GetEdges() []*E
- }
- }
- contract Edge(type N Node) {
- struct {
- from,to *N
- }
- interface {
- GetFrom() *N
- GetTo() *N
- }
- }
- contract Graph(type N Node,type E Edge) {
- struct {
- nodes []*N
- }
- }
- ```
- ## Contracts using primitive types and 'like' keyword
- Contracts can be defined in terms of primitive types:
- ```
- contract unsigned {
- like (byte, uint8, uint16, uint32, uint64, uint)
- }
- ```
- A type T satisfying the 'unsigned' contract can be any one of the
- listed types, or a type derived from any of those types.
- In general, "like (x,y,...)" within a contract definition implies that
- the contrete type satisfying the contract must be one of x, y,... or a
- type derived from those.
- This allows interesting contracts such as:
- ```
- contract numberStringer {
- like (byte,uint8, uint16,... <list all numeric types>)
- interface {
- String() string
- }
- }
- ```
- The above definition means that a concrete type T must be a type
- derived from the listed numeric types, and it must implement the
- String() string function.
- With this style of contract definition, the standard library can
- contain a library of common constraints such as integers, floats,
- unsigned, signed, etc.
- One problem this cannot address is == operator. This requires a
- built-in contract, something like "supportsEqual". Then we can also
- define:
- ```
- contract MapKey {
- supportsEqual
- }
- ```
- ## Examples from the proposal
- ### Sort
- This example defines an ordered contract, and such a contract can also be included in
- the library of predefined contracts as:
- ```
- contract Ordered {
- like(numeric types, string, ...)
- }
- ```
- ### Map keys
- MapKey would be a predefined contract defined using the "supportsEqual" builtin
- ### Sets
- Contract comparable in this example is the same this as supportsEqual builtin.
- ### Metrics
- ```
- contract Metric1 struct(type T MapKey) {
- sync.Mutex
- m map[T]int
- }
- func (m *M) Add(type M Metric1(T))(v T) {
- m.Lock()
- defer m.Unlock()
- if m.m==nil {
- m.m=make(map[T]int)
- }
- m[v]++
- }
- ```
- Above Metric1 is defined as a contract. Metric1 can also be defined as
- a parameterized struct, as done in the official proposal.
- ### List transform
- No changes to the official proposal version.
Add Comment
Please, Sign In to add comment