Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
List all potentially useful type constraints/contracts

This gist will list all potentially useful type constraints/contracts. Please ignore the syntax used in this gist. The syntax is just to make the desciption convenient. If you have interests on my Go proposal, please read this gist instead.

This gist can also be viewed as a contract proposal, which propose some built-in contracts, upon which we can build more complex contracts.

Basic constraints/contracts

There are about 20 built-in (basic) contracts.

Type property related constraints/contracts

  • isAny[T type] // not much useful, maybe it is not needed.
  • isDefined[T type]
  • isAlias[T type]
  • isNamed[T type]
  • isComparable[T type] // might be not essential, for it can be replaced with the following listed comparable[T, T]
  • isReceiveable[T type] // T must be a channel type
  • isSendable[T type] // T must be a channel type
  • isSigned[T type] // T must be a numeric type
  • isVariadic[T type] // T must be a function type

Type relation constraints/contracts

  • identical[T ...type]
  • aliasOf[Tx, Ty type] // might be not essential, for it can be splited into isAlias[Tx] + identical[Tx, Ty]
  • underlyingOf[Tx, Ty type]// might be not essential, for it can be replcaed with identical[Tx, underlying(Ty)]. (see the underlying helper below)
  • convertableTo[Tx, Ty type]
  • assignableTo[Tx, Ty type]
  • comparable[Tx, Ty type]
  • implements[Tx, Ty type] // Ty must be an interface type.
  • includes[Tx, Ty type] // Tx has all the fields of Ty.
  • extends[Tx, Ty type] // Tx has all the fields of Ty. Different to includes[Tx, Ty], methods will be treated as fields of function types.
  • sameKind[Ts ...type] // ex: sameKind[T, int], sameKind[T1, T2, T3]``sameKind[T, struct{}], sameKind[T, interface{}], sameKind[T, func()], sameKind[T, chan int], sameKind[T, *int], sameKind[T, []int], sameKind[T, [0]int], sameKind[T, map[int]int]

For better readibility, it may be better to add a basic contract for the latter 5 kinds in the sameKind examples: channelKind[T ...type], pointerKind[T ...type], sliceKind[T ...type], arrayKind[T ...type], mapKind[T ...type]. Or user ? to replace the int placeholders.

Constants related constraints/contracts

  • N cmp M // M and N are two constants
  • isUntyped[v const]

Maybe we can also represent identical[Tx, Ty type] as Tx == Ty.

Some helpers

  • comparable(vx, vy) // mainly for the cases of either vx or vy is an untyped value, to complement comparable[Tx, Ty type]
  • any() // return a type which denotes an any type. Or use ? to represent an any type.
  • typeOf(v) // return the type (or default type) of value v.
  • underlying(T) // return the underlying type of T
  • element(T) // return the element type of T, T must be an array, slice, map, channel type
  • key(T) // return the key type of map T
  • base(T) // return the base type of pointer T
  • field(T.f) // return the field type of struct T
  • method(T.f) // return the method type of T
  • selector(T.f) // T.f is either of a field (of a function type) or a method
  • input(T.n) // return the nth parameter type of a function type, n is an unsigned integer.
  • output(T.n) // return the nth result type of a function type, n is an unsigned integer.
  • numInputs(T) // return the number of parameters of a function type
  • numOutputs(T) // return the number of results of a function type
  • length(T) // return the length of an array type

Exntended/Custom Constraints/Contracts Examples

gen isInteger[T type] {
	assure sameKind[T, int8] || sameKind[T, uint8] || sameKind[T, int16] || sameKind[T, uint16] || 
	       sameKind[T, int32] || sameKind[T, uint32] || sameKind[T, int64] || sameKind[T, uint64] ||
		   sameKind[T, int] || sameKind[T, uint] || sameKind[T, uintptr]
}

gen isSignedInteger[T type] {
	assure isInteger[T]
	assure isSigned[T]
	
	// or: assure isInteger[T] && isSigned[T]
}

gen isUnsignedInteger[T type] {
	assure isInteger[T]
	assure !isSignedInteger[T]
	
	// or: assure isInteger[T] && !isSignedInteger[T]
}

gen isFloat[T type] {
	assure sameKind[T, float32] || sameKind[T, float64]
}

gen isComplex[T type] {
	assure sameKind[T, complex64] || sameKind[T, complex128]
}

gen isNumeric[T type] {
	assure isInteger[T] || isFloat[T] || isComplex[T]
}

gen isBasic[T type] {
	assure isNumeric[T] || sameKind[T, bool] || sameKind[T, string]
}

gen addable[T type] {
	assure isNumeric[T] || sameKind[T, string]
}

gen orderable[T type] {
	assure isNumeric[T] || sameKind[T, string]
	assure !isComplex[T]
}
gen isRectangle[Tr, Tn type] {
	assure isFloat[Tn]

	type rect struct {
		width, height Tn
	}

	assure extends[Tr, rect]
}
gen isShape2D[Ts, Tn type] {
	assure isFloat[Tn]

	type shape interface {
		Area() Tn
		SetScale(Tn)
	}

	assure implements[Ts, shape]
}
gen isChannelOfSignalChannel[Tc type] {
	assure sameKind[Tc, chan any()]
	type Te = element(Tc)
	assure sameKind[Te, chan any()]
	assure equal[element(Te), struct{}]
}
gen isStringArrayWithMinimumLength[A type, N const] {
	assure sameKind[A, [0]any()]
	assure sameKind[element(A), string]
	type Tn = typeOf(N)
	assure isInteger(Tn)
	assure length(A) >= N
}
gen convertableSlices[Tx, Ty type] {
	assure sameKind[Tx, []any()]
	assure sameKind[Ty, []any()]
	assure convertable[element(Tx), element(Ty)]
}

More thoughts

Conditional constraints

An example:

gen WeirdContract[Tx, Ty. Tz type] {
	type anySlice = []any()
	assure sameKind[Tx, anySlice] if sameKind[Ty, string]
	assure sameKind[Ty, anySlice] if sameKind[Tx, string]
	assure convertable[Tx, Tz] if convertable[Ty, Tz]
}

Maybe not elemental. The above one is equuvalent to the following one, thought the above one has a good readibility.

gen OneSliceOneString[Tx, Ty type] {
	assure sameKind[Tx, []any()]
	assure sameKind[Ty, string]
}

gen BothAreNotString[Tx, Ty type] {
	assure !sameKind[Tx, string]
	assure !sameKind[Ty, string]
}

gen BothConverableTo[Tx, Ty, Tz type] {
	assure convertable[Tx, Tz] if convertable[Ty, Tz]
}

gen WeirdContract[Tx, Ty. Tz type] {
	assure OneSliceOneString[Tx, Ty] || OneSliceOneString[Ty, Tx] || BothAreNotString[Tx, Ty]
	assure BothConverableTo[Tx, Ty, Tz] || !convertable[Ty, Tz]
}
@dotaheor
Copy link
Author

dotaheor commented Sep 7, 2018

Welcome anybody help me improve the list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment