XCode 11.2.1
macOS Mojave 10.14.6
So, I'm trying to add the ability to remove objects from an array, if I've kept the reference. Following internet advice, I've caused my protocol to inherit from AnyObject, as this causes/requires/implies === to be defined on any classes that implement the protocol. However, XCode is behaving strangely with the types on the Array extension. Consider that the following compiles fine:
public protocol Foo: AnyObject {
}
public extension Array where Element == Foo {
mutating func removeElement(element: Element) {
if let idx = self.firstIndex(where: {$0 === element}) {
self.remove(at: idx)
}
}
}
public func bar(array: [Foo], element: Foo) -> [Foo] {
var arrayCopy: [Foo] = array
arrayCopy.removeElement(element: element)
return arrayCopy
}
but that if I change the extension type to Element: AnyObject, I get a compile error as follows:
...
public extension Array where Element: AnyObject {
...
...
// Compiler error: '[Foo]' requires that 'Foo' conform to 'AnyObject'
arrayCopy.removeElement(element: element)
...
Foo DOES conform to AnyObject. It's right there in its definition. Why does XCode not acknowledge this?
You are using old software so you don't get the modern error message:
Referencing instance method 'removeElement(element:)' on 'Array'
requires that 'Foo' be a class type
And that's true. element isn't an instance of a static type, as far as the compiler understands, but it will be if you write it like this instead:
public func bar<Foo: Module.Foo>(array: [Foo], element: Foo) -> [Foo] {
where Module is the actual name of your module, of course.
If you need to use a heterogeneous array, then I don't know how to make things any cleaner than this. Let me know if you figure out better.
(Keep the signature of the function the same; change the body instead.)
var arrayCopy: [AnyObject] = array
arrayCopy.removeElement(element: element)
return arrayCopy as! [Foo]
Related
I am using Swift 2.2 on XCode 7.3.1 and trying to call a Generic function from another Generic function.
Code
class Thing1 {
let variable: SomeProtocol
init<A: SomeProtocol>(variable: A) {
self.variable = variable
self.add1(self.variable)
}
func add1<A: SomeProtocol>(stuff: A) {
let thing: Thing2 = Thing2()
thing.add2(stuff)
}
}
class Thing2 {
func add2<A: SomeProtocol>(stuff: A) {
}
}
protocol SomeProtocol { }
add1("a") // Cannot invoke 'add1' with an argument list of type '(String)'
add1(4) // Cannot invoke 'add1' with an argument list of type '(Int)'
I get the error.
'Cannot invoke add with an argument of list type '(Whatever type I used to call the function)''
The problem is that abstract types in Swift don't necessarily conform to themselves – therefore you cannot use a SomeProtocol typed thing as a concrete typed thing that conforms to SomeProtocol (which is what your add1 generic function expects as an argument).
The simplest solution in your case therefore is just to use the generic variable argument, rather than the variable property, as because it's a generic, it's typed as a concrete thing that conforms to SomeProtocol, which can therefore be passed into your add1 function:
init<A: SomeProtocol>(variable: A) {
self.variable = variable
add1(variable)
}
However in order to prevent these kind of issues later down the line, you may want to consider making your class generic, assuming that your variable property should be of constant type throughout the lifetime of a given Thing1 instance:
class Thing1<A:SomeProtocol> {
let variable: A
init(variable: A) {
self.variable = variable
add1(variable)
}
func add1(stuff: A) {
let thing = Thing2()
thing.add2(stuff)
}
}
Or, you could refactor your code to use the abstract type SomeProtocol, which will allow you to work with any type that conforms to SomeProtocol (e.g allowing you to mix different Thing1 instances with different variable types in an array):
class Thing1 {
let variable: SomeProtocol
init(variable: SomeProtocol) {
self.variable = variable
add1(variable)
}
func add1(stuff: SomeProtocol) {
let thing = Thing2()
thing.add2(stuff)
}
}
class Thing2 {
func add2(stuff: SomeProtocol) {
}
}
Although you should always be aware of the extra costs that come with using abstract types, see this great WWDC talk for more info.
Adding the extensions to String and Int and constructing Thing1 objects makes it work:
extension String: SomeProtocol{}
extension Int: SomeProtocol{}
Thing1(variable: "a").add1("a")
Thing1(variable: 2).add1(4)
I'm using Swift and trying to make some collection objects. These collection objects have a backing Dictionary to hold custom objects. For example, an object might be of type Cat and the collection object would be of type Cats. Cats would have a private dictionary containing values of type Cat. I have other types that also need respective collections (each collection type has specific logic for the type it holds).
I created a protocol to ensure each collection has a few common characteristics. These common functions and subscripts are generally passthroughs to the backing dictionary. Here is the protocol:
protocol ObjectDictionaryProtocol {
// These are necessary for generics to work in protocols
typealias Key: Hashable
typealias Value
// MARK: - Properties
var count: Int { get }
var isEmpty: Bool { get }
var keys: LazyMapCollection<Dictionary<Key, Value>, Key> { get }
var values: LazyMapCollection<Dictionary<Key, Value>, Value> { get }
// MARK: - Subscripts
subscript(key: Key) -> Value? { get set }
}
When I go to actually use the protocol as a type, for instance:
var objects: ObjectDictionaryProtocol
or
init(objs: ObjectDictionaryProtocol) {
...
}
I get the error:
Protocol 'ObjectDictionaryProtocol' can only be used as a generic constraint because it has Self or associated type requirements
I've searched around and it looks like the Hashable protocol I'm conforming to for my Key typealias is causing this. What is the best way to get around this? Is there a way to change the protocol such that I don't need the Hashable, or do I need to do something in the class that is using ObjectDictionaryProtocol? Or maybe there's a better way to effectively 'subclass' a Swift Dictionary (quotes because I realize the Dictionary struct cannot be subclassed)?
A protocol with associated types is less a type and more a template for a type. The actual type exists when the protocol's associated types are specified. Thus ObjectDictionaryProtocol 'becomes' a type when you specify:
ObjectDictionaryProtocol<String,Cat>
but the above is not valid Swift...
So you asked... '[is there] a better way to effectively 'subclass' a Swift Dictionary'. You might get by with an extension with something like:
class Cat {}
extension Dictionary where Value : Cat {
func voice (name: Key) {
if let _ = self[name] {
print ("\(name): Meow")
}
}
}
var someCats = Dictionary<String,Cat>()
someCats["Spot"] = Cat()
someCats.voice("Spot")
// Spot: Meow
Or you may need to actually implement the protocol.
class ObjectDiciontary<Key:Hashable, Value> : ObjectDictionaryProtocol {
var backingDictionary = Dictionary<Key,Value>()
// implement protocol
}
var object : ObjectDictionary<String,Cat> = ...
// ...
The reason is because when you're using typealias you're effectivly making your Protocol into a generic protocol as Protocol<T>. Bear with me here, I'll explain why and how to fix it.
The issue here is that Apple has decided to make typealias the keyword for defining associated types. This is fixed in Swift 2.2 (Xcode 7.3)
You can read more about it on https://github.com/apple/swift-evolution/blob/master/proposals/0011-replace-typealias-associated.md
It's being renamed to associatedtype which makes more sense.
This means your protocol has to be adopted, and there define its associated types.
In your case it would look something like
protocol ObjectDictionaryProtocol {
associatedtype Value
}
extension String : ObjectDictionaryProtocol {
associatedtype = Double
}
The init could look like
init<T : ObjectDictionaryProtocol>(objs: ObjectDictionaryProtocol)
or
init<T : ObjectDictionaryProtocol
where T.Value == Double>(objs: ObjectDictionaryProtocol)
Now for typealias Key: Hashable it means that whatever type that is assigned to Key has to conform or be Hashable
This will give you an error that String isn't conforming to ObjectDictionaryProtocol as it can't fulfil the requirements.
protocol ObjectDictionaryProtocol {
associatedtype Value : FloatingPointType
}
extension String : ObjectDictionaryProtocol {
associatedtype = Int
}
Int isn't a FloatingPointType (but Double is)
In swift 2.0 is there a way to pass the type of the class in a variable so that I can later use it for checking if a object type 'is' that class type.
Better explained thru following example :
class Base {..}
class Derived : Base {..}
var obj: Base = Derived()
if obj is Derived {
print("obj is Derived type")
}
This is fine. But I want to be ability to store the class type 'Derived' in a variable something like this :
let classType = Derived // Of course this will give compile error
And use it later to check the type of an object :
if obj is classType {..}
The closest I came to dealing with saving the Class type is:
let classType = Derived.self
This says the classType is of type 'Derived.Type', but you can't really use that for checking the object type as below :
if obj is classType {..blah.. } // Compile error.'Use of undeclared type 'classType'
I hope you are getting my point. I'm trying to store the class type in a variable and later use that to check if the object belongs to that type.
Is there a way to do it.
I looked at similar forums on stack overflow but nothing which came close to answering this.
Like this:
class Base {}
class Derived : Base {}
var obj: Base = Derived()
if obj.dynamicType === Derived.self {
print("obj is Derived type")
}
#matt's answer works with Swift 2.0. In swift 3 you can simply do the following:
class Base {}
class Derived : Base {}
var obj: Base = Derived()
let aClassType = Derived.self
if type(of: obj) == aClassType {
print("hey !")
}
Unless === is better. I don't get the difference.
I may have a solution which doesn't need to create an instance of saved type.
The idea is to create a generic struct conforming to protocol P with a typealias inside. Then we can create instances of that struct and pass them to a function, which accepts an argument conforming to P and has access to a type via typealias in protocol.
Lets create something like this:
protocol TypeContainerP {
typealias type
}
struct TypeContainer<T>: TypeContainerP {
typealias type = T
}
Now we can create instance of TypeContainer parameterized with some types:
class A {}
class B {}
let containerA = TypeContainer<A>()
let containerB = TypeContainer<B>()
and create function, which has TypeContainerP as an argument and gives us access to type via protocol:
func check<T, E: TypeContainerP>(any: T, _: E) {
print(any is E.type)
}
and we have:
check(A(), containerA) // true
check(A(), containerB) // false
check(B(), containerA) // false
check(B(), containerB) // true
Given we have a Swift protocol with one static method:
protocol Creatable: class {
static func create() -> AnyObject
}
and a pure Swift class which conforms to the protocol:
class Foo : Creatable {
static func create() -> AnyObject {
return Foo() as AnyObject
}
}
Later on when one tries to make use of that protocol by operating on type Creatable e.g.:
var f : Creatable = Foo.self
f.create()
The compiler complains with the following:
error: type 'Foo.Type' does not conform to protocol 'Creatable'
The question is: is this a Swift limitation or I'm using the protocols and static/class method in the wrong way.
Objective-C equivalent would be something like:
Class someClass = [Foo class];
if ([someClass conformsToProtocol:#protocol(Creatable)]) {
[(Class <Foo>)someClass create];
}
A Creatable reference points to an instance of Foo, not to the Foo type itself.
To get the equivalent of the class-level protocol implementation, you need an instance of Creatable.Type:
let c: Creatable.Type = Foo.self
However, you’ll get an error when you then try to use it:
// error: accessing members of protocol type value 'Creatable.Type' is unimplemented
c.create()
All that said, is there a reason why you can’t just use functions to fulfill your requirement, instead of metatypes?
let f = Foo.create
// f is now a function, ()->AnyObject, that creates Foos
let someFoo = f()
Using .Type is the key:
var f : Creatable.Type = Foo.self
And this no longer gives the "unimplemented" error. See full code below:
protocol Creatable: class {
static func create() -> AnyObject
}
class Foo : Creatable {
static func create() -> AnyObject {
return Foo() as AnyObject
}
}
var f : Creatable.Type = Foo.self
f.create()
Let's say I have a protocol :
public protocol Printable {
typealias T
func Print(val:T)
}
And here is the implementation
class Printer<T> : Printable {
func Print(val: T) {
println(val)
}
}
My expectation was that I must be able to use Printable variable to print values like this :
let p:Printable = Printer<Int>()
p.Print(67)
Compiler is complaining with this error :
"protocol 'Printable' can only be used as a generic constraint because
it has Self or associated type requirements"
Am I doing something wrong ? Anyway to fix this ?
**EDIT :** Adding similar code that works in C#
public interface IPrintable<T>
{
void Print(T val);
}
public class Printer<T> : IPrintable<T>
{
public void Print(T val)
{
Console.WriteLine(val);
}
}
//.... inside Main
.....
IPrintable<int> p = new Printer<int>();
p.Print(67)
EDIT 2: Real world example of what I want. Note that this will not compile, but presents what I want to achieve.
protocol Printable
{
func Print()
}
protocol CollectionType<T where T:Printable> : SequenceType
{
.....
/// here goes implementation
.....
}
public class Collection<T where T:Printable> : CollectionType<T>
{
......
}
let col:CollectionType<Int> = SomeFunctiionThatReturnsIntCollection()
for item in col {
item.Print()
}
As Thomas points out, you can declare your variable by not giving a type at all (or you could explicitly give it as type Printer<Int>. But here's an explanation of why you can't have a type of the Printable protocol.
You can't treat protocols with associated types like regular protocols and declare them as standalone variable types. To think about why, consider this scenario. Suppose you declared a protocol for storing some arbitrary type and then fetching it back:
// a general protocol that allows for storing and retrieving
// a specific type (as defined by a Stored typealias
protocol StoringType {
typealias Stored
init(_ value: Stored)
func getStored() -> Stored
}
// An implementation that stores Ints
struct IntStorer: StoringType {
typealias Stored = Int
private let _stored: Int
init(_ value: Int) { _stored = value }
func getStored() -> Int { return _stored }
}
// An implementation that stores Strings
struct StringStorer: StoringType {
typealias Stored = String
private let _stored: String
init(_ value: String) { _stored = value }
func getStored() -> String { return _stored }
}
let intStorer = IntStorer(5)
intStorer.getStored() // returns 5
let stringStorer = StringStorer("five")
stringStorer.getStored() // returns "five"
OK, so far so good.
Now, the main reason you would have a type of a variable be a protocol a type implements, rather than the actual type, is so that you can assign different kinds of object that all conform to that protocol to the same variable, and get polymorphic behavior at runtime depending on what the object actually is.
But you can't do this if the protocol has an associated type. How would the following code work in practice?
// as you've seen this won't compile because
// StoringType has an associated type.
// randomly assign either a string or int storer to someStorer:
var someStorer: StoringType =
arc4random()%2 == 0 ? intStorer : stringStorer
let x = someStorer.getStored()
In the above code, what would the type of x be? An Int? Or a String? In Swift, all types must be fixed at compile time. A function cannot dynamically shift from returning one type to another based on factors determined at runtime.
Instead, you can only use StoredType as a generic constraint. Suppose you wanted to print out any kind of stored type. You could write a function like this:
func printStoredValue<S: StoringType>(storer: S) {
let x = storer.getStored()
println(x)
}
printStoredValue(intStorer)
printStoredValue(stringStorer)
This is OK, because at compile time, it's as if the compiler writes out two versions of printStoredValue: one for Ints, and one for Strings. Within those two versions, x is known to be of a specific type.
There is one more solution that hasn't been mentioned on this question, which is using a technique called type erasure. To achieve an abstract interface for a generic protocol, create a class or struct that wraps an object or struct that conforms to the protocol. The wrapper class, usually named 'Any{protocol name}', itself conforms to the protocol and implements its functions by forwarding all calls to the internal object. Try the example below in a playground:
import Foundation
public protocol Printer {
typealias T
func print(val:T)
}
struct AnyPrinter<U>: Printer {
typealias T = U
private let _print: U -> ()
init<Base: Printer where Base.T == U>(base : Base) {
_print = base.print
}
func print(val: T) {
_print(val)
}
}
struct NSLogger<U>: Printer {
typealias T = U
func print(val: T) {
NSLog("\(val)")
}
}
let nsLogger = NSLogger<Int>()
let printer = AnyPrinter(base: nsLogger)
printer.print(5) // prints 5
The type of printer is known to be AnyPrinter<Int> and can be used to abstract any possible implementation of the Printer protocol. While AnyPrinter is not technically abstract, it's implementation is just a fall through to a real implementing type, and can be used to decouple implementing types from the types using them.
One thing to note is that AnyPrinter does not have to explicitly retain the base instance. In fact, we can't since we can't declare AnyPrinter to have a Printer<T> property. Instead, we get a function pointer _print to base's print function. Calling base.print without invoking it returns a function where base is curried as the self variable, and is thusly retained for future invocations.
Another thing to keep in mind is that this solution is essentially another layer of dynamic dispatch which means a slight hit on performance. Also, the type erasing instance requires extra memory on top of the underlying instance. For these reasons, type erasure is not a cost free abstraction.
Obviously there is some work to set up type erasure, but it can be very useful if generic protocol abstraction is needed. This pattern is found in the swift standard library with types like AnySequence. Further reading: http://robnapier.net/erasure
BONUS:
If you decide you want to inject the same implementation of Printer everywhere, you can provide a convenience initializer for AnyPrinter which injects that type.
extension AnyPrinter {
convenience init() {
let nsLogger = NSLogger<T>()
self.init(base: nsLogger)
}
}
let printer = AnyPrinter<Int>()
printer.print(10) //prints 10 with NSLog
This can be an easy and DRY way to express dependency injections for protocols that you use across your app.
Addressing your updated use case:
(btw Printable is already a standard Swift protocol so you’d probably want to pick a different name to avoid confusion)
To enforce specific restrictions on protocol implementors, you can constrain the protocol's typealias. So to create your protocol collection that requires the elements to be printable:
// because of how how collections are structured in the Swift std lib,
// you’d first need to create a PrintableGeneratorType, which would be
// a constrained version of GeneratorType
protocol PrintableGeneratorType: GeneratorType {
// require elements to be printable:
typealias Element: Printable
}
// then have the collection require a printable generator
protocol PrintableCollectionType: CollectionType {
typealias Generator: PrintableGenerator
}
Now if you wanted to implement a collection that could only contain printable elements:
struct MyPrintableCollection<T: Printable>: PrintableCollectionType {
typealias Generator = IndexingGenerator<T>
// etc...
}
However, this is probably of little actual utility, since you can’t constrain existing Swift collection structs like that, only ones you implement.
Instead, you should create generic functions that constrain their input to collections containing printable elements.
func printCollection
<C: CollectionType where C.Generator.Element: Printable>
(source: C) {
for x in source {
x.print()
}
}