So I was just playing with the protocols and just got confused with the following behaviour.
I have a protocol with the function and a base class with the same function name. Now, another class is inheriting from a base class and implementing a protocol. But it is not producing error in some scenarios.
For example:
protocol P {
func greetings()
}
class Base {
func greetings() {
print("Hello Base")
}
}
class A: Base {
override func greetings() {
print("Hello Class")
}
}
extension A: P {
}
let a = A()
print(a.greetings()) // print: Hello Class
let b:Base = A()
print(b.greetings()) // print: Hello Class
let p:P = A()
print(p.greetings()) // print: Hello Class
So, how is the conformance of the class to the protocol happening?
Also in the following case, when protocol function has default implementation, it compiles without any error and always opt from base class function.
protocol P {
func greetings()
}
extension P {
func greetings() {
print("Hello Protocol")
}
}
class Base {
func greetings() {
print("Hello Base")
}
}
class A: Base {
}
extension A: P {
}
let a = A()
print(a.greetings()) // print: Hello Base
let b:Base = A()
print(b.greetings()) // print: Hello Base
let p:P = A()
print(p.greetings()) // print: Hello Base
Why it always opt for a base class function? And Why no compile time error because of ambiguous function call?
The type of the variable you assign an object to does not control how functions are dispatched on that object. When looking for a function, the computer starts at the object and walks "up" through the class hierarchy looking for an implementation. ie. It starts at A and if it doesn't find a function, it goes up to Base (A's superclass) and looks there. If still not found it goes up to the next superclass (which there isn't one in this case). If the function isn't found then you get an error.
In your first example you have an instance of A and A overrides the base greetings so that is that implementation that will always be used. This is related to an important concept in Object Oriented Programming - Substitutability.
In this case you can declare a variable of type Base but assign an instance of a more specialised class - A, but the program still operates correctly.
Remember that type inference as shown in your first assignment (let a = A()) is not present in all languages. In many cases you need to explicitly declare a variable's type. If declaring a variable of type Base meant that the Base function was called instead of subclass, it would defeat the purpose of subclassing.
With regard to your question
how is the conformance of the class to the protocol happening?
A protocol is a specification but not an implementation (we will look at your question around default implementations next). Your protocol says that all things that conform to P must provide a greeting function. Clearly both Base and A provide a greeting function. Your extension merely adds the stipulation that A conforms to P. It doesn't need to add the implementation of P because the greeting method already exists.
If you removed the extension A: P then let p:P = A() would give an error because the compiler no longer knows that A conforms to P.
This brings us to your last two questions:
Why it always opt for a base class function?
And Why no compile time error because of ambiguous function call?
From The Swift Programming Language
You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol. If a conforming type provides its own implementation of a required method or property, that implementation will be used instead of the one provided by the extension.
In your second example block, A doesn't override the Base implementation of greeting, so the Base implementation is always called.
The default implementation of greeting that you added to P will only be used in the case where a class that conforms to P doesn't provide an implementation.
Default implementations can make it easier to conform to a protocol by supplying implementation where there is some behaviour that will apply to all or a majority of cases. Default implementations are always ignored if the conforming class provides an implementation
Consider the following example:
Protocol Vehicle {
func soundHorn()
var numberOfDoors: Int
}
extension Vehicle {
func soundHorn() {
print("Beep")
}
}
class SportsCar: Vehicle {
var numberOfDoors: Int {
return 2
}
}
class Sedan: Vehicle {
var numberOfDoors: Int {
return 4
}
}
class Truck: Vehicle {
var numberOfDoors: Int {
return 2
}
func soundHorn() {
print("**HONK**")
}
}
Here we have defined a simple protocol, Vehicle, that says that a Vehicle has a number of doors and can sound its horn. We provided a default soundHorn that prints "Beep". We then declared classes that implement this protocol. The two different types of car have different numbers of doors but we are happy with the default horn. For a Truck we have a bigger, louder horn, so we implement soundHorn rather than using the default:
var v: Vehicle = SportsCar()
v.soundHorn() // Prints "beep"
v = Truck()
v.soundHorn() // Prints "**HONK**"
Note how v is of type Vehicle but we get the correct horn based on the object that is actually assigned to v. The compiler is happy because it knows that all Vehicles can soundHorn; it doesn't need to know the specific vehicle type.
Related
A/c to Apple Doc,
A function or method with an opaque return type hides its return value’s type information. Instead of providing a concrete type as the function’s return type, the return value is described in terms of the protocols it supports
EDIT: Cutting the whole question short
/* PROTOCOLS */
protocol MyPros {}
/* STRUCT */
struct MyStruct {}
/* CLASSES */
class ClassA : MyPros {}
class ClassB : ClassA {}
class ClassC : ClassB {}
Now I using Opaque return type, 1. with struct 2. with class
/* FUNCTIONS */
func getOpaqueStruct() -> some MyStruct { // ERROR: An 'opaque' type must specify only 'Any', 'AnyObject', protocols, and/or a base class
return MyStruct()
}
func getOpaqueClass() -> some ClassC {
return ClassC()
}
getOpaqueStruct returns error which is understandable, if you check getOpaqueClass , getOpaqueClass also not returning protocols, and/or a base class so why class object able to return any class object in the inheritance chain. It also must be returns the baseclass i.e. classA or protocol i.e. MyPros.
ClassC can be in future be superclass of ClassD but base class of these chain is ClassA.
I think you are misunderstanding what the phrase "base class" in the error message means. It doesn't mean "a class that doesn't inherit from anything, and can have subclasses". It just means "a class that can have subclasses" or in other words, "a class that other classes can inherit from".
Why only limit the feature to classes that doesn't inherit from anything, when anything that could have subclasses can benefit from this feature.
Old answer (to revision 3 of the question):
You can't do some StructType because structs don't have subclasses. They whole point of opaque return types is to allow you to tell the caller that:
I'm returning a definite type, but you don't need to know what type this is. You just need to know it is a subclass of XXXClass/confomer of YYYProtocol.
No other types can inherit from structs, so if you have a method that is said to return some StructType, then it can only return StructType, nothing else. This defeats the purpose of opaque return types.
From the name of your method, writing:
func getPlanet() -> some Planet {
return Earth(name: "Earth", creatures: "Humans")
}
would make more sense in my opinion.
The caller knows that getPlanet will return a definite type, that is a conformer of Planet.
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've been trying to get this code to work
protocol Shootable
{
func shoot ()
}
protocol Shooter
{
var weapon:Shootable { get set }
}
class Gun:Shootable
{
func shoot() {
}
func someOtherMethod()
{
}
}
class Player:Shooter
{
var weapon:Gun
init ()
{
weapon = Gun()
weapon.someOtherMethod()
}
}
But the compiler tells me that Player does not conform to the Shooter protocol. I assume this is because the Player weapon var is of type Gun, not Shootable, even if Gun implements Shootable.
But then I changed this and now it works:
protocol Shooter
{
typealias Weapon:Shootable
var weapon:Weapon { get set }
}
And I have no idea why. I thought typealiases just give another name to a type, I wasn't aware of this kind of ability...
Can anyone shed some light on this?
AFAIK typealias inside a protocol declaration is something like declaring a generic type. Using a protocol type in a declaration is declaring you will use it just for what the protocol declares.
Your first example would work in case you write:
class Player:Shooter
{
var weapon:Shootable
init ()
{
weapon = Gun()
/* weapon.someOtherMethod()
Can't use it 'cause weapon is strictly a Shootable, thus it is not meant to have any other methods than shoot()
*/
}
}
Your second example works since you declare a generic type inside the protocol and require it to be a type that conforms to Shootable. Your modification makes use of type inference, thus it could be more clear the following rewriting of your second example:
class Player:Shooter
{
typealias Weapon = Gun
var weapon:Weapon
init ()
{
weapon = Gun()
weapon.someOtherMethod()
}
}
Here I explicitly declare that the generic protocol type alias Weapon is Gun (and since it conforms to Shootable all is ok). In your example, this is implicitly inferred by the compiler since there is no ambiguity.
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()
}
}
I want to lazy/inline implement a protocol in Swift.
So in the point of the implementation I will have access to variables outside the protocol scope ,
Same as implementing a interface in Java without declaring a class:
class MyClass:UIView {
var someComponent:SomeInnerComponent = SomeInnerComponent();
var count:Int = 0;
var a = :SomeProtocol { //<----- IS THIS POSSIBLE, IF YES HOW ?
func a0() {MyClass.count--}
func a1() {MyClass.count++}
}
someComponenet.delegate = a;
}
protocol SomeProtocol {
func a0()
func a1()
}
editing----
thanks i look at this solution, and i didn't see how to access a variable of the parent class.
all the examples show an Anonymous class but no one of the examples is accessing the parent variables .
What you're looking for is an inner class (not necessarily an anonymous one), declared in a scope that lets it access the count variable of a MyClass instance, and that adopts a protocol defined at a different scope. Right now Swift has a few of those pieces, but it doesn't look like you can put them all together in any way that's as concise as what you might be looking for.
You might think about declaring an inner class:
class MyView: UIView {
let someComponent = SomeInnerComponent() // type SomeInnerComponent is inferred
var count = 0 // type Int is inferred
class Helper: SomeProtocol {
func a0() { count-- } // ERROR
// ...
}
init() {
someComponent.delegate = Helper()
}
}
But that won't work, because count is implicitly self.count, where self is a Helper instance, not the MyView instance that "owns" the Helper instance. And there isn't a way to reference that MyView instance (or its properties) from within a Helper's methods, because you could just as well construct a MyView.Helper() without having an existing MyView instance. Inner classes (or nested types in general) in Swift nest only in lexical scope, not in existential ownership. (Or to put it another way, since you referenced Java: all inner classes in Swift are like static inner classes in Java. There's no non-static inner class.) If that's a feature you'd like, though, it's probably worth telling Apple you want it.
You could also try declaring Helper inside MyView.init() -- in Swift you can nest type definitions anywhere, including inside functions or methods of other types. Defined there, it can refer to MyView's properties. However, now the type information for Helper is only visible inside of MyView.init(), so when you assign it to someComponent.delegate (whose type is just SomeProtocol), you can't make use of it... this crashes the compiler, even. (That's another bug to report, but it's hard to say whether the bug is really "compiler crashes on valid usage" or "code is bad, but compiler crashes instead of producing error".)
The closest solution I can come up with looks something like this:
class SomeInnerComponent {
var delegate: SomeProtocol?
}
protocol SomeProtocol {
func a0()
func a1()
}
class MyClass {
var someComponent = SomeInnerComponent()
var count = 0
struct Helper: SomeProtocol {
var dec: () -> ()
var inc: () -> ()
func a0() { dec() }
func a1() { inc() }
}
init() {
someComponent.delegate = Helper(
dec: { self.count -= 1 }, // see note below
inc: { self.count += 1 }
)
}
}
How it works:
Helper is an inner struct (could be a class, but a struct is simpler)
It implements the a0 and a1 methods, satisfying the requirements of SomeProtocol
The implementations of a0 and a1 call through to the closures dec and inc, which are stored properties (aka instance variables) of the Helper struct
You write (or otherwise specify) these closures when you construct a Helper instance (using the default member-wise initializer, Helper(dec: (Void -> Void), inc: (Void -> Void)))
Because you can write the closures when initializing a Helper, those closures can capture variables where you're calling the initializer, including the implicit self that refers to the MyClass instance creating the Helper.
You need both a0/a1 and dec/inc because you need closures (the latter), not methods, for capturing the enclosing state. And even though closures and funcs/methods are in many ways interchangeable, you can't create a method/func implementation by assigning a closure to a method/func name. (It'd be a different story if SomeProtocol required closure properties instead of methods, but I'm assuming SomeProtocol isn't something under your control.)
Anyway, this is kind of a lot of boilerplate and a layer of abstraction that you might not really need, so it's probably worth looking into other ways to architect your code.
Note: my example uses the closure { self.count -= 1 } where you might expect { self.count-- }. The latter doesn't work because that's an expression with a value, so Swift will interpret it as shorthand for the closure's return value. Then it'll complain that you assigned a () -> Int closure to a property that expects a () -> () (aka Void -> Void) closure. Using -= 1 instead works around this issue.
I would go for a different approach, I know this a pretty old topic but just in case someone else struggles with this issue:
class MyClass:UIView {
var someComponent:SomeInnerComponent = SomeInnerComponent();
var count:Int = 0;
init(){
// Assign the delegate or do it somewhere else to your preference:
someComponenet.delegate = ProtocolImplementation(myClass: self);
}
private class ProtocolImplementation: SomeProtocol {
let selfReference: MyClass
init(myClass: MyClass){
selfReference = myClass
}
public func a0(){
selfReference.count--
}
public func a1(){
selfReference.count++
}
}
}
protocol SomeProtocol {
func a0()
func a1()
}
By following this approach it's also possible to include the same protocol multiple times, lets say your Protocol supports a generic and you want to implement it twice. SomeProtocol< SomeObject > and SomeProtocol< OtherObject > could be both used this way if needed.
Kind regards