Kotlin define interface for enum class values method - class

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()
}
}

Related

Does Kotlin has extension class to interface like Swift

In Swift, we could extend a class with an interface as below
extension MyExtend {
public var type: String { return "" }
}
extension MyOrigin: MyExtend {
public var type: ListItemDataType {
return "Origin"
}
}
Do we have that capability in Kotlin? (e.g. extend an interface)
Yes, Kotlin does have Extensions — similar to Swift.
Swift:
class C {
func foo(i: String) { print("class") }
}
extension C {
func foo(i: Int) { print("extension") }
}
C().foo(i: "A")
C().foo(i: 1)
Kotlin:
class C {
fun foo(i: String) { println("class") }
}
fun C.foo(i: Int) { println("extension") }
C().foo("A")
C().foo(1)
Output:
class
extension
There are some key differences you'll want to read up on.
Extensions do not actually modify classes they extend. By defining an
extension, you do not insert new members into a class, but merely make
new functions callable with the dot-notation on variables of this
type.
We would like to emphasize that extension functions are dispatched
statically, i.e. they are not virtual by receiver type. This means
that the extension function being called is determined by the type of
the expression on which the function is invoked, not by the type of
the result of evaluating that expression at runtime.
↳ https://kotlinlang.org/docs/reference/extensions.html

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"
}

Not specifying type in generic for Swift class

Let's say we have one protocol:
protocol Animal {
}
two class which implement this protocol:
class Dog: Animal {
}
class Bear: Animal {
}
and generic which uses this protocol:
class A<T: Animal> {
}
Now I can create another classes:
class B: A<Dog> {
}
class C: A<Bear> {
}
I hope you understand case. And now we have protocol which has instance of class A as parameter:
protocol SomeProtocol {
func something(a: A)
}
and I want to implement this protocol in class e.g. D.
class D: SomeProtocol {
func something(a: A) {
}
}
But it won't compile because we have to specify generic for A, how can we do that if we want to send in this parameter instance of class B or C? Can I somehow omit generic in this function?
Can I somehow omit generic in this function?
No, you currently cannot talk in terms of a generic type without its placeholder(s). However, you can simply introduce a new local generic placeholder to the function, allowing the placeholder to be satisfied at the call-site.
protocol SomeProtocol {
func something<T>(a: A<T>)
}
class D : SomeProtocol {
func something<T>(a: A<T>) {
// ...
}
}
In the case of passing in an instance of B, T will be Dog. In the case of passing in an instance of C, T will be Bear.

How to define func to a specific case of Enum in 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!

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.