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]//Tmust be a channel typeisSendable[T type]//Tmust be a channel typeisSigned[T type]//Tmust be a numeric typeisVariadic[T type]//Tmust 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 theunderlyinghelper below)convertableTo[Tx, Ty type]assignableTo[Tx, Ty type]comparable[Tx, Ty type]implements[Tx, Ty type]//Tymust be an interface type.includes[Tx, Ty type]//Txhas all the fields ofTy.extends[Tx, Ty type]//Txhas 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//MandNare two constantsisUntyped[v const]
Maybe we can also represent identical[Tx, Ty type] as Tx == Ty.
comparable(vx, vy)// mainly for the cases of eithervxorvyis 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 ofTelement(T)// return the element type ofT,Tmust be an array, slice, map, channel typekey(T)// return the key type of mapTbase(T)// return the base type of pointerTfield(T.f)// return the field type of structTmethod(T.f)// return the method type ofTselector(T.f)//T.fis 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.