Sorry I couldn't figure out a more descriptive title for this. The integer generic parameters proposal motivated me to try some rudimentary metaprogramming.
I tried to implement something similar to C++'s std::conditional
like so (compiler explorer link).
// the static member `value` is inconsequential for now
protocol IntegerValue {
static var value: Int { get }
}
struct ZeroValue : IntegerValue {
static let value = 0
}
struct NonZeroValue : IntegerValue {
static let value = 1
}
// With Integer parameters, first parameter will let B: Int
struct If<B, Consequent, Alternative> {
}
extension If where B == NonZeroValue {
typealias T = Consequent
}
extension If where B == ZeroValue {
typealias T = Alternative
}
typealias cond = ZeroValue
typealias type1 = If<cond, Int, Float>.T
The last line results in an ambiguous type name error
<source>:22:40: error: ambiguous type name 'T' in 'If<cond, Int, Float>' (aka 'If<ZeroValue, Int, Float>')
typealias type1 = If<cond, Int, Float>.T
~~~~~~~~~~~~~~~~~~~~ ^
and includes a note
<source>:15:15: note: found candidate with type 'If<cond, Int, Float>.T' (aka 'Int')
typealias T = Consequent
^
But, this is the extension for NonZeroValue
, not ZeroValue
.
And, for some reason when I try to get a value directly instead of assigning to a typealias, e.g. let value = If<cond, Int, Float>.T()
, this compiles just fine (compiler explorer link).
I have the following questions
- Why is the extension with the formal parameter constraint
B == NonZeroValue
a candidate in the first place? Shouldn't it be discarded since the actual parameterB
isZeroValue
? - Why does this only happen when assigning the type to a typealias?