On 13 January 2016 at 08:16, Maximilian Hünenberger < swift-evolution@swift.org> wrote:
1+ for adding generics to protocols.
What about generics in protocols which are only a view to its associated
types or generics which create/are associated types?
Example of a simple protocol which models a node of a tree:
// Before
// NodeType can be anything
// currently Swift doesn't allow
// `typealias NodeType: Node`
//
// or even where clauses
// `typealias NodeType: Node where NodeType.T == T`
protocol Node {
typealias T
typealias NodeType
var value: T { get }
var nodes: [NodeType] { get }
}
// After
protocol Node<T> {
typealias T // probably remove this declaration
var value: T { get }
var nodes: [Node<T>] { get }
}
So a generic parameter is placed after the protocol name. Therefore a
corresponding associated type could be synthesized making its declaration
in the body of the protocol unnecessary.
In order to let
func afunction<S: SequenceType where S.Generator.Element == Int>(s: S){}
still compile there could be a general Swift feature to get the generic
type by dot syntax (e.g. synthesized typealiases for every generic
parameter).
The function declaration above could be rewritten to using function like
parameter syntax:
func afunction(s: SequenceType<Generator: GeneratorType<Int>,
SubSequence: _>){}
// or omitting `SubSequence: _` since the type is already unambiguous
func afunction(s: SequenceType<Generator: GeneratorType<Int>>){}
in this case there is almost no win. But as you can see in the example
with the protocol, generics allow for much better abstraction.
Also where clauses could be used in generic parameter declarations which
are disallowed for associated types.
Maximilian
Am 12.01.2016 um 19:19 schrieb Jordan Rose via swift-evolution < > swift-evolution@swift.org>:
Agreed on both counts. Generics are more familiar but don't actually cover
the use cases where the associated type is *not* independent of the model
object (like a Sequence's Generator or a Collection's Index). Dropping that
information results in a lot of extra indirection at runtime, which we
don't want.
Jordan
On Jan 12, 2016, at 8:17, Austin Zheng via swift-evolution < > swift-evolution@swift.org> wrote:
Strong -1, covariance on generics should be explicitly opt-in. Also -1 on
generics replacing associated types in protocols.
Austin
On Jan 12, 2016, at 1:45 AM, Howard Lovatt via swift-evolution < > swift-evolution@swift.org> wrote:
Currently you generics are invariant whereas function arguments etc. are
covariant. I am suggesting that if the way generics are implemented is
changed then they can be made covariant and that this will add considerable
utility to Swift generics.
1st a demonstration of the current situation of invariant generics:
// Current system
class Top {}
class Bottom: Top {}
struct Box<T: AnyObject> {
var value: T
init(_ initialValue: T) {
value = initialValue;
}
}
let boxB = Box(Bottom())
// let boxT: Box<Top> = boxB // Covariance currently not allowed
The key point is although `Bottom` 'is a’ `Top`, `Box<Bottom>` *is not* a
`Box<Top>`.
I am suggesting:
1. That `Box<Bottom>` should be a `Box<Top>` (covariance).
2. An implementation that allows the above covariance.
3. That protocols are made generic, i.e. `protocol Box<T> { var value: T {
get set } }` and that this mechanism replaces associated types for
protocols.
// Proposal:
// 1. No change to Box, i.e. programmer would just write Box as before
// 2. Code transformed by comiler with write check for each specific,
generic type instance
// Best approximation of resulting code in current Swift to
demonstrate spirit of idea:
// Compiler writes a universal form using the upper bound (it writes
the underlyting representation).
// In practice this would be called `Box` but used `BoxAnyObject` to
indicate that it has a generic argument bounded by `AnyObject`.
struct BoxAnyObject {
// Generated from generic argument `<T: AnyObject>`.
let T: AnyObject.Type // Store the actual type.
// Generated from stored property `var value: T` and noting that
`T`'s upper bound is `AnyObject`.
private var _value: AnyObject // Access the stored property
through a setter so that type can be checked
var value: AnyObject {
get {
return _value
}
set {
// In all functions check that args declared as `T` are
actually a `T` or a sub-type.
// Note: `is` only works with type literal and there is
no `>=` operator for types :(.
// `is` would need changing or `>=` for types adding,
nearest at moment `==`.
precondition(T == /* >= */ newValue.dynamicType, "Type of
newValue, \(newValue.dynamicType), is not a sub-type of generic type T, \(
T)")
_value = newValue
}
}
// Generated from `init(_ initialValue: T)` and noting that `T`'s
upper bound is `AnyObject`.
init(_ lowestCommonDeclaredT: AnyObject.Type, _ initialValue:
AnyObject) {
T = lowestCommonDeclaredT
_value = initialValue
}
}
// Demonstrate that all `Box`es are the same size and therefore can
be bitwise copied
// Compiler supplies lowest-common, declared, generic type for all
the `T`s in the `init` call.
var bT = BoxAnyObject(Top.self, Top()) // In practice user would
write `let bT = Box(Top())`.
bT.T // Top.Type
sizeofValue(bT) // 16
var bB = BoxAnyObject(Bottom.self, Bottom()) // In practice user
would write `let bB = Box(Bottom())`.
bB.T // Bottom.Type
sizeofValue(bB) // 16
// Demonstration covariance.
bT = bB // Compiler would check covariance of declared generic types.
bT.T // Bottom.Type
// Demonstrate generic returned type
// Compiler would add cast to declared, generic type.
bB.value as! Bottom // In practice user would write `bB.value`.
// Demonstrate type safety
bT = BoxAnyObject(Top.self, Top()) // In practice user would write
`bT = Box(Top())`.
bT.value = Top() // OK
// bT.value = Bottom() // Doesn't work at present because need `>=`
for types, but would work in practice
// bB.value = Top() // Runtime error - wrong type
The implications of this proposal are:
1. The compiler can statically type check a read from a stored property.
2. A write to a stored property is type checked at runtime.
3. Protocols can be made generic instead of having an associated type and
then they become a proper type with dynamic dispatch.
4. Generic protocols can be a type just like non-generic protocols,
structs, and classes and unlike associated type protocols that can only be
a generic constraint.
5. The awkwardness of dealing with associated type generics is replaced by
a more powerful and easier to understand semantic of a type, just like the
other types.
6. There is a lot of ‘non-obvoius’, long code, for example `inits`, that
use a `where` clause to constrain an associated type protocol, this would
be unnecessary.
7. There are whole types, `AnySequence`, `AnyGenerator`, etc., that would
be replaced by a generic protocols, `Sequence`, `Generator`, etc.
Advantages:
1. Covariant generics are a powerful addition to the language.
2. Generics’ invariance are inconsistent with the rest of the language.
3. Generic protocols would become a ‘proper’ type and you could have
arrays and fields of a generic protocol.
4. There are many threads on swift-evolution looking at how protocols can
be made into a ‘proper’ type or at least a concept that is easier to
understand.
Compatibility:
1. This would be a major change since associated types in protocols would
be replaced by generics.
2. The new implementation of generics might break some existing `struct`
and `class` code, for example if it is dependent on the exact size of an
object because the class will have extra fields, one for each generic type,
and therefore will be larger.
Disadvantages:
1. Major change.
2. Object size increases.
Thanks in advance for any comments,
— Howard.
PS This is part of a collection of proposals previously presented as
“Protocols on Steroids”.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution