what is the difference protocol's `: AnyObject` between `none`? - swift

1.
protocol A: AnyObject { }
2.
protocol A { }
I know case 1 can limit class-type
But, why should I limit class-type?

AnyObject requires that conforming types be classes, rather than structs or enums. See Class-Only Protocols for details.
Classes provide reference semantics, rather than value semantics, which you may require for your protocol. For example, if you want to observe an object, that only makes sense for a reference type (you can't observe changes to a value type, since value types are copied when modified). For more details on that see Structures and Classes, and particularly the sections explaining value and reference types.
There is no value type equivalent of AnyObject. You can't require value semantics for a protocol. This can lead to some headaches. As an example of the difference, consider the following:
protocol Incrementing {
var value: Int { get set }
}
extension Incrementing {
func incremented() -> Self {
var new = self // Value types copy, reference types reference
new.value += 1
return new
}
}
struct S: Incrementing { var value: Int = 0 }
class C: Incrementing { var value: Int = 0 }
var s = S()
s.incremented().value // 1
s.value // 0
var c = C()
c.incremented().value // 1
c.value // 1 (!!!)
This code makes sense for a struct, but is buggy for a class. There's no real fix for that in Swift today.

Related

Swift compile time dynamic type property

Is there any syntax can make this work? I need a property can determine its type in the compile time.
protocol P {}
struct A: P {
var onlyAHas: String
}
struct B: P {
var onlyBHas: String
}
var ins1: any P = A()
var ins2: any P = B()
ins1.onlyAHas = "a only"
ins2.onlyBHas = "b only"
Before getting to the solution, let's break down what any means, and while we're at it, we'll include some as well:
When you write:
var ins1: any P = A()
You are telling the compiler that you want to use ins1 as P. It's the protocol oriented equivalent of this OOP code:
class Base {
var baseProperty: String? = nil
}
class Concrete: Base {
var concreteProperty: String? = nil
}
let obj: Base = Concrete();
obj.baseProperty = "Some value" // <-- This is fine
obj.concreteProperty = "Some value" // <-- This is an error
This code tells the compiler that obj is a Base. You can assign it from a Concrete, but because that's a subclass of Base, but obj is still known locally as a Base not as a Concrete, so it can't access the properties of Concrete that weren't inherited from Base.
It's the same in your example. ins1 is known locally as a P not as an A, and P doesn't have an onlyAHas property.
You'd get similar behavior with some instead of any. There are a few differences between the two, but let's just talk about the main one:
some tells the compiler that it will be a type that it can resolve to one specific concrete type, but that it should enforce the abstraction to the protocol in source code. This allows it to generate more efficient code internally, because knowing the concrete type allows the compiler to call the concrete's implementation directly instead of going through its protocol witness table, which is the protocol-oriented analog of a "vtable" in OOP, so the effect is like in OOP when the compiler devirtualizes a method call because despite the syntax, it knows the actual concrete type. This avoids the runtime overhead of dynamic dispatch while still letting you use the abstraction of the existential type... well it's more like it requires you to use the abstraction of the existential type than lets you, because from a source code point of view, the abstraction is enforced.
any also enforces the abstraction, but it goes the other way in terms of the kind of optimizations the compiler can do. It says that the compiler must go through the protocol witness table, because, as the keyword suggests, its value could be any concrete type that conforms to the protocol, even if the compiler could determine that it's actually just one specific type locally. It also allows relaxation of some rules regarding using the protocol as a type when it has Self and associatedtype constraints.
But either way, you are telling the compiler that you want to use ins1 as a P and not as an A.
The solutions
There are a few solutions, actually:
Downcasting
The first is to downcast to the concrete type, as was suggested in comments by Joakim Danielson:
if var ins1 = ins1 as? A {
ins1.onlyAHas = "a only"
}
Downcasting is a code smell, but sometimes is actually the clearest or simplest solution. As long as it's contained locally, and doesn't become a wide-spread practice for using instances of type, P, it might be fine.
However, that example does have one problem: A is a value type, so the ins1 whose onlyAHas property is being set is a copy of the original ins1 you explicitly created. Having the same name confuses it slightly. If you only need the change to be in effect in the body of the if, that works just fine. If you need it to persist outside, you'd have to assign back to the original. Using the same name prevents that, so you'd need to use different names.
Execute concrete-specific code only at initialization
This only applies if the concrete type just configures some things for the protocol up-front, and thereafter protocol-only code can be used:
var ins1: any P = A(onlyAHas: "a only")
// From here on code can only do stuff with `ins1` that is defined in `P`
Or your could delegate the initialization to a function that internally knows the concrete type, but returns any P.
func makeA(_ s: String) -> any P
{
var a = A()
a.onlyAHas = s
return a
}
var ins1 = makeA("a only");
// From here on code can only do stuff with `ins1` that is defined in `P`
Declare protocol methods/computed properties that do the work.
This is the usual way to use protocols. Declaring a method in the protocol is similar to declaring a method in a base class. Implementing the method in a conforming concrete type is like overriding the method in a subclass. If you don't also provide a default implementation in a protocol extension, the protocol will enforce that conforming types implement the protocol - which is a big advantage over the OOP approach.
protocol P {
mutating func setString(_ s: String)
}
struct A: P
{
var onlyAHas: String
mutating func setString(_ s: String) {
onlyAHas = s
}
}
struct B: P
{
var onlyBHas: String
mutating func setString(_ s: String) {
onlyBHas = s
}
}
var ins1: any P = A()
var ins2: any P = B()
ins1.setString("a only") // <- Calls A's setString
ins2.setString("b only") // <- Calls B's setString
I'm doing this with a setString method, but you could certainly use a computed variable in the protocol to do the same thing, and that would be more "Swifty." I didn't do that just to emphasize the more general idea of putting functionality in the protocol, and not get hung up on the fact that the functionality in question happens to be setting a property.
If you don't need all conforming types to be able to set a String, one solution is to provide a do-nothing default implmentation in an extension on P:
protocol P {
mutating func setString(_ s: String)
}
extension P
{
mutating func setString(_ s: String) { /* do nothing */ }
}
// Same A and B definitions go here
struct C: P { }
var ins3: any P = C();
ins1.setString("a only") // <- Calls A's setString
ins2.setString("b only") // <- Calls B's setString
ins3.setString("c only") // <- Calls setString from extension of P
Most often though, setting/getting some concrete property is an implementation detail of doing some task that varies with the concrete type. So instead, you'd declare a method in the protocol to do that task:
protocol P
{
mutating func frobnicate()
}
struct A
{
var onlyAHas: String
mutating func frobnicate()
{
// Do some stuff
onlyAHas = "a only"
// Do some other stuff that uses onlyAHas
}
}
B would be defined similarly doing whatever is specific to it. If the stuff in comments is common code, you could break it down into prologue, main action, and epilogue.
protocol P
{
mutating func prepareToFrobnicate()
mutating func actuallyFrobnicate() -> String
mutating func finishFrobnication(result: String)
}
extension P
{
/*
This method isn't in protocol, so this exact method will be called;
however, it calls methods that *are* in the protocol, we provide
default implementations, so if conforming types, don't implement them,
the versions in this extension are called, but if they do implement
them, their versions will be called.
*/
mutating func frobnicate()
{
prepareToFrobnicate()
finishFrobnication(result: actuallyFrobnicate());
}
mutating func prepareToFrobnicate() {
// do stuff general stuff to prepare to frobnicate
}
mutating func actuallyFrobnicate() -> String {
return "" // just some default value
}
mutating func finishFrobnication(result: String) {
// define some default behavior
}
}
struct A
{
var onlyAHas: String
mutating func actuallyFrobnicate() -> String
{
// Maybe do some A-specific stuff
onlyAHas = "a only"
// Do some more A-specific stuff
return onlyAHas
}
}
struct B
{
var onlyBHas: String
mutating func actuallyFrobnicate() -> String {
"b only"
}
mutating func finishFrobnication(result: String)
{
// Maybe do some B-specific stuff
onlyBHas = result
// Do some more B-specific stuff
}
}
var ins1: any P = A()
var ins2: any P = B()
ins1.frobnicate();
ins2.frobnicate();
In this example, the frobnicate in the protocol extension is called, because it's defined only in the protocol extension.
For ins1, frobnicate then calls the extension's prepareToFrobnicate, because even though it's declared directly in the protocol, A doesn't implement that and a default implementation is provided in the extension.
Then it calls A's actuallyFrobnicate because it's defined directly in the protocol, and A does implement it, so the default implementation isn't used. As a result the onlyAHas property is set.
Then it passes the result from A's actuallyFrobnicate to the finishFrobnication in the extension, because it's defined directly in the protocol, but A doesn't implement it, and the extension provides a default implementation.
For ins2, frobnicate still calls the default prepareToFrobnicate, and then call's B's implementation of actuallyFrobnicate, but B's implementation doesn't set its onlyBHas property there. Instead, it just returns a string, which frobnicate passes to finishFrobnication, which calls B's implementation, because unlike A, B provides its own implementation, and that's where B sets it.
Using this approach, you can simultaneously standardize the general algorithm of a task like frobnicate, while allowing for dramatically different implementation behavior. Of course, in this case, both A and B just set a property in their respective concrete types, but they do it at different phases of the algorithm, and you can imagine adding other code, so that the two effects really would be very different.
The point of this approach is that when we call inst1.frobnicate(), it doesn't know or care about exactly what inst1 is doing internally do accomplish it. The fact that it internally sets the onlyAHas property in the concrete type is an implementation detail the calling code doesn't need to be concerned with.
Just use the concrete type
In your code example, you are creating and using ins1, and ins2 in the same context. So they could just as easily be defined like this:
var ins1 = A()
var ins2 = B()
ins1.onlyAHas = "a only" // <- This is fine because ins1 is an A
ins2.onlyBHas = "b only" // <- This is fine because ins2 is a B
If you have some function, munge that you want to do on both A and B, you can define it terms of the protocol.
func munge(_ p: any P)
{
// In here you can only use `p` as defined by the protocol, `P`
}
If munge needs to do things that depend on concrete-specific properties or methods, you can use one of the previously described approaches...
OR...
If you know for sure that you only will ever have a small number of concrete types conforming to P, which admittedly is sometimes impossible to really know, but occasionally you do, then you can just write specialized overloaded versions of munge for each concrete type:
func munge(_ a: A) {
// Do `A`-specific stuff with `a`
}
func munge(_ b: B) {
// Do `B`-specific stuff with `b`
}
This kind of regresses to older solutions to problems like this. When I say it's an old solution, I'm referring to the fact that even back when the C++ compiler was just a preprocessor that converted C++ source code to C source code which would then be compiled, didn't have templates, and standardization wasn't even on the horizon, it would let you overload functions. You can do that with Swift too, and it's a perfectly valid solution. Sometimes it's even the best solution. More often it leads to code duplication, but it's in your toolbox to use when it's appropriate.

Using a subclass of a protocol requirement

I'm working on a project that's using MVVM and we'd like to introduce more safety by stopping the caller being able to mutate the objects we're exposing.
We can't make Immutable a struct and just mark mutate() as a mutating, because we add observers which mutates the object that we need in the Immutable form.
This example shows what we'd like to do, but we just get an error that C doesn't confirm to P because we're trying to satisfy the protocol with a subclass of the required Immutable, Mutable
class Immutable {}
class Mutable: Immutable {
func mutate() {}
}
​
protocol P {
var a: Immutable { get }
}
​
class C: P {
let a: Mutable
​
init() {
a = Mutable()
a.mutate()
}
}
Does anyone have a creative solution to this that doesn't require lots of boilerplate to work around, like making a Immutable to satisfy the type requirements and then casting in line like:
class C: P {
let a: Immutable
​
init() {
a = Mutable()
(a as? Mutable)?.mutate()
}
}
This isn't ideal for us because we call mutate() many, many times and don't want to have to refactor all of our code.
Change protocol P to have an associatedtype as below,
protocol P {
associatedtype T: Immutable
var a: T { get set }
}
As you were assigning a value to variable a inside the class that conform to P so variable a declaration changed as above to allow setting a value.
Now, you can define the type inside the conforming class as,
class C: P {
var a: Mutable
init() {
self.a = Mutable()
self.a.mutate()
}
}

Why sub-protocol doesn't fulfill conformance for its parent? [duplicate]

This question already has answers here:
Why can't a get-only property requirement in a protocol be satisfied by a property which conforms?
(3 answers)
Closed 4 years ago.
I have structs that are conforming to protocols, but are using derived protocols, instead of directly using its parent protocol:
protocol A { }
protocol B: A { }
protocol C {
var property: A { get }
}
struct Foo: C {
let property: A
}
struct Bar: C {
let property: B
}
// Error: Type 'Bar' does not conform to protocol 'C'
Why doesn't Bar fulfill the conformance because property is a sub-protocol of A.
B describes a type that conforms to some set of rules. It is not itself a type that conforms to those rules. B does not conform to B, let alone anything it requires additional conformance to. protocol B:A says "anything that conforms to B also must conform to A." However, B does not conform to B, and so does not conform to A.
This has been answered many times on SO, but to repeat the "why," it comes down most simply to this example:
protocol A {
init()
}
func f(type: A.Type) {
let a = type.init()
}
f(type: A.self)
If A itself conforms to A, then this should be legal. But what init should f call? In the presence of init and static requirements, it's not possible for protocols to conform to themselves.
While the specific covariance you want in this case is possible in principle, Swift doesn't have the ability to distinguish between legal and illegal covariance, and disallows all of it. For example, consider the small variation from immutable to mutable:
protocol C {
var property: A { get set }
}
In this case, it is definitely impossible for Bar to conform (it would have to provide a setter for property that accepted any A, even though the getter would return a subtype of A). Swift is not able to distinguish all the cases where it is possible (generally when everything is immutable and there are no init or static requirements) from the cases where it isn't. There's been some discussion of allowing these kinds of cases where it's technically possible, but the concern is that very small changes to the protocol could then break your entire type structure, sometimes for non-obvious reasons. Instead, at least for now, type requirements are generally invariant.
A typical way to address this overall issue is to just provide accessors for the types you want. For example:
protocol A { }
protocol B: A { }
protocol C {
var aProperty: A { get }
}
struct Foo: C {
let aProperty: A
}
struct Bar: C {
var aProperty: A { return bProperty }
let bProperty: B
}
This provides greater flexibility (you can make bProperty a var if you like), and makes your code more explicit.

Usage of Generics

I have the following structs:
struct A<T> {
var val: T
}
struct B<T> {
var setOfA: Set<A<T>>
}
Is this incorrect usage of generics, if the set of As can have values of both A<Int> and A<Float> type (or any other type)?
If yes, is using Any the correct way to do this?
Would generics have been the right way to go, if the set of As was constrained to A<>s of a single type?
Swift is a moving target, all code tested using Xcode 9.2 & Swift 4.0.
First if you wish to insert A<T> items into a set then the type must implement the Hashable protocol. You can implement this protocol as needed but for illustrative purposes a simple approach is to require the type parameter T to be Hashable and to implement the protocol by indirecting to val:
struct A<T> : Hashable where T : Hashable
{
var val : T
var hashValue: Int { return val.hashValue }
static func ==(lhs: A<T>, rhs: A<T>) -> Bool
{
return lhs.val == rhs.val
}
}
The rest of the answer does not require the above implementation, just that A<T> is Hashable.
Constraining your Set to only containing instances of A<T> for any and all T is more of a challenge. One approach to this problem is to use an existential type, which in this context essentially allows the wrapping of differently typed value inside another non-generic wrapper. Swift has some pre-defined existential types, in particular AnyHashable which you could use to define B's var:
struct B
{
var setOfA : Set<AnyHashable> = Set()
...
}
Unfortunately this does not constrain the set to only hold values of type A<T> for any T.
The type of setOfA cannot be Set<A<AnyHashable>> as that would require a value of type A<T> for some T to be cast-able to A<AnyHashable> and Swift does not support that (researching variance might help understand why).
You might wonder why the type cannot be Set<Hashable>. Unfortunately (in this context!) Hashable is a protocol with a Self requirement and Swift does not support using it as a generic type parameter in this context. AnyHashable is a non-generic struct which type erases (the existential type bit) the value it wraps.
So back to solving the problem of constraining the set to only contains A's. One solution is to hide (private) the set inside B and provide a generic insertion function which only accepts A<T> values, for any T. The set value itself can then be made public using a read-only computed property. For example:
struct B
{
// private property so only B's functions can modify the set
private var _setOfA : Set<AnyHashable> = Set()
// public read-only property so _setOfA cannot be changed directly
var setOfA : Set<AnyHashable> { return _setOfA }
// public insert function which only accepts A<T> values, for any T
mutating func insert<T>(_ element : A<T>) -> (Bool, A<T>)
{
return _setOfA.insert(element)
}
}
Here is dome sample code using the above:
let x = A(val: 4) // x : A<Int>
let y = A(val: "hello") // y : A<String>
var z = B()
print(z.insert(x)) // insert being generic accepts any A<T>
print(z.insert(y))
print(z.insert(x)) // should return (false, x) as element already added
print("\(z)")
for member in z.setOfA
{
print("member = \(member) : \(type(of:member))")
if let intMember = member as? A<Int>
{
print(" intMember = \(intMember) : \(type(of:intMember))")
}
else if let stringMember = member as? A<String>
{
print(" stringMember = \(stringMember) : \(type(of:stringMember))")
}
}
This outputs:
(true, __lldb_expr_501.A<Swift.Int>(val: 4))
(true, __lldb_expr_501.A<Swift.String>(val: "hello"))
(false, __lldb_expr_501.A<Swift.Int>(val: 4))
B(_setOfA: Set([AnyHashable(__lldb_expr_501.A<Swift.String>(val: "hello")), AnyHashable(__lldb_expr_501.A<Swift.Int>(val: 4))]))
member = A<String>(val: "hello") : AnyHashable
stringMember = A<String>(val: "hello") : A<String>
member = A<Int>(val: 4) : AnyHashable
intMember = A<Int>(val: 4) : A<Int>
HTH
If you plan on letting your struct contain val of a specific type, use <T: DesiredProtocol>. If the type doesn't matter, and your val can be of any type, just implement the structure as struct A<T> {}. A<T> is equal to A<T: Any>.
Note that your example won't compile if you intend to have setOfA contain A with different types.
The elements in a Set must be hashable.
In B<T>, T represents only one type. Therefore, you cannot store different types in Set<A<T>>.
Because of this requirement, struct A<T> must conform to the Hashable protocol, and the implementation of B must be changed.
struct A<T>: Hashable {
var val: T
// Implementation of Hashable
}
/// This struct should not be generic. It would constrain its setOfA to only contain the same type.
/// By removing the generics, and use Any instead, you let each element have its own type.
struct B {
var setOfA: Set<A<Any>>
}
var set: Set<A<Any>> = Set()
set.insert(A(val: 0 as Int))
set.insert(A(val: 1 as Float))
let b = B(setOfA: set)
Edit:
Due to the fact that you're looking for a way to insert a generic A<T> into A<Any> without specifying its type as A<Any> on creation, I've come up with two different ways:
let v1 = A(val: 5)
var v2 = A(val: 3)
aSet.insert(A(val: v2.val))
aSet.insert(withUnsafePointer(to: &v3, { return UnsafeRawPointer($0) }).assumingMemoryBound(to: A<Any>.self).pointee)
Edit
If it is as you write, that B's setOfA would only have A<> of a single type, it's the choice of the context whether you should use generics or not. The question is rather if struct B needs to be generic. struct A can be a value type for many different tasks, while struct B doesn't need to. If B is more specific, you could rather just write:
struct B {
var setOfA: Set<A<Int>>
}
As above-mentioned, if you intend to have the same set contain A<Int> and A<Float>, then var setOfA: Set<A<Any>> is the correct way.
If struct A has a very specific use-case, and you don't actually need it to be generic, you should change the type of val. Your code should be understandable and comprehensive. I would recommend one of these solutions:
struct A: Hashable {
var val: Any
// or
var val: Numeric
// Implementation of Hashable
}

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.