You may want to remove the semicolon in the following example from your proposal:
func f2(i: Int) -> opaque P { // okay: both returns produce Int
if i > 10 { return i }
return 0; // <-- here
}
In the following example there is a missing }
:
func f7(_ i: Int) -> opaque P {
if i == 0 {
return f7(1) // okay: returning the opaque result type of f(), similar to f5()
/* here */ else if i < 0 {
let result: Int = f7(-i) // error: opaque result type of f() is not convertible to Int
return result
} else {
return 0
}
}
@Douglas_Gregor I understand that the top recursion is invalid because we want to store the opaque result into a constant and by the rules of opaque types the static type system does not know the concrete type at that point, even if it's inside the same function from where we'll return the concrete type. However I wonder if the following would be valid.
func f7(_ i: Int) -> opaque P {
if i == 0 {
return f7(1)
} else if i < 0 {
return f7(-i) as Int // Is this valid or not?
} else {
return 0
}
}
Are there ,
missing between these opaque
clauses?
extension BidirectionalCollection {
public func reversed()
-> opaque BidirectionalCollection where _.Element == Element
opaque RandomAccessCollection where Self: RandomAccessCollection
opaque MutableCollection where Self: MutableCollection {
return ReversedCollection<Self>(...)
}
}
Have you forgot to update the grammar? Why is there a ->
after the where
clause?
opaque-conditional-requirement ::= where-clause '->' requirement-list
I'm not sure I follow this reasoning:
public typealias Reversed<Base : BidirectionalCollection> : opaque BidirectionalCollection where _.Element == Base.Element = ReversedCollection<Base>
Then, we can describe conditional conformances on
Reversed
:extension Reversed: RandomAccessCollection where Element == Base.Element { }
The conditional conformance must be satisfied by the underlying concrete type (here,
ReversedCollection
), and the extension must be empty:Reversed
is the same asReversedCollection
at runtime, so one cannot add any API toReversed
beyond whatReversedCollection
supports.
If the concrete type is public then I can retroactively extend it with custom protocols, even add custom conditional conformances or simply add more custom API to the type. When such a type is hidden by an opaque
type then we don't know which conditional conformances could exist on the hidden concrete type and therefore a library user can no longer add custom conditional conformances, retroactively conform to custom protocols or simply extend the API of the hidden concrete type. Why is this restriction necessary? I think there is enough information exposed by the opaque type to allow extending all subsets of opaque types at once.
// module A
public protocol P {
func value() -> Int
}
extension Int : P {
public func value() -> Int {
return self
}
}
extension Double : P {
public func value() -> Int {
return Int(self)
}
}
public struct T {
func opaqueP() -> opaque P {
return 42 // Int
}
}
// module B
// extends the concrete type that conforms to `P`
extension opaque P {
func multipliedByTwo() -> Int {
return self.value() * 2
}
}
let t = T()
let p = t.opaqueP()
let value = p.value()
let new = p.multipliedByTwo() // this should be valid, because we indirectly extended `Int` in this case
Loosing the ability to extend these types would be simply a shoot in the own foot.