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.
There are about 20 built-in (basic) 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 listedcomparable[T, T]
isReceiveable[T type]
//T
must be a channel typeisSendable[T type]
//T
must be a channel typeisSigned[T type]
//T
must be a numeric typeisVariadic[T type]
//T
must be a function type
identical[T ...type]
aliasOf[Tx, Ty type]
// might be not essential, for it can be splited intoisAlias[Tx]
+identical[Tx, Ty]
underlyingOf[Tx, Ty type]
// might be not essential, for it can be replcaed withidentical[Tx, underlying(Ty)]
. (see theunderlying
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 ofTy
.extends[Tx, Ty type]
//Tx
has all the fields ofTy
. Different toincludes[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.
N cmp M
//M
andN
are two constantsisUntyped[v const]
Maybe we can also represent identical[Tx, Ty type]
as Tx == Ty
.
comparable(vx, vy)
// mainly for the cases of eithervx
orvy
is an untyped value, to complementcomparable[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 valuev
.underlying(T)
// return the underlying type ofT
element(T)
// return the element type ofT
,T
must be an array, slice, map, channel typekey(T)
// return the key type of mapT
base(T)
// return the base type of pointerT
field(T.f)
// return the field type of structT
method(T.f)
// return the method type ofT
selector(T.f)
//T.f
is either of a field (of a function type) or a methodinput(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 typenumOutputs(T)
// return the number of results of a function typelength(T)
// return the length of an array type
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)]
}
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]
}
Welcome anybody help me improve the list.