What is the best way to unite to unrelated types under one protocol, e.g. to use that new type as an element type for an array?
e.g.:
Third-party-provided class Foo and class Bar are unrelated, however, I would like to create an array which contains elements of types Foo and Bar. Note that I can't change the implementation of Foo and Bar directly.
One approach might be:
protocol FooBar {}
extension Foo: FooBar {}
extension Bar: FooBar {}
However, this strikes me as odd and rather unappealing, since there are no implementations – are there other ways?
I will enumerate through that array and process the Elements knowing that it can be either Foo or Bar inside.
Not the answer directly to your question, but given that you only want to iterate through the array that contains Foos and Bars you could use enum like:
enum FooBar {
case WrappedFoo(Foo)
case WrappedBar(Bar)
}
This will at least save you from having to do as? with every element in order to get the exact type you are dealing with.
Example:
// Some setup
var arr: [FooBar] = []
let foo = Foo()
let bar = Bar()
arr.append(.WrappedFoo(foo))
arr.append(.WrappedFoo(foo))
arr.append(.WrappedBar(bar))
arr.append(.WrappedFoo(foo))
arr.append(.WrappedBar(bar))
arr.append(.WrappedBar(bar))
// Enumeration
arr.forEach {
switch $0 {
case .WrappedFoo(let foo):
// do something with `foo`
case .WrappedBar(let bar):
// do something with `bar`
}
}
Related
I've read the documentation, and seen perhaps only a part of what the protocol is. I just am not following the logic. Can someone help me understand this?
What I see in xcode when I examine the protocol
/// Conforming to the CaseIterable Protocol
/// =======================================
///
/// The compiler can automatically provide an implementation of the
/// `CaseIterable` requirements for any enumeration without associated values
/// or `#available` attributes on its cases. The synthesized `allCases`
/// collection provides the cases in order of their declaration.
///
/// You can take advantage of this compiler support when defining your own
/// custom enumeration by declaring conformance to `CaseIterable` in the
/// enumeration's original declaration. The `CompassDirection` example above
/// demonstrates this automatic implementation.
public protocol CaseIterable {
/// A type that can represent a collection of all values of this type.
associatedtype AllCases : Collection = [Self] where Self == Self.AllCases.Element
/// A collection of all values of this type.
static var allCases: Self.AllCases { get }
}
I'm struggling to follow what is happening here and why. Can someone walk me through the logic of this please?
One of the other big struggles I'm having because of this is if I conform a protocol to be CaseIterable.
protocol Foo: CaseIterable {}
I can't use it as a variable anymore.
struct Bar {
var foo: Foo
}
I get this error
Protocol 'Foo' can only be used as a generic constraint because it has Self or associated type requirements.
It does have Self requirements but I can't figure out how to get around this problem. If someone could help me understand why this happens and how to fix it too, I'd be very grateful.
Edit: - This is the playground code copied directly. I've updated it to use the some, but I'm not quite sure how to proceed past this error.
import Foundation
protocol Zot: CaseIterable {
var prop: Data { get }
}
enum Bar: Zot {
case thing3
case thing4
var prop: Data {
switch self {
case .thing3, .thing4: return Data()
}
}
init() {}
}
enum Baz: Zot {
case thing1
case thing2
var prop: Data {
switch self {
case .thing1, .thing2: return Data()
}
}
init() {}
}
enum Foo {
case bar
case baz
var otherValues: some Zot {
switch self {
case .bar:
return Bar
case .baz:
return Baz
}
}
}
CaseIterable exists to allow you to programmatically walk through all the possible cases of an enum, allowing you use the enum type as a Collection of its cases:
enum CardinalDirection: CaseIterable { case north, south, east, west }
for direction in CardinalDirection.allCases {
// Do something with direction which is one of north, south, east, west
print("\(direction)")
}
This prints
north
south
east
west
There is nothing that prevents you from making other kinds of types conform to CaseIterable; however, the compiler will only synthesize conformance for enum types. It's not useful for most other kinds of types; however, I have occasionally found it useful for types that conform to OptionSet. In that case you have to manually implement conformance.
struct AssetFlags: OptionSet, CaseIterable
{
typealias RawValue = UInt8
typealias AllCases = [AssetFlags]
let rawValue: RawValue
static let shouldPreload = AssetFlags(rawValue: 0x01)
static let isPurgeable = AssetFlags(rawValue: 0x02)
static let isLocked = AssetFlags(rawValue: 0x04)
static let isCached = AssetFlags(rawValue: 0x08)
static var allCases: AllCases = [shouldPreload, isPurgeable, isLocked, isCached]
}
Note that OptionSet is conceptually similar to an enum. They both define a small set of distinct values they can have. With one they are mutually exclusive, while for the other they may be combined. But the key thing for CaseIterable to be useful is the finite nature of the set of possible distinct values. If your type has that characteristic, conforming to CaseIterable could be useful, otherwise, it wouldn't make sense. Int or String, for example, are not good candidates for CaseIterable.
In my own code, I don't bother conforming to CaseIterable, even for enum types, until a specific need arises that requires it. Actually I take that approach to all protocol conformance. It's a specific case of the more general YAGNI rule of thumb: "You ain't gonna need it."
Regarding your Bar struct, the problem is not specifically related to CaseIterable, but rather to using a protocol with Self or associated type requirements, which for Foo happens to be inherited from CaseIterable.
Swift 5.7 relaxed the rules concerning Self and associated type requirements a bit, allowing you to use the any keyword to tell the compiler you want to use an existential Foo instead of a concrete Foo to write
struct Bar {
var foo: any Foo
}
If you want a concrete Foo you could use some. The original way to do it though, which still works, is to make Bar explicitly generic
struct Bar<T: Foo> {
var foo: T
}
Update based on revised question code
The way you're using enums is... well, let's say it's out of the ordinary. There are two problems. The first is that you're returning types not values:
enum Foo {
case bar
case baz
// Will return a *value* of a type that conforms to Zot
var otherValues: some Zot
{
switch self {
case .bar:
return Bar // Bar is a *type* not a value
case .baz:
return Baz // Baz is a *type* not a value
}
}
}
I'll fix this is in a way that is almost certainly wrong for what you want to do, but allows moving forward to the other problem. We need to return values, so I'll just pick the first of the corresponding cases of Bar and Baz, and that will expose the other problem.
enum Foo {
case bar
case baz
var otherValues: some Zot
{
switch self {
case .bar: return Bar.thing3
case .baz: return Baz.thing1
}
}
}
The problem here is that some means that there will be one specific concrete type that conforms to Zot, so the compiler will be able to access its properties and methods directly rather than via its protocol witness table... it's basically a way to have the efficiency of having the calling code use the concrete types without having to tie to calling code to the concrete type at the source code level. otherValues, however, returns a value of either of two types, so the return type would have to be an existential type rather than a concrete one. You could do this if you return any Zot instead of some Zot.
Of course even using any, this version is wrong, because it doesn't take into account half of the cases of Bar and Baz. I assume that you want to be able to construct a Foo from a Bar or Baz while preserving its original value somehow, and I guess retrieve it later.
Before I present solutions, I want to mention that without knowing exactly what you are trying to accomplish, your code feels like it took a wrong design turn at some point. It would probably be better to rethink how you're doing what you want to do to see if there is a better way.
If I understand what your trying to do, I can think of at least three of ways, none of which requires CaseIterable, but maybe that's needed for other reasons.
Option 1
The first is to define Foo so that it explicitly contains all of the cases of Bar and Baz:
enum Foo: Zot
{
case thing1, thing2, thing3, thing4
init(_ value: Bar)
{
switch value
{
case .thing3: self = .thing3
case .thing4: self = .thing4
}
}
init(_ value: Baz)
{
switch value
{
case .thing1: self = .thing1
case .thing2: self = .thing2
}
}
var prop: Data
{
switch self
{
case .thing1: return Baz.thing1.prop
case .thing2: return Baz.thing2.prop
case .thing3: return Bar.thing3.prop
case .thing4: return Bar.thing4.prop
}
}
var bazValue: Baz?
{
switch self
{
case .thing1: return .thing1
case .thing2: return .thing2
default: return nil
}
}
var barValue: Bar?
{
switch self
{
case .thing3: return .thing3
case .thing4: return .thing4
default: return nil
}
}
}
This has the advantage of being straight-forward, but will require more maintenance if you add/remove cases from Bar or Baz - or even add a whole other enum that conforms to Zot.
Option 2
The second way is to define Foo so that it uses associated values:
enum Foo
{
case bar(value: Bar)
case baz(value: Baz)
init(_ value: Bar) { self = .bar(value: value) }
init(_ value: Baz) { self = .baz(value: value) }
}
I think this second case is cleaner, and you don't need otherValues because usage code can do:
switch foo
{
case let .bar(value: bar):
// do whatever with bar
case let .baz(value: baz):
// do whatever with baz
}
Still assuming second version of Foo, maybe an even cleaner way is:
extension Foo
{
func withZotValue<R>(_ code: (any Zot) throws -> R) rethrows -> R
{
switch self
{
case let .bar(value: value): return try code(value)
case let .baz(value: value): return try code(value)
}
}
}
That allows you to eliminate a lot of switch statements in usage code. To use it:
foo.withZotValue { zotValue in
// Do something with zotValue that the Zot protocol supports.
}
If you need this second version of Foo to conform to CaseIterable, Swift won't synthesize conformance for you because of the associated values, but you can write the conformance yourself.
extension Foo: CaseIterable
{
typealias AllCases = [Self]
static var allCases: AllCases {
[
Baz.allCases.map { .baz(value: $0) },
Bar.allCases.map { .bar(value: $0) },
].joined()
}
}
Option 3:
The last possible solution, which actually should probably be the first, if it applies, would be to define whatever you're trying to do that's common to both Bar and Baz in Zot. Whether that's a good idea or not depends on what you're trying to do, but let's assume it does make sense. For example, I notice that both Bar and Baz support a prop property, but the Zot protocol doesn't list prop. Why not? Is it unrelated to "Zotness"? If anything that conforms to Zot should have a prop property, then add it to the protocol:
protocol Zot: CaseIterable {
var prop: Data { get }
}
You still provide implementations of prop in Bar and Baz - that's kind of like overriding a base class method in subclasses.
Let's say the Data returned from prop is encoded JSON and you want be able to decode a Codable thing from a Zot. You can now do that without caring if its a Bar or a Baz (or any other new Zot-conforming type you might add later):
func decode<T: Codable>(_ type: T.Type, from src: some Zot) throws -> T {
return try JSONDecoder().decode(T.self, from: src.prop)
}
I've got a toy example here that I can't find any solutions for online.
protocol Tree {
associatedtype Element
// some nice tree functions
}
class BinaryTree<T> : Tree {
typealias Element = T
}
class RedBlackTree<T> : Tree {
typealias Element = T
}
enum TreeType {
case binaryTree
case redBlackTree
}
// Use a generic `F` because Tree has an associated type and it can no
// longer be referenced directly as a type. This is probably the source
// of the confusion.
class TreeManager<E, F:Tree> where F.Element == E {
let tree: F
init(use type: TreeType){
// Error, cannot assign value of type 'BinaryTree<E>' to type 'F'
switch(type){
case .binaryTree:
tree = BinaryTree<E>()
case .redBlackTree:
tree = RedBlackTree<E>()
}
}
}
I'm not sure what the problem here is or what I should be searching for in order to figure it out. I'm still thinking of protocols as I would interfaces in another language, and I view a BinaryTree as a valid implementation of a Tree, and the only constraint on F is that it must be a Tree. To confuse things even more, I'm not sure why the following snippet compiles given that the one above does not.
func weird<F:Tree>(_ f: F){ }
func test(){
// No error, BinaryTree can be assigned to an F:Tree
weird(BinaryTree<String>())
}
Any pointers or explanations would be greatly appreciated.
I don't understand the context of the situation this would be in. However, I have provided two solutions though:
1:
class Bar<F:Foo> {
let foo: FooClass.F
init(){
foo = FooClass.F()
}
}
2:
class Bar<F:Foo> {
let foo: FooClass
init(){
foo = FooClass()
}
}
What you are currently doing doesn't make logical sense, to whatever you are trying to achieve
I don't know what are you trying for, but of course it's not possible to do that. from your example, you attempt to create Bar class with generic. and that not the appropriate way to create a generic object, because the creation of generic object is to make the object to accept with any type.
Here's some brief explanation of the generic taken from Wikipedia.
On the first paragraph that says, "Generic programming is a style of computer programming in which algorithms are written in terms of types to-be-specified-later that are then instantiated when needed for specific types provided as parameters."
it's very clear about what are the meaning of to-be-specified-later, right :)
Back to your example :
class Bar<F: Foo> {
let foo: F
init() {
// Error, cannot assign value of type 'FooClass' to type 'F'
foo = FooClass()
}
}
From the above code, it is type parameter F which has a constraint to a type Foo. and, you try to create an instance for foo variable with a concrete implementation, that is FooClass. and that's not possible since the foo variable is a F type(which is abstract). of course we can downcast it, like this foo = FooClass() as! F, but then the foo is only limited to FooClass, so why even bother with generic then ?
Hope it help :)
Your approach to this is wrong. In your original example, you would have to specify the type of both the element (E) and the container (BinaryTree or RedBlackTree), in addition to the enum value. That make no sense.
Instead, you should construct the manager to take a tree as the constructor argument, allowing Swift to infer the generic arguments, i.e.
class TreeManager<E, F: Tree> where F.Element == E {
var tree: F
init(with tree: F) {
self.tree = tree
}
}
let manager = TreeManager(with: BinaryTree<String>())
Alternatively, you should look into using opaque return types in Swift 5.1 depending on what the final goal is (the example here is obviously not a real world scenario)
Something like this seems reasonable. The point was to try and have some piece of logic that would determine when the TreeManager uses one type of Tree vs another.
protocol TreePicker {
associatedtype TreeType : Tree
func createTree() -> TreeType
}
struct SomeUseCaseA<T>: TreePicker {
typealias TreeType = RedBlackTree<T>
func createTree() -> TreeType {
return RedBlackTree<T>()
}
}
struct SomeUseCaseB<T>: TreePicker {
typealias TreeType = BinaryTree<T>
func createTree() -> TreeType {
return BinaryTree<T>()
}
}
class TreeManager<T, Picker: TreePicker> where Picker.TreeType == T {
let tree: T
init(use picker: Picker){
tree = picker.createTree()
}
This introduces another protocol that cares about picking the tree implementation and the where clause specifies that the Picker will return a tree of type T.
I think all of this was just the result of not being able to declare the tree of type Tree<T>. Its a bit more verbose but its basically what it would have had to look like with a generic interface instead. I think I also asked the question poorly. I should have just posted the version that didn't compile and asked for a solution instead of going one step further and confusing everyone.
protocol Foo {
associatedtype F
}
class FooClass : Foo {
typealias F = String
}
class Bar<M:Foo> {
let foo: M
init(){
foo = FooClass() as! M
}
}
Let's say I have an array of type Foo with FooBar objects in it.
Bar <T> class is a generic class that inherits from Foo.
Then I have multiple FooBar classes, that inherits from Bar<T>, each with different generic type. (Bar<Int>, Bar<String>).
The problem is that I need to walk through the array of type Foo, check if na object is of type Bar<T>, cast it to Bar and set it's property.
Buty Swift won't allow me to cast to unknown type <T> and Bar<Any> doesn't match Bar<Int> or another...
I came up with two possible solutions - add new class to the hierarchy that inherits from Foo and is parent of Bar, but is not generic, and cast to this one or implement a protocol (which seems as much better solution).
What I'm really not sure about is if protocols are meant for this kind of stuff. In C-like lang, I would use an interface probably.
//Edit: Sample code
class Foo {
}
class Bar<T> : Foo {
var delegate : SomeDelegate
}
class FooBar: Bar<Int> {
}
class FooBar2: Bar<String> {
}
let arr : [Foo] = [ FooBar(), FooBar2(), Foo() ]
for item in arr {
// this is the problem - I need to match both String,Int or whathever the type is
if let b = item as? Bar<Any> {
b.delegate = self
}
}
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 { ...
I'm trying to store a type in a variable so that I can use it like a 1st class type later on.
class SomeModel {}
let someType = SomeModel.self
let array = Array<someType>()
In this case sure I could have done Array<SomeModel>() instead but I want to generalize it and let subclasses provide the value of someType.
However I get errors like someType isn't a type or use of undeclared type 'someType' on the last line.
If you need to store several type values in array, this works pretty well:
let array: [Any.Type] = [String.self, Int.self]
func someFunc<T>(model: T) -> Array<T> {
let array = Array<T>()
return array
}
let someType = SomeModel.self
let array = someFunc(someType())
Looks like this does what I want. The only drawback is that I have to create an instance of the desired type to pass. In this case its minimal overhead, but it just seems like a waste.
Another thing with using generics like this is it appears that the generic's possible types are computed at compile time, so at run time model.dynamicType doesn't necessarily match T. In most cases it will, but if you are doing any reflection driven stuff make sure to really check your use case well.
These days, this can be more easily and adaptably achieved by using .Type on a class or protocol. Note that only functions available to that root class or protocol will be accessible however, so you should ensure that a required initialiser of some kind is defined. For example:
protocol MyClass {
init(someValue: Int)
}
class MyWrapper {
let myClassType: MyClass.Type
init(classType: MyClass.Type) {
self.myClassType = classType
}
func new(with value: Int) -> MyClassType {
return MyClassType.init(someValue: value)
}
}
You can now initialise this rather silly factory class with a specific class implementing the MyClass protocol and when you call the new() function with an integer value it will generate a new instance of that class and return it.