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.
Related
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()
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
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.
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.
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")
}