Why do I get the error “Protocol … can only be used as a generic constraint because it has Self or associated type requirements”? - swift

I wrote an extension onto Int as below.
extension Int {
func squared () -> Int {
return self * self
}
}
print(10.squared()) // works
The above code works. Now I want to extend the IntegerType protocol so that Int, UInt, Int64, etc would all conform. My code is as below.
extension IntegerType {
func squared () -> IntegerType { // this line creates error
return self * self
}
}
I get error:
Protocol 'IntegerType' can only be used as a generic constraint because it has Self or associated type requirements
I already saw this question and its video & this question, still couldn't understand. I only understood that there is some associatedType which in this case is Self but couldn't connect the dots. I feel like also my lack of knowledge on the Generics subject is also a reason...
Can someone elaborate a bit on the subject and why does the extension create an error?

You just have to return Self
edit/update:
Note: You can extend all numeric types (Integer & FloatingPoint) in Swift 4 extending the Numeric Protocol
Swift 4
extension Numeric {
func squared() -> Self {
return self * self
}
}
Swift 3
extension Integer {
func squared() -> Self {
return self * self
}
}

A function return type can only be a concrete Type.
The point is Type. Anything struct, class or Protocols that are completely defined in themselves are pure Type. However when a protocol or struct depend on another Generic Type Placeholder such as T, then this is a partial type.
Type are a data construct that compiler has to allocate certain memory.
So something like this:
let a = Array<T>() or let b = T is not sufficient information for the compiler to deduce at compile time.
Hence, this wont work.
extension IntegerType {
func squared () -> IntegerType { // this line creates error
return self * self
}
}
Here, IntegerType is a partial type. It is a generic protocol that only when conformed can then we know the exact type. Similar to Array. Array itself is not a type. Its a generic container. Only when someone creates it with Array() or Array()... then it has a type.
The same happened with you.
public protocol IntegerType : _IntegerType, RandomAccessIndexType {
then again,
public protocol RandomAccessIndexType : BidirectionalIndexType, Strideable, _RandomAccessAmbiguity {
#warn_unused_result
public func advancedBy(n: Self.Distance) -> Self
then again,
public protocol _RandomAccessAmbiguity {
associatedtype Distance : _SignedIntegerType = Int
}
Hence, as RandomAccessIndexType has Self requirement meaning until and unless someone conforms to it, Self is unknown placeholder. It is partial Type.
Since IntegerType conforms to the RandomAccessIndexType and _RandomAccessAmbuiguity which requires Distance associated type too.
Hence you cant do this too
let a: IntegerType = 12
Again IntegerType needs to know Self and Distance (associatedType).
Int however provides the details like so
public struct Int : SignedIntegerType, Comparable, Equatable {
/// A type that can represent the number of steps between pairs of
/// values.
public typealias Distance = Int
Hence you can do such
let a:Int = 10
because it provides Self for SignedIntegerType and Distance for its other counterpart.
Simply put it:
A partial type cannot be used where a concrete type can be. A partial type are good for other generics and constraining them.

Related

Unable to create operator for generic class in Swift

In Swift 4 I've created the following protocol to determine if something has a + operator inplemented
protocol Addable { static func +(lhs: Self, rhs: Self) -> Self }
Now I've created a class named Vector<T> where T is of course a generic type.
class Vector<T: Addable>: Addable {
var values: [T]
init(values: [T]) {
self.values = values
}
static func +(lhs: Vector<T>, rhs: Vector<T>) -> Self {
return lhs
}
}
The return lhs part of the + operator implementation is just temporary. But for some reason this gives me the following error:
Cannot convert return expression of type 'Vector<T>' to return type 'Self'
Any idea what I'm doing wrong here? I haven't got a clue.
Moved from comments:
Problem is caused by class inheretability. It looks like Swift cannot infer returning Self type for non-final classes, because Self in current class and in it's subclasses mean different. But for some reason there's no such problem with Self in parameters.
And solutions to this problem are:
make class final, and set returning Self to the proper type and it will work
replace class with struct, and set proper type
add associatedtype that is Self by default:
protocol Addable {
associatedtype S = Self
static func + (lhs: Self, rhs: Self) -> S
}
Latter option will work with non-final classes, but associated type should be checked that it's still equal to Self.

In Swift, how to cast to protocol with associated type?

In the following code, I want to test if x is a SpecialController. If it is, I want to get the currentValue as a SpecialValue. How do you do this? If not with a cast, then some other technique.
The last line there won't compile. There error is: Protocol "SpecialController" can only be used as a generic constraint because it has Self or associated type requirements.
protocol SpecialController {
associatedtype SpecialValueType : SpecialValue
var currentValue: SpecialValueType? { get }
}
...
var x: AnyObject = ...
if let sc = x as? SpecialController { // does not compile
Unfortunately, Swift doesn't currently support the use of protocols with associated types as actual types. This however is technically possible for the compiler to do; and it may well be implemented in a future version of the language.
A simple solution in your case is to define a 'shadow protocol' that SpecialController derives from, and allows you to access currentValue through a protocol requirement that type erases it:
// This assumes SpecialValue doesn't have associated types – if it does, you can
// repeat the same logic by adding TypeErasedSpecialValue, and then using that.
protocol SpecialValue {
// ...
}
protocol TypeErasedSpecialController {
var typeErasedCurrentValue: SpecialValue? { get }
}
protocol SpecialController : TypeErasedSpecialController {
associatedtype SpecialValueType : SpecialValue
var currentValue: SpecialValueType? { get }
}
extension SpecialController {
var typeErasedCurrentValue: SpecialValue? { return currentValue }
}
extension String : SpecialValue {}
struct S : SpecialController {
var currentValue: String?
}
var x: Any = S(currentValue: "Hello World!")
if let sc = x as? TypeErasedSpecialController {
print(sc.typeErasedCurrentValue as Any) // Optional("Hello World!")
}
[Edited to fix: : SpecialValue, not = SpecialValue]
This is not possible. SpecialValueController is an "incomplete type" conceptually so the compiler cannot know. SpecialValueType, although it is constrained by SpecialValue, it is not known until it is determined by any adopting class. So it is a really placeholder with inadequate information. as?-ness cannot be checked.
You could have a base class that adopts SpecialController with a concrete type for SpecialValueController, and have multiple child classes that inherit from the adopting class, if you're still seeking a degree of polymorphism.
This doesn't work because SpecialController isn't a single type. You can think of associated types as a kind of generics. A SpecialController with its SpecialValueType being an Int is a completely different type from a SpecialController with its SpecialValueType being an String, just like how Optional<Int> is a completely different type from Optional<String>.
Because of this, it doesn't make any sense to cast to SpecialValueType, because that would gloss over the associated type, and allow you to use (for example) a SpecialController with its SpecialValueType being an Int where a SpecialController with its SpecialValueType being a String is expected.
As compiler suggests, the only way SpecialController can be used is as a generic constraint. You can have a function that's generic over T, with the constraint that T must be a SpecialController. The domain of T now spans all the various concrete types of SpecialController, such as one with an Int associated type, and one with a String. For each possible associated type, there's a distinct SpecialController, and by extension, a distinct T.
To draw out the Optional<T> analogy further. Imagine if what you're trying to do was possible. It would be much like this:
func funcThatExpectsIntOptional(_: Int?) {}
let x: Optional<String> = "An optional string"
// Without its generic type parameter, this is an incomplete type. suppose this were valid
let y = x as! Optional
funcThatExpectsIntOptional(y) // boom.

Swift: Any Kind of sequence as a function parameter

I have created my custom sequence type and I want the function to accept any kind of sequence as a parameter. (I want to use both sets, and my sequence types on it)
Something like this:
private func _addToCurrentTileset(tilesToAdd tiles: SequenceType)
Is there any way how I can do it?
It seems relatively straightforward, but I can't figure it out somehow. Swift toolchain tells me:
Protocol 'SequenceType' can only be used as a generic constraint because it has Self or associated type requirements, and I don't know how to create a protocol that will conform to SequenceType and the Self requirement from it.
I can eliminate the associatedType requirement with, but not Self:
protocol EnumerableTileSequence: SequenceType {
associatedtype GeneratorType = geoBingAnCore.Generator
associatedtype SubSequence: SequenceType = EnumerableTileSequence
}
Now if say I can eliminate self requirement, then already with such protocol definition other collectionType entities like arrays, sets won't conform to it.
Reference:
my custom sequences are all subclasses of enumerator type defined as:
public class Enumerator<T> {
public func nextObject() -> T? {
RequiresConcreteImplementation()
}
}
extension Enumerator {
public var allObjects: [T] {
return Array(self)
}
}
extension Enumerator: SequenceType {
public func generate() -> Generator<T> {
return Generator(enumerator: self)
}
}
public struct Generator<T>: GeneratorType {
let enumerator: Enumerator<T>
public mutating func next() -> T? {
return enumerator.nextObject()
}
}
The compiler is telling you the answer: "Protocol 'Sequence' can only be used as a generic constraint because it has Self or associated type requirements".
You can therefore do this with generics:
private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T) {
...
}
This will allow you to pass in any concrete type that conforms to Sequence into your function. Swift will infer the concrete type, allowing you to pass the sequence around without lose type information.
If you want to restrict the type of the element in the sequence to a given protocol, you can do:
private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T) where T.Element: SomeProtocol {
...
}
Or to a concrete type:
private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T) where T.Element == SomeConcreteType {
...
}
If you don't care about the concrete type of the sequence itself (useful for mixing them together and in most cases storing them), then Anton's answer has got you covered with the type-erased version of Sequence.
You can use type-eraser AnySequence for that:
A type-erased sequence.
Forwards operations to an arbitrary underlying sequence having the same Element type, hiding the specifics of the underlying SequenceType.
E.g. if you will need to store tiles as an internal property or somehow use its concrete type in the structure of you object then that would be the way to go.
If you simply need to be able to use the sequence w/o having to store it (e.g. just map on it), then you can simply use generics (like #originaluser2 suggests). E.g. you might end up with something like:
private func _addToCurrentTileset<S: SequenceType where S.Generator.Element == Tile>(tilesToAdd tiles: S) {
let typeErasedSequence = AnySequence(tiles) // Type == AnySequence<Tile>
let originalSequence = tiles // Type == whatever type that conforms to SequenceType and has Tile as its Generator.Element
}

protocol with same associated type name

If I have two protocols whose associated type happens to be the same, such as
protocol Read {
associatedtype Element
func read() -> Element
}
protocol Write {
associatedtype Element
func write(a: Element)
}
Then I would like to have a class to read integer from and write string to:
class ReadWrite: Read, Write {
func read() -> Int {
return 5
}
func write(a: String) {
print("writing \(a)")
}
}
but the compiler complains and suggests changing String to Int. Ideally the type should be inferred, or at least compiles if I explicitly declare
associatedtype Read.Element = Int
associatedtype Write.Element = String
within ReadWrite. Any work around?
update
Workaround inspired by this question is to create two auxiliary protocols
protocol ReadInt: Read {
associatedtype Element = Int
}
protocol WriteString: Write {
associatedtype Element = String
}
and have the class inherit from these two instead:
class ReadWrite: ReadInt, WriteString {
func read() -> Int {
return 5
}
func write(a: String) {
print("writing \(a)")
}
}
This seems to compile, but I am afraid of any gotcha following this way.
update again
I found the issue in Swift's issue tracker. Anyone require this missing feature (like me) should vote for it. As a comparison, this pattern is possible in Rust, which also supports associated types (although this is not an idiomatic usage).
Another workaround is to create a third, combined protocol:
protocol ReadWrite {
associatedtype R
associatedtype W
func read() -> R
func write(a: W)
}
It's not pretty, since it forces you to redeclare the protocol members, but it does keep it generic (you're not limited to String and Int).

Use of typealias syntax within protocols in the Swift standard library

In the Swift programming guide from Apple, it is described how to use the typealias keyword within protocols (from the section on Generics)
protocol Container {
typealias ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
which is then implemented:
struct IntStack: Container {
typealias ItemType = Int // can sometimes be left out and inferred by the compiler
mutating func append(item: Int) {
self.push(item)
}
// redacted
}
However, a significantly different use case is found in the Swift standard lib, e.g
public protocol ForwardIndexType : _Incrementable {
typealias Distance : _SignedIntegerType = Int
// redacted
}
or
public protocol CollectionType : Indexable, SequenceType {
typealias Generator : GeneratorType = IndexingGenerator<Self>
public func generate() -> Self.Generator
// redacted
}
together with:
extension CollectionType where Generator == IndexingGenerator<Self> {
public func generate() -> IndexingGenerator<Self>
}
What does this syntax represent? It appears that the typealias is both declared, restricted (e.g. to GeneratorType) and assigned, all at once? What does this mean and why is it so? I expected to see assignment (=) only in implementing client code.
My understanding of typealias is that it represents a type, that is 'filled in' by the implementing code (as per generics) yet here it seems to implement a type for the typealias in the declaration, even though this is also done in the extension (where I would expect it).
Take a look at this answer. Use of a colon shows inheritance, use of an equals sign shows assignment.
In my understanding this means the following:
typealias X // defines associated type X for subclasses to override
typealias X: Y // defines associated type X and requires that it conform to Y
typealias X = Z // defines associated type X with a default of type Z
typealias X: Y = Z // defines associated type X with a default of type Z and requires that any overrides conform to Y
My interpretation seems to be supported by this article on Swift generics:
An associated type is declared by a protocol using the typealias
keyword. It normally set by an item that conforms to that protocol,
although you can supply a default. Like type parameters, an
associated type can be used as a token when building generic type
rules.
The use of the keyword typealias can be misleading for defining associated types and may be replaced by associatedtype in the future.