Kotlin enables me to implement an interface by delegating to a primary constructor argument like so:
class Foo(xs : ArrayList<Int>) : List<Int> by xs { }
But this exhibits the backing implementer to the user. Delegating to an anonymous also seems to be ok:
class Foo() : List<Int> by ArrayList<Int>() { }
This hides the implementation details, but we loose access to features not provided by the interface, which in this case is mutability.
I would therefore like to delegate the implementation to a property that is not in the primary constructor. What I would like to have is similar to
class Foo() : List<Int> by xs {
val xs : List<Int> = ArrayList<Int>()
}
which doesn't compile.
Is it possible to have a property defined explicitly in the class body and still be able to delegate implementation to it?
This is not currently possible. The expression in the by-clause is computed only once before the construction of the class, so you cannot reference symbols of that class.
There is a request in the issue tracker to allow this, although it's almost definitely not going to be supported in Kotlin 1.0.
One funny workaround that sometimes works is to make the property which you want to be a delegate, a constructor parameter with the default value instead. That way it'll be accessible both in the by-clause and in the class body:
class Foo(val xs: List<Int> = ArrayList<Int>()) : List<Int> by xs {
fun bar() {
println(xs)
}
}
Keep in mind though that xs in by xs is still calculated only once here, so even if xs is a var property, only the default value provided in the constructor will be used. It's not a universal solution, but sometimes it can help.
Expanding on the answer of Alexander Udalov, I came up with a solution using a private base class
private open class FooBase(protected val xs : MutableList<Int>) : List<Int> by xs { }
class Foo() : FooBase(ArrayList()) {
fun bar() {
xs.add(5)
}
}
Now I can have access to the property backing my interface implementation but am not restricted to operations provided by that interface while still hiding the actual implementation from the user.
Note: Although it works, I get the following warning from IntelliJ IDEA 15 CE which arises from EXPOSED_SUPER_CLASS inspection: Deprecated: subclass effective visibility 'public' should be the same or less permissive than its superclass effective visibility 'private'. I'm not quite sure what the deprecated part here means – whether the warning will be removed in the future or this won't compile at some point. Anyway, we don't really have to use a private open class, abstract or simply open will do, because even if the user is allowed to create an instance of FooBase, there is not much he can do with it.
Update:
There is actualy a simple and compact solution that does not use any suspicious behaviour:
class Foo private constructor(private val xs: ArrayList<Int>) : List<Int> by xs {
constructor() : this(ArrayList<Int>()) { }
}
Related
The following code is valid Kotlin code:
abstract class A {
protected lateinit var v: X
abstract fun f(): X
class SubA : A() {
override fun f(): X {
return SubX()
}
init {
v = f()
}
}
}
It defines an abstract class which has a lateinit var field and an abstract method that sets the value of that field. The reason behind this is that that method may be called later again, and its behavior should be defined in the subclasses that extend the original class.
This code is a simplification of a real-world code, and even though it works, I feel like it is messy since the developer of the subclass could choose not to (or forget) to call v = f() inside an init block. And we cannot do that in A either because then it will show a warning that we are calling a non-final method in the constructor. What I propose is the following:
abstract class A {
private lateinit var v: X
abstract fun f(): X
class SubA : A() {
override fun f(): X {
return SubX()
}
}
lateinit { // this does not exist
v = f()
}
}
The benefits of this is that now the field can be private instead of protected, and the developer does not have to manually call v = f() in each of their subclasses (or the subclasses of their subclasses), and the naming fits with the nomenclature of Kotlin since lateinit is already a keyword and init is already a block. The only difference between an init and a lateinit block would be that the contents of a lateinit block are executed after the subclass constructors, not before like init.
My question is, why isn't this a thing? Is this already possible with some other syntax that I do not know about? If not, do you think it's something that should be added to Kotlin? How and where can I make this suggestion so that the developers would most likely see it?
There are three options, and you can implement your lateinit block in two ways
don't lazy init - just have a normal construction parameter
use a delegated lazy property
add a lambda construction parameter to the superclass class A
All of these solves the problem of requiring subclasses of A having to perform some initialization task. The behaviour is encapsulated within class A.
Normal construction parameter
Normally I'd prefer this approach, and don't lazy init. It's usually not needed.
abstract class A(val v: X)
class SubA : A(SubX())
interface X
class SubX : X
fun f() can be replaced entirely by val v.
This has many advantages, primarily that it's easier to understand, manage because it's immutable, and update as your application changes.
Delegated lazy property
Assuming lazy initialization is required, and based on the example you've provided, I prefer the delegated lazy property approach.
The existing equivalent of your proposed lateinit block is a lazy property.
abstract class A {
protected val v: X by lazy { f() }
abstract fun f(): X
}
class SubA : A() {
override fun f(): X {
return SubX()
}
}
interface X
class SubX : X
The superclass can simply call the function f() from within the lazy {} block.
The lazy block will only run once, if it is required.
Construction parameter
Alternatively the superclass can define a lambda as construction parameter, which returns an X.
Using a lambda as a construction parameter might be preferred if the providers are independent of implementations of class A, so they can be defined separately, which helps with testing and re-used.
fun interface ValueProvider : () -> X
abstract class A(
private val valueProvider: ValueProvider
) {
protected val v: X get() = valueProvider()
}
class SubA : A(ValueProvider { SubX() })
interface X
class SubX : X
The construction parameter replaces the need for fun f().
To make things crystal clear I've also defined the lambda as ValueProvider. This also makes it easier to find usages, and to define some KDoc on it.
For some variety, I haven't used a lazy delegate here. Because val v has a getter defined (get() = ...), valueProvider will always be invoked. But, if needed, a lazy property can be used again.
abstract class A(
private val valueProvider: ValueProvider
) {
protected val v: X by lazy(valueProvider)
}
If I have something like the following:
interface IRecordService {
fun doSomething () : Record
}
#MongoRepository
interface IRecordRepository : MongoRepository<Record, String> {
}
#Service
class RecordService (
private val recordRepository : IRecordRepository // or just val instead of private val
) : IRecordService
{
override fun doSomething () : Record {
// does something
}
}
Is there any difference between using private val in the RecordService constructor vs just val? I've seen both being used but couldn't tell if there was a recommended way or why.
This isn't specific to Spring or Mongo; it's just core Kotlin. There are several things going on here; I'll try to unpick them.
Consider the simpler definition:
class MyClass(i: Int)
The parens specify the primary constructor: any parameters there (such as i) are passed into the class, and are available during construction. So you could pass them up to the superclass constructor, use them in property initialisers, and/or in an init block:
class MyClass(i: Int) : MySuperclass(i) {
val someProperty = i
init {
println("i is $i")
}
}
However, they don't persist after the instance has been constructed — so you couldn't refer to them in methods, or from outside the class.
If you want to do that, you have to define a property for each parameter you want to persist. You could do that explicitly, e.g.:
class MyClass(i: Int) {
val i2 = i
}
Here every instance of MyClass has a property called i2 which is initialised to the i constructor parameter.
However, because this is a common pattern, Kotlin provides a shortcut. If you specify val or var in the primary constructor:
class MyClass(val i: Int)
then Kotlin creates a property with the same name as the parameter, and initialises it for you. So every instance of the above class has a property called i that you can refer to at any time.
By default, properties in Kotlin are public: you can access them from inside the class, from subclasses, from other classes in the same module, and from any other code that has a MyClass instance.
However, in some cases it's useful to restrict access, so you can add a visibility modifier: internal prevents code in other modules from seeing it, protected allows only subclasses to see it, and private makes it visible only inside the class itself.
So, to answer your question: without the private modifier, any code that had access to your RecordService would be able to access its recordRepository property; adding private prevents that, and means that only code within RecordService can see it.
In general, it might be a good idea to centralise all access to the recordRepository in the one class; then making it private would ensure that no other code can muck around with it. That would make it easier to see what's going on, easier to debug, and safer to work on. (However, we obviously don't know about the rest of your program, and can't advise on whether that would be a good plan in your case.)
By the way, using an I prefix for interfaces is not a convention that's used much in Kotlin (or Java). There's often little point in having an interface with only one implementation; and if you could have multiple implementations, then better to use a simple term for the interface and then more specific terms for the implementations. (For example: the List interface with ArrayList and LinkedList classes, or Number with Int and Long.)
If you put val, it will be a constructor parameter and property. If you don't, it will be a constructor parameter (NOT property).
See Why to put val or var in kotlin class constructors
Firstly if you use val it converts this constructor parameter to property,If you do not want to hide this property (to set it) from other classes,you can use val.But if you do not want your property to be changed by other classes you should use private val instead.
Well, you can use both val and private val in your constructor there's no problem in that, it's just that with private keyword your properties wont be modified or accessed by some other class, so it basically provides some data hiding. If you talking about difference in functionality inside your RecordService class, then no there wont be any difference.
guys, I am learning kotlin. From https://kotlinlang.org/docs/interfaces.html#properties-in-interfaces it says:
Properties declared in interfaces can't have backing fields, and
therefore accessors declared in interfaces can't reference them.
(I think the pronoun "them" at the end of quoted sentence should refer to "properties" rather than "fields". )
However the following code works. It seems that we can refer to properties. Why is print(prop) highlighted as red then?
interface MyInterface {
val prop: Int // abstract
val propertyWithImplementation: String
get() = "foo"
fun foo() {
print(prop) // this is highlighted red but it works. what's does the author want to say?
}
}
class Child : MyInterface {
override val prop: Int = 29
}
fun main() {
val c = Child()
c.foo()
}
Besides, I noticed that in the above example foo is not accessor. So I tried following example and it works too:
interface User {
val email: String
val nickname: String
get() = email.substringBefore('#') // aren't we referring to a property in accessor? why does this work then?
}
So what does the author want to say in here? what does "them" refer to?
"Them" in this sentence means "fields".
Property is basically a getter (setter) and it could be optionally backed by a field. For technical reasons interfaces can't hold fields, so properties in interfaces have to be "fieldless". Property has to be either abstract or its implementation can only use e.g. other properties/functions, but it can't store/read any data directly. Note that referencing other properties does not break above rule, because, as I said, property is mainly a getter/setter, not a field.
print(prop) is highlighted as red, because... well, this is how automatic highlighter colored it... :-)
I would like to semantically constrain a map to only accept "data" class object types as the value in kotlin like so:
class Test(
val test : Int
)
data class Test2 (
val test : Int
)
fun test(map : Map<String, /* compile error on Test, but accept Test2 or any other data class */>) {
}
I'm mainly trying to do this so that I can keep everything in the map cloneable, but when I do this:
fun <T: Cloneable> test(map : Map<String, T>) {
// test clone
map.map { it.key.uuid to it.value.clone() } .toMap() // error on .clone() Cannot access 'clone': it is protected in 'Cloneable'
}
but I thought implementing the Cloneable interface made your clone method public? Essentially I'm looking for a compile time guarantee that all data is copyable in that method invocation, (is a primitive type, a data class that I can call .copy() on, or any object that has implemented Cloneable). Is my only option reflection and runtime assertions?
I thought implementing the Cloneable interface made your clone method public?
No, it's simply a marker interface, which tells the protected Object.clone() method not to throw a CloneNotSupportedException. In practice, classes that implement Cloneable will usually override clone() and make it public, but that's not necessary. And of course that's no help when you don't know the exact type!
The cloning mechanism was an early part of Java, and not very well-designed. (Effective Java calls it “a highly atypical use of interfaces and not one to be emulated”.) But it's still used, so we're stuck with it…
(See also these related answers.)
I don't know whether this is the best way or not, but how about you to use property like below.
SomeClass::class.isData
Kdoc says
true if this class is a data class.
While i am reading document of Kotlin, i saw that we should avoid using open properties declared at base class:
It means that, by the time of the base class constructor execution, the properties declared or overridden in the derived class are not yet initialized. If any of those properties are used in the base class initialization logic (either directly or indirectly, through another overridden open member implementation), it may lead to incorrect behavior or a runtime failure. When designing a base class, you should therefore avoid using open members in the constructors, property initializers, and init blocks.
The document said that properties in derived class are not yet initialized when base class's constructor is called. But, how can we access derived class's properties which are not initialized, from base class constructor(I assumed that the incorrect behavior or a runtime failure were caused by this situation)? Is it possible?
I don't know kotlin, but I'm assuming that open is the same as virtual in other languages. It is unsafe to call virtual members in a base class constructor because the base constructor is called before the derived constructor. If the overridden property requires that the derived class be fully initialized it can cause errors because the derived constructor has not yet been called when you are inside the base constructor. At least that is the way it works in .NET languages like C#.
Open functions in Kotlin are functions which can be overridden by a subclass. Generally, it's a good practice to limit a class's inheritance because you should provide a class with it's necessary codes to make it overridable. If your intention is not to let a class to override your base class, then you should make it final. So Kotlin make this easy by making each class and method final by default. You can find a more detailed answer in the Objects and Class chapter of the book Kotlin in Action.
The so-called fragile base class problem occurs when modifications of a base class
can cause incorrect behavior of subclasses because the changed code of the base class no
longer matches the assumptions in its subclasses. If the class doesn’t provide exact rules
for how it should be subclassed (which methods are supposed to be overridden and how),
the clients are at risk of overriding the methods in a way the author of the base class
didn’t expect. Because it’s impossible to analyze all the subclasses, the base class is
"fragile" in the sense that any change in it may lead to unexpected changes of behavior in
subclasses.
To protect against this problem, Effective Java by Joshua Bloch (Addison-Wesley,
2008), one of the best-known books on good Java programming style, recommends that
you "design and document for inheritance or else prohibit it." This means all classes and
methods that aren’t specifically intended to be overridden in subclasses need to be
explicitly marked as final .
Kotlin follows the same philosophy. Whereas Java’s classes and methods are open by
default, Kotlin’s are final by default.
I assume you are asking about this example in Kotlin documentation:
open class Base(val name: String) {
init { println("Initializing a base class") }
open val size: Int =
name.length.also { println("Initializing size in the base class: $it") }
}
class Derived(
name: String,
val lastName: String,
) : Base(name.replaceFirstChar { it.uppercase() }.also { println("Argument for the base class: $it") }) {
init { println("Initializing a derived class") }
override val size: Int =
(super.size + lastName.length).also { println("Initializing size in the derived class: $it")
}
}
Kotlin designers followed good practices learned, from other language mistakes, so they made class, properties, and functions closed by default for overriding or inheriting. why?
let's add the open modifier to the base class property and override it:
open class Base(open val name: String) {
init { println("Initializing a base class") }
open val size: Int =
name.length.also { println("Initializing size in the base class: $it") }
}
class Derived(
override val name: String,
val lastName: String,
) : Base(name.replaceFirstChar { it.uppercase() }.also { println("Argument for the base class: $it") }) {
init { println("Initializing a derived class") }
override val size: Int =
(super.size + lastName.length).also { println("Initializing size in the derived class: $it") }
}
fun main() {
println("Constructing the derived class(\"hello\", \"world\")")
Derived("hello", "world")
}
if you run this code the output will be like below:
Constructing the derived class("hello", "world")
Argument for the base class: Hello
Initializing a base class
**Exception in thread "main" java.lang.NullPointerException
at Base.<init> (File.kt:6)
at Derived.<init> (File.kt:12)
at FileKt.main (File.kt:23)**
The error is happening because this line of code
open val size: Int =
name.length.also { println("Initializing size in the base class: $it") }
Why? when we were trying to initialize the Derived class, first the superclass is initialized first, so the initialization is done by evaluating the super constructor argument, then the properties and init blocks in their declaration order in the class.
when it comes to val size: Int = name.length.also{...} the initialization calls the name property which is overridden by the Derived class, the one that does NOT yet initialize.
so by avoiding marking the base properties by open, you protect the base class client from abusing the class.