Setting setter of an interface in class implementing it - interface

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.

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.

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 to get some parameter in the child class through the base class

I'm stuck.
I try to make right code's architect but I can not solve following case:
I have some base class and inherited from it class like:
class BaseClass {
var name: String
init(name: String) {
self.name = name
}
}
class ChildClass: BaseClass {
var otherName: String
init(otherName: String) {
self.otherName = otherName
}
}
And the following function:
func someFunc() -> BaseClass {
let a = ChildClass.init(otherName: "NAME")
return a
}
How can I get the parameter "otherName"?
The available parameter is only one - "name", but I want to get "otherName":
let b = someFunc()
b.PARAMETERS
You can use:
(b as! ChildClass).otherName
Your function returns your object as BaseClass object, so you can't access any of ChildClass methods. In order to access ChildClass methods, you need to cast your object to ChildClass using as!, as we know it is a ChildClass object. After that you'll be able to access all the parameters of ChildClass.

Struct static vars under inheritance

how the ambiguity can be resolved in this case provided that I can't change the name Static and the name SOMECONST for each class (to keep a consistent convention across the API classes)
it might or might not work in playgrounds but the error AMBIGUOUS USE OF SOMECONST appears during compilation in Xcode.
If it's not possible then I'm going to revert to getters, any person got an idea if Apple will implement static for classes or it's only designed for struct and enum???
public class A {
public struct Static {
public static let SOMECONST = 1
}
init(val: Int) {
println(val)
}
}
public class B: A {
public struct Static {
public static let SOMECONST = 2
}
init() {
super.init(val: B.Static.SOMECONST)
}
}
B()
The program (unsurprisingly) can't compile because it found two candidates for the SOMECONST symbol:
error: ambiguous use of 'SOMECONST'
super.init(val: B.Static.SOMECONST)
^
note: found this candidate
static let SOMECONST = 2
^
note: found this candidate
static let SOMECONST = 1
^
Using nested types for storing constants like this is generally a bad idea, because nested types can't be overriden by subclasses. You should declare the constants directly as part of your class.
Now, ideally you would do something like this:
class A {
class let SOMECONST = 1
}
class B: A {
override class let SOMECONST = 2
}
But, unfortunately, this is not supported by the current Swift compiler. The only way you can override a class (static) variable is to make it computable:
class A {
class var SOMECONST: Int {
return 1
}
}
class B: A {
override class var SOMECONST: Int {
return 2
}
}
That's a little bit uglier, but it works. You can now create your B's initializer:
init() {
super.init(val: B.SOMECONST) // prints "2"
}

Getting an argument from a private constructor

I want to get access to an argument in a private constructor without using mutable variables:
class Class1 {
val strArgPublic = // get strArg argument from the private constructor. How?
private def this(strArg: String) = {
//.....
}
}
I want not only get strArg and return it, but change it a little bit and return a new modified copy of it.
How can I do this?
There is not only private constructor in your class. There is also a public constructor. You should decide what will be a value of strArgPublic after public constructor. If there is should be no public constructor you should define your class like this:
class Class1 private(strArg: String) {
val strArgPublic = transform(strArg)
}
If there should be a parameterless public constructor you could define one as auxiliary constructor:
class Class1 private(strArg: String) {
val strArgPublic = transform(strArg)
def this() = this("default")
}