Your pitch as I understand it, is to suggest that a generic type parameter T can be generic over a disjunction (ORing) of a finite (hopefully) set of (potentially unrelated) types, such as Float
and Double
. That's called a disjunctive type. It's to be contrasted with a conjunctive type, which is a conjunction (ANDing) of a finite set of potentially unrelated types, which can be spelt (for example) as Hashable & Comparable
in Swift.
Both conjunctive and disjunctive types only make sense in a generic context, when specifying the type of a parameter or return value of a function. They do not make sense as types themselves.
For example, to replace the use of GYB for stamping out Float
/Double
, (U)Int(|8|16|32|64)
couldn't be replaced as a hypothetical
struct Int | Int 8 | Int 16 | Int32 | Int64 | UInt | UInt8 | UInt16 | UInt32 | UInt64 { ... }
Because it would be rediculous to specify differing behaviour on a case basis.
func + (lhs: Self, rhs: Self) -> Self {
// I need to call 1 of 10 different LLVM built-ins, depending on the type of Self.
// How the hell do I specify that? something like this?
let t = true._getBuiltinLogicValue()
switch (lhs, rhs) {
case let (l as Int8, r as Int8):
return Builtin.uadd_with_overflow_Int8(l._value, r._value, t)
case let (l as Int16, r as Int16):
return Builtin.uadd_with_overflow_Int16(l._value, r._value, t)
case let (l as Int32, r as Int32):
return Builtin.uadd_with_overflow_Int32(l._value, r._value, t)
case let (l as Int64, r as Int64):
return Builtin.uadd_with_overflow_Int64(l._value, r._value, t)
case let (l as Int, r as Int):
return Builtin.uadd_with_overflow_Int64(l._value, r._value, t) //assuming Int = 64 bits
case let (l as UInt8, r as UInt8):
return Builtin.uadd_with_overflow_Int8(l._value, r._value, t)
case let (l as UInt16, r as UInt16):
return Builtin.uadd_with_overflow_Int16(l._value, r._value, t)
case let (l as UInt32, r as UInt32):
return Builtin.uadd_with_overflow_Int32(l._value, r._value, t)
case let (l as UInt64, r as UInt64):
return Builtin.uadd_with_overflow_Int64(l._value, r._value, t)
case let (l as UInt, r as UInt):
return Builtin.uadd_with_overflow_Int64(l._value, r._value, t) //assuming UInt = 64 bits
// Yuck!
}
}
Thus, even if disjoint types were available (at great complexity and speed costs, to the compiler), they wouldn't be particularly useful for solving the issues GYB addresses.