Is there a way to set a typealias of a protocol's associated type in a sub protocol? - swift

I didn't see this in the similar questions, so I think this is unique. I have a protocol
protocol Zot {}
protocol Foo {
associatedType Bar: Zot
var prop1: Bar { get set }
}
Now I could say
class Zoty: Zot {}
class Fooy: Foo {
typealias Bar = Zoty
var prop1: Zoty = Zoty()
}
But I haven't quite moved to the class layer yet. Is there a way for me to set the type alias in a protocol like so?
protocol Fooie: Foo {
typealias Bar = Zoty
var prop1: Zoty { get set }
}
The compiler says to make it like this
protocol Fooie: Foo where Bar == Zoty {
var prop1: Bar { get set }
}
But then it throws the error Cannot override mutable property 'prop1' of type 'Self.Bar' with covariant type 'Zoty'

To fix the error, just remove this line in Fooie
var prop1: Bar { get set }
You do not need to redeclare this again, and I do agree the error message is a bit confusing. Swift thinks that you are trying to override the property, which as far as it is concerned, is declared to be a different type, but in this context, the two types can only be the same.
After removing the property, you can now do:
class Fooy: Fooie {
var prop1 = Zoty()
}
and this gives errors
class SomethingElse: Zot {}
class Fooy: Fooie {
var prop1 = SomethingElse()
}
'Fooie' requires the types 'SomethingElse' and 'Zoty' be equivalent
Type 'Fooy' does not conform to protocol 'Fooie'

Related

How to correctly use generics with protocols and different types?

I have the script below written in Swift 5 and I am doing something wrong to configure the generics.
Basically it's a Foo protocol with a function with has an argument with a generic type and it's implemented in both Fez and Foz, where the type of the bar function is defined in the class definition. By using associatedtype is possible to fix this?
Any idea of what could be and how to solve it? Am I doing something wrong with the setup of generics? I need to support both Int and String.
protocol Foo {
func bar<T>(zed: T)
}
class Fez: Foo {
private var zed: Int = 0
func bar<Int>(zed: Int) {
self.zed = zed //Cannot assign value of type 'Int' to type 'Swift.Int'
}
}
class Foz: Foo {
private var zed: String = ""
func bar<String>(zed: String) {
self.zed = zed //Cannot assign value of type 'String' to type 'Swift.String'
}
}
Thank you very much.
For the downvoter: I hope you have a nice day.
A generic like this says that the caller can choose any type to pass to bar, and the implementation will handle it. You mean that the implementation gets to decide what type it can be passed, and that's an associatedtype as you suggest.
protocol Foo {
associatedtype Zed
func bar(zed: Zed)
}
class Fez: Foo {
private var zed: Int = 0
func bar(zed: Int) {
self.zed = zed
}
}
class Foz: Foo {
private var zed: String = ""
func bar(zed: String) {
self.zed = zed
}
}

Protocol only implemented by struct or immutable

I have a class A that holds an object B implementing the protocol P.
I would like to forbid any modification to object B without class A acknowledging it. Is it possible without any delegate or mutual reference?
Considering that it is possible to specify a protocol that can only be implemented by class type objects protocol P: class {} , if there is something similar for structs, I could bind the protocol to a struct, makeing it explicit (being known that structs are passed by value) that the object B has to be set but not edited.
Long story short:
Is there a way to force a protocol implementation to be a struct?
The only I would suggest is to wrap class A by a protocol Q and define a variable setter of an instance of protocol P inside.
protocol Q {
var p: P? { get set }
}
class A : Q {
var p: P? {
get {
// logic
}
set {
//logic
}
}
}
Protocols shouldn't be used this way. Protocols is to define behaviour, not the exact shape of object.
I assume by restricting protocol to structs you want to achieve immutability of it's implementers. If so we can design protocol with getters only
protocol Foo {
var foo: string { get }
}
This way Foo is immutable and it's can't be changed from anywhere no matter if it's struct or class.
Then, we can inherit FooMutable from Foo and add mutators there
protocol FooMutable: Foo {
var foo: string { get set }
}
Finally class A is the only place where we can mutate Foo:
class A {
private var fooValue: FooMutable = FooImpl()
var foo: Foo { get { return fooValue } }
func mutateFoo() {
fooValue.foo = "bar"
}
}
class FooImpl: FooMutable {
var foo = "foo"
}

Specialize generic function requirement on protocol inheritance

I have some protocol hierarchies on my code where I have protocols defining the objects I use and protocols defining functions to use with this objects.
The object protocols are inherited by other object protocols that add more functionality to the original protocols and so are the functions that use them. The problem is that I can't find a way to specialize the function to take only the inherited parameter.
Here's some code to clarify what I'm trying to do:
protocol A {
var foo: String { get set }
}
protocol B: A {
var bar: String { get set }
}
struct Test: B {
var foo: String = "foo"
var bar: String = "bar"
}
protocol UseAProtocol {
static func use<T: A>(_ obj: T)
}
protocol UseBProtocol: UseAProtocol {
}
extension UseBProtocol {
//If I change the requirement to <T: B> this won't conform to `UseAProtocol`.
static func use<T: A>(_ obj: T) {
print(obj.foo)
// print(obj.bar) - Since obj does not conform to `B` I can't access ".bar" here without a forced casting.
}
}
struct Manager: UseBProtocol {
}
Manager.use(Test())
What I want to do is make the use function on the UseBProtocol only accept objects that conform to B. B inherits from A, but when I change from <T:A> to <T:B> I got an error saying that Manager does not conform to UseAProtocol and I have to change it back to <T:A>.
I know I can do this using associatedtype and where clauses on the inherit protocols - that's what I use today - but I wanted to move the generic requirement to the method so I could group all of them together under the same struct (I have a lot of this hierarchies and by using associatedtype I must use one struct by hierarchy). When the Conditional Conformances came to Swift this would be possible with associatedtype, but until them...
I could also use as! to force the casting from A to B on the UseBProtocol implementation, but that's a really bad solution and the error would be throw only at runtime.
Is there any way to achieve what I'm looking for?
It seems like what you are actually looking for is an associatedType in UseAProtocol rather than making the use function generic.
By declaring an associated type in UseAProtocol and changing the function signature of use to static func use(_ obj: ProtocolType) your code compiles fine and you can access both foo and bar from Manager.
protocol AProtocol {
var foo: String { get set }
}
protocol BProtocol: AProtocol {
var bar: String { get set }
}
struct Test: BProtocol {
var foo: String = "foo"
var bar: String = "bar"
}
protocol UseAProtocol {
associatedtype ProtocolType
static func use(_ obj: ProtocolType)
}
protocol UseBProtocol: UseAProtocol {
}
extension UseBProtocol {
static func use(_ obj: BProtocol) {
print(obj.foo)
print(obj.bar)
}
}
struct Manager: UseBProtocol {
}
Manager.use(Test()) //prints both "foo" and "bar"

Cannot assign to generic property in protocol

I'd like to know if there's something simple that I'm missing here in this code or if it's just a mix of Swift trickeries that are preventing me from doing what I want.
I'm allowing types implementing the Foo protocol to contain an entity property of any type, as long as it conforms to StringIdentifiable:
protocol StringIdentifiable {
var id: String? { get }
}
protocol Foo: class {
associatedtype AnyStringIdentifiable: StringIdentifiable
var entity: AnyStringIdentifiable? { get set }
}
As of Swift 3.1, this "any type" part wouldn't be possible if not using the associatedtype. Going ahead, let's say I have another protocol that requires a Foo property. However, Foo is generic, so as you may know we can't do that because "generic protocols can only be used as a generic constraint". Trying to avoid the type erasure mess, I decided to use another associatedtype in my second protocol and the compiler doesn't complain:
protocol Bar {
//var foo: Foo { get set } // can't do because Foo is generic
associatedtype AnyFoo: Foo
var foo: AnyFoo { get set }
}
But now, if I try to set something in foo, the compiler will complain:
extension Bar {
func setEntity(_ entity: StringIdentifiable) {
foo.entity = entity
}
}
The error is Cannot assign value of type 'StringIdentifiable' to type '_?'
Note: this question's code is testable in a playground.
You can do it like this
//: Playground - noun: a place where people can play
import Cocoa
protocol StringIdentifiable {
var id: String? { get }
}
protocol Foo: class {
associatedtype AnyStringIdentifiable: StringIdentifiable
var entity: AnyStringIdentifiable? { get set }
}
protocol Bar {
//var foo: Foo { get set } // can't do because Foo is generic
associatedtype AnyFoo: Foo
var foo: AnyFoo { get set }
}
extension Bar {
func setEntity(_ entity: AnyFoo.AnyStringIdentifiable) {
foo.entity = entity
}
}
Within Bar you can use AnyFoo.AnyStringIdentifiable to make sure the types are correct when setting foo.entity, because foo.entity is of the type AnyFoo.AnyStringIdentifiable.

readonly mutable fields in Swift

When defining a class in Swift, you can have var properties which are like normal fields in other OOP languages, but also let properties which are both read-only and immutable (like T const * const in C++).
However is there a Swift equivalent of C++'s T * const? (That is, the field itself is immutable, but the object it points to is mutable)?
Here's a representation of my scenario:
class Foo {
let bar: Bar
init(bar: Bar) {
self.bar = bar
}
}
protocol Bar {
var fleem: Int? { get set }
}
class ConcreteBar : Bar {
var fleem: Int? = nil
}
var foo: Foo = Foo( bar: ConcreteBar() )
foo.bar.fleem = 123
(Playground link: https://iswift.org/playground?3jKAiu&v=2 )
Presently this gives me this compiler error:
Swift:: Error: cannot assign to property: 'bar' is a 'let' constant`
foo.bar.fleem = 123
Note that I am not actually setting bar, I'm only setting bar.fleem. I don't know why the compiler is complaining about assigning to bar.
If I change Foo to use this:
class Foo {
var bar: Bar
// ...
...then it compiles okay, but then I lose the guarantee that Foo.bar always has the same instance.
I know I could also change it to private(set):
class Foo {
public private(set) var bar: Bar
// ...
...but Foo itself is still free to overwrite the bar object-reference, and the use of var means that the compiler cannot assume the reference is immutable either, so some optimizations may be skipped.
I'm looking for something like a hypothetical let mutable or var readonly keyword or modifier.
By default, protocol typed objects have value value semantics. As a consequence, they're not mutable if the variable is a let constant.
To introduce reference semantics (and by extension, the mutability of objects referred to be a let constant), you need to make your protocol into a class protocol:
protocol Bar: class {
var fleem: Int? { get set }
}
You need to add the class attribute to the protocol to make it reference type compliant:
protocol Bar : class { ...