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

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

Related

Copy constructor and "Cannot call value of non-function type" error

I have a base class A and three subclasses:
class A {}
class X : A {}
class Y : A {}
class Z : A {}
In my code, I have an instance m which I would like to create a copy of, of the same type.
I can successfully use the following code:
let n = type(of: m).init(m)
... and in class A:
required init(m : A) {
self.param1 = m.param1
I try to simplify things by creating a copy constructor in class A:
func copy() {
return type(of: self).init(self)
}
but this declaration generates the error: Cannot call value of non-function type 'AType'
Two questions: What am I doing wrong? and Is there a simpler way to create a copy constructor involving subclasses?
Try the Prototype desing pattern:
public protocol Copying: class {
init(_ prototype: Self)
}
extension Copying {
public func copy() -> Self {
return type(of: self).init(self)
}
}
public class A: Copying {
public var value1: Int
public var value2: Int
public init(value1: Int, value2: Int) {
self.value1 = value1
self.value2 = value2
}
public required convenience init(_ a: A) {
self.init(value1: a.value1, value2: a.value2)
}
}
and you can use it like:
let a = A(value1: 700, value2: 37)
let aCopy = a.copy()

kotlin override property from interface with subtype

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

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.

variable of a base class that uses generics

I have a abstract base class (DataSource, in my simplified scenario below) and a handful of subclasses (IntSource and StringSource). The base class is using generics.
I want to have a variable (say, currentDataSource) typed as the base class so it can refer to an instance of any of the subclasses. I can't figure out how to declare it, though. The declaration requires a concrete type which immediately breaks the abstraction.
class DataSource<Element> where Element:Equatable {
var elements = [Element]()
func description() {
print("must override")
}
}
class IntSource: DataSource<Int> {
override func description() {
print("Ints!")
}
}
class StringSource: DataSource<String> {
override func description() {
print("Strings!")
}
}
let a = IntSource()
let b = StringSource()
var current: DataSource<???> // this is where I'm stuck
current = a
print(current.description())
current = b
print(current.description())

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