How to define func to a specific case of Enum in Swift? - swift

enum Type {
case A
case B
func do() {
}
}
I would like do for available for case A

I don't think what you want is possible with enums.
However, it can be done with tricks.
First, create a class called Type:
class Type { private init() {} }
And create two classes, AType and BType to inherit Type:
// Put this in the same file as Type
class AType: Type { private init() {} }
class BType: Type { private init() {} }
The private initializer is to prevent external code to create AType and BType objects.
In Type, add these static properties:
static let A = AType()
static let B = BType()
Then you're basically done!
To add a method that only Type.A is accessible, just add it in the AType class!
This way, just like an enum, Type.A and Type.B can still be assigned to a Type object!

Related

Kotlin define interface for enum class values method

if I define an enum class, let's say:
enum class MyEnum { }
I can do the following as enum class all have a values method:
val values = MyEnum.values()
Now I want my enum to implement an interface and have access to the values() method:
enum class MyEnum : EnumInterface { }
interface EnumInterface {
fun values() : Array<T>
fun doStuff() {
this.values()
}
}
This doesn't compile and I'm sure how to type the values method. Is it possible to define such interface? Thanks!
You were really close to correct answer. You need to define generic interface and you enum should extend it typed with enum's class like this:
enum class MyEnum : EnumInterface<MyEnum> {
A,B,C;
override fun valuesInternal() = MyEnum.values()
}
interface EnumInterface<T> {
fun valuesInternal():Array<T>
fun doStuff() {
this.valuesInternal()
}
}

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"

Swift Implicitly pass self as inout parameter for reference type

Is it possible to implicitly pass self as an inout parameter to modify a reference variable in place?
Here is a method which can convert an abstract base class into one of its concrete subclasses. My question is, must I always have that first argument, obj: inout AbstractBaseClass, or can I implicitly pass self. I realize that this might also be expressed as a static method.
func convertTo(_ obj: inout AbstractBaseClass, _ type: ConcreteClassTypes) {
switch type {
case .concreteClass1: obj = ConreteClass1()
case .concreteClass2: obj = ConcreteClass2()
}
}
Here is the full code:
class AbstractClass {
enum ConcreteType {
case concreteClass1
case concreteClass2
}
var id: Int = 0
fileprivate init() { }
func convert(_ obj: inout AbstractClass, to type: ConcreteType) {
let oldId = obj.id
switch type {
case .concreteClass1: obj = ConcreteClass1()
case .concreteClass2: obj = ConcreteClass2()
}
obj.id = oldId
}
class ConcreteClass1: AbstractClass {
override init() { super.init() }
}
class ConcreteClass2: AbstractClass {
override init() { super.init() }
}
}
var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj.convert(&obj, to: .concreteClass2) //is there any way to eliminate this first argument?
Like matt, I'm not convinced that inout is the right tool for the job in this case.
Although that being said, if you insist on it, one way to achieve what you want is to (ab)use protocol extensions. They allow the definition of mutating methods, which pass the implicit self parameter as inout (to allow the mutation of adopting value types).
So you could say:
protocol AbstractClassProtocol {}
class AbstractClass : AbstractClassProtocol {
enum ConcreteType {
case concreteClass1
case concreteClass2
}
fileprivate init() {}
class ConcreteClass1: AbstractClass {
override init() { super.init() }
}
class ConcreteClass2: AbstractClass {
override init() { super.init() }
}
}
extension AbstractClassProtocol where Self == AbstractClass {
mutating func convert(to type: AbstractClass.ConcreteType) {
switch type {
case .concreteClass1:
self = AbstractClass.ConcreteClass1()
case .concreteClass2:
self = AbstractClass.ConcreteClass2()
}
}
}
var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj.convert(to: .concreteClass2)
print(obj) // AbstractClass.ConcreteClass2
But it's a bit of a hack, and I'd be wary about using it.
...to modify a reference variable in place? Here is a method which can convert an abstract base class into one of its concrete subclasses...
You are not "modifying" or "converting" anything. You are substituting one object for another. Thus, there is no self that could be passed here; the idea of what you are doing is to destroy one self and provide another in its place.
That said, it's a little unclear what the inout variable is for. Why don't you just assign the new object in place of the old object?
func giveMeA( _ type: AbstractClass.ConcreteType) -> AbstractClass {
switch type {
case .concreteClass1: return AbstractClass.ConcreteClass1()
case .concreteClass2: return AbstractClass.ConcreteClass2()
}
}
var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj = giveMeA(.concreteClass2)
The effect is identical to what you're doing. If you think it's not, you're just kidding yourself about what the inout parameter is doing.
I'm going to propose a completely different way of looking at what you're trying to do.
Don't have an abstract superclass. Don't have multiple subclasses. Have one class with multiple functional variants. The functional variants are expressed by a helper object — a struct — owned by the class instance.
So to change functionalities, you just set the helper to a different type of helper. Basically, you give your object a personality transplant.
I have an app that works that way. I have four view controllers that present slightly different info in slightly different ways. But in fact they are one view controller and an enum with four cases that dictates those differences. Thus, at any time the view controller can manifest itself as any of the four types.

How to have a variable with generic typing and multiple inheritance in Swift?

I have this Protocol, Class, and a Class that takes a generic which has to conform to both.
I want to build a registry which holds an array of such classes, but how do I define a variable in the registry which will satisfy the compiler?
Consider this example:
protocol SomeProtocol {
}
class SomeClass {
}
class AnotherClass<R, P where P:SomeProtocol, P:SomeClass> {
}
class Registry {
private init() {}
// This is not allowed since the second generic doesn't conform to neither required class
var registry:[AnotherClass<AnyObject, AnyObject>] = []
}
This is how
import UIKit
protocol SomeProtocol {
}
class SomeClass {
}
class AnotherClass<R, P where P:SomeProtocol, P:SomeClass> {
}
class TheClass : SomeClass, SomeProtocol {}
class Registry {
private init() {}
var registry:[AnotherClass<AnyObject, TheClass>] = []
}
You need to define a class that inherits SomeClass and SomeProtocol. AnyObject doesn't inherit from SomeClass and SomeProtocol and that's why you get an error.
Update
To make it less restritive
This is how
import UIKit
protocol SomeProtocol {
}
class SomeClass {
}
class AnotherClass<R, P where P:SomeProtocol, P:SomeClass> {
}
class TheClass : SomeClass, SomeProtocol {}
class Registry<T, where T:SomeProtocol, T:SomeClass> {
private init() {}
var registry:[AnotherClass<AnyObject, T>] = []
}
Update 2
Eventually, however, you will end up with something like
Registry<TheClass>
because generics needs a concrete class in the end.
What you could do is enforce the type at runtime instead - you will need to add #objc to your protocols though - via is. An alternative would be to scrap generics and use a interface or a base class.