kotlin override property from interface with subtype - interface

I have the following situation:
interface AbstractState {...}
interface SubState {...}
interface NiceInterface {
var currentState: AbstractState
...
}
Furthermore I have a class which implements this interface.
class Class : NiceInterface {
override var currentState: AbstractState = SubState()
}
This implies that I have to write the following at every use of it in the class:
(currentState as SubState).doSomething()
Is there a way to avoid the "as SubState" part? Or some kind of smart way to do it?
Like with generics:
interface => val currentStates: List<out AbstractState>
class => override val currentStates = ArrayList<SubState>()

As Alexey Romanov said the problem with setter, so there is a workaround, replace var by val:
interface AbstractState {}
class SubState : AbstractState{}
interface NiceInterface {
val currentState: AbstractState
}
class Class : NiceInterface {
override val currentState: SubState by lazy {
SubState()
}
}
So now you don't need to cast:
currentState.doSomething()

Related

Kotlin Secondary Constructor and Primary Constructor

class EditorImpl(text: String) : Editor {
private val myDocument: Document
init {
myDocument = DocumentImpl(text)
}
//secondary constructor
constructor(document: Document) : this(document.getText()) {
}
override fun getText(): CharSequence {
return myDocument.getText()
}
override fun setText(text: String) {
myDocument.setText(text)
}
override fun getChars(): CharSequence {
return getText()
}
override fun putChar(chars: CharSequence) {
setText(chars.toString())
}
override fun getDocument(): Document {
return myDocument
}
}
How do I make sure that 'document' parameter passed in the secondary constructor is assigned to 'myDocument' field as every secondary constructor is required to call the primary constructor? I don't want to swap the constructors. Thanks in advance.
You mentioned you don't want to swap the constructors, but if you have no real reason against it, it should definitely be the way to go.
If it makes sense that users can create an instance with a custom document, then this should be the primary constructor because it is the one that defines the most things for the class. The constructor with text is just sugar to automatically create a Document from this text:
class EditorImpl(private val myDocument: Document) : Editor {
constructor(text: String) : this(DocumentImpl(text))
override fun getText(): CharSequence = myDocument.getText()
override fun setText(text: String) {
myDocument.setText(text)
}
override fun getChars(): CharSequence = getText()
override fun putChar(chars: CharSequence) {
setText(chars.toString())
}
override fun getDocument(): Document = myDocument
}
Also as a side note, are Document and Editor defined in Java? This setter/getter approach is not very idiomatic in Kotlin, if these are custom classes/interfaces, consider using Kotlin properties instead.

What is the proper way to code Kotlin's by-clause (a.k.a. Class Delegation) in Swift?

I need to re-code in Swift a Kotlin class defined like this:
class A(private val foo: FooInterface = FooBase()) : FooInterface by foo {
...
}
Is the only way to achieve that is by directly extending the class A with the FooInterface protocol and redirecting all calls to a local private Foo instance?
extension A: FooInterface {
func fooFun1() {
self.privateFooInstance.fooFun1()
}
}
What is the most concise way to do that?
As you already know, Swift does not have direct support for Class Delegation.
So, you may need more code than Kotlin, which has direct support for Delegation. But, instead of extending each class which implements the protocol, you can add default implementation for delegation.
protocol FooInterface {
func fooFun1()
//...
}
protocol FooDelegateable {
var fooDelegate: FooInterface {get}
}
extension FooInterface where Self: FooDelegateable {
func fooFun1() {
self.fooDelegate.fooFun1()
}
//...
}
struct SomeFoo: FooInterface {
func fooFun1() {
print("FooInterface is delegated to SomeFoo.")
}
}
class A: FooInterface, FooDelegateable {
private let foo: FooInterface
//FooDelegateable
var fooDelegate: FooInterface {return foo}
init(_ foo: FooInterface) {
self.foo = foo
}
//...
}
let a = A(SomeFoo())
a.fooFun1() //->FooInterface is delegated to SomeFoo.
How is it?

Setting setter of an interface in class implementing it

Just begin with using kotlin in android-
I am trying to use setter of an interface in a class implementing it-
interface MyInterface {
val prop: Int // abstract
var propertyWithImplementation: String
get() = "foo"
set(text){"$text foo"}
fun foo() {
print(prop)
}
}
class Child : MyInterface {
override val prop: Int = 29
override var propertyWithImplementation="bhu"
}
fun main(args: Array<String>) {
println(Child().propertyWithImplementation)
}
Output:bhu
Expected Output=bhu foo
Where am i going wrong?
You are overriding the var, not setting it, and not using the parent setter in the override, so it ends up not being used in any way. Setting it would look like e.g.
class Child : MyInterface {
override val prop: Int = 29
init {
propertyWithImplementation="bhu"
}
}
but if you do that the output will be foo because that's what the getter always returns. And the setter doesn't actually set anything, it just creates a string and ignores it.
You don't have backing fields in an interface, so you'll need to store the value somewhere else, e.g.
interface MyInterface {
protected var backingProperty: String
var propertyWithImplementation: String
get() = backingProperty
set(text){ backingProperty = "$text foo" }
}
class Child {
override var backingProperty = "foo"
}
to fix this problem.

Overriding val defined in interface by using var with the same name defined in superclass

There is a Base class (var needs to stay protected):
open class Base(protected var id: Int) {}
There is an interface which needs to use val:
interface ProviderI {
val id: Int
}
There is also a class which inherits from Base and implements the ProviderI interface. Within which I'm trying to implement the interface's val using the superclass var (which has the same name).
As a not working example, I'm trying to do something like that (example does not work):
class Instance(id: Int): Base(id), ProviderI {
override val id
get() { return super.id }
}
The idea is simple but I've tried everything and every time different error is reported.
To override a member that is present in several supertypes, Kotlin requires it to be open in all supertypes, and this restriction looks quite natural, because otherwise final members could be easily overridden in this way.
The solution is to make id open in Base as well and to override it as a var property:
open class Base(protected open var id: Int)
interface ProviderI {
val id: Int
}
class Instance(id: Int): Base(id), ProviderI {
override var id: Int
get() = super.id
set(value) { super.id = value }
}
Kotlin does not allow val properties to override var properties.
Closest thing that will work:
open class Base(protected open var id: Int) {}
interface ProviderI {
val id: Int
}
class Instance(id: Int): Base(id), ProviderI {
override var id: Int = 0
get() { return super.id }
}

How can I override superclass property with different type

As title.
I know. I can use [AnyObject] instead of type variable, But I just want to prevent a lots of type checking in swift.
And now, I don't have any idea about this problem. Does anyone can help me. Thanks
class TypeA: NSObject {
var name: String
........
}
class TypeB: TypeA {
.........
}
class ObjectA {
var type = [TypeA]()
}
class ObjectB: ObjectA {
override var type = [TypeB]() <---Cannot override a property "type"
}
Question update: Thanks guys and reference to "R Menke"'s code
class TypeA: NSObject {
override init() {
print("typeA")
}
}
class TypeB: TypeA {
override init() {
print("typeB")
}
}
class ObjectA<T:TypeA> {
var type = [T]()
init(type:T) {
self.type.append(type)
print("objectA")
}
func addNewType() {
let newType = TypeA()
self.type.append(newType) <-- compiler complaints at here
}
}
class ObjectB<T:TypeA>: ObjectA<T> {
override init(type:T) {
super.init(type: type)
print("objectB")
}
}
You can make ObjectA and ObjectB generic classes.
class ObjectA<T:TypeA> {
var type = [T]()
Now the type attribute will always be a TypeA or a subclass of TypeA.
But you no longer need to downcast to find out what type it is.
class TypeA: NSObject {
override init() {
print("typeA")
}
}
class TypeB: TypeA {
override init() {
print("typeB")
}
}
class ObjectA<T:TypeA> {
var type = [T]()
init(type:T) {
self.type.append(type)
print("objectA")
}
}
class ObjectB<T:TypeA>: ObjectA<T> {
override init(type:T) {
super.init(type: type)
print("objectB")
}
}
let tA = TypeA()
let tB = TypeB()
let oA = ObjectA(type: tA) // ObjectA<TypeA>
let oB = ObjectB(type: tB) // ObjectB<TypeB>
Or just make ObjectA generic :
ObjectB will now work as a specialiser for ObjectA, it is not generic itself, but does put a constraint on it's superclass. Now you can use it like any other class but it's type property will have TypeB as type instead of TypeA
class ObjectA<T:TypeA> {
var type = [T]()
init(type:T) {
self.type.append(type)
print("objectA")
}
}
class ObjectB: ObjectA<TypeB> {
override init(type:TypeB) {
super.init(type: type)
print("objectB")
}
}
#RMenke is completely correct here, but it's also important to understand why it's true. This isn't a limitation of Swift. This is a fundamental issue of what subclasses mean.
Let's pretend for a moment that you could do what you're asking for. If that were true, the following code would be legal:
let objA: ObjectA = ObjectB()
objA.type.append(ObjectA())
I have to be allowed to treat ObjectB as if it were an ObjectA. That's what the Liskov Substitution Principle means for subtyping. So now I'm allowed to add an ObjectA to an [ObjectB]. That breaks the whole type system. Blam.
Generally when you want this, it's because you're misusing subclasses. Subclasses are seldom the right tool in pure Swift; they mostly creep in because of bridging to ObjC. But even in ObjC, subclassing should be avoided when possible. Swift brings us excellent new tools to help avoid subclasses, and you should prefer them. For example, rather than subclassing, just use protocols:
protocol A {}
struct TypeA: A {}
struct TypeB: A {}
class Object<T: A> {
var type = [T]()
}
You are not allowed to override a stored property in swift. However, you are allowed to change the value of an inherited property while initialising an Instance.
Example:
class TypeA: NSObject {
}
class TypeB: TypeA {
}
class ObjectA {
var type = [TypeA]()
}
class ObjectB: ObjectA {
override init() {
super.init()
type = [TypeB]()
}
}
Another option, would be to use one Class within the other instead of using inheritance. Something like this:
class TypeA: NSObject {
}
class TypeB: TypeA {
}
class ObjectA {
var type = [TypeA]()
}
class ObjectB: NSObject {
private var obj = ObjectA()
var type: [TypeB] {
get{
return obj.type as! [TypeB]
}
set {
obj.type = newValue
}
}
}
var obj1 = ObjectB()
obj1.type = [TypeB()]
let test: TypeB = obj1.type[0]