Given:
enum class Foo {
BAR,
BAZ { fun qux(foo: Any) {} }
}
It appears to be legal code, but when I try to access qux() like so:
val foo = Foo.BAZ
foo.qux("blah")
...it doesn't work as the member function is not visible.
Is there a way I can access qux() outside of the enum class? If not, then what would be a use case for a custom member of an enum entry?
You can use it to implement interfaces and abstract methods, but since those body blocks are anonymous classes You won't be able to explicitly access per-entry values.
Perhaps what you're looking for can be achieved by using sealed classes?
Related
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.
I want to use Kotlin delegation in a particular context.
The delegate should not be passed in the constructor.
I want to keep a reference to the delegate for later use in the code. From within the method that I override, say printMessage(), I still need to call the delegate the same way you'd call super.printMessage() in polymorphic inheritance.
I can do the first by simply instantiating an anonymous delegate in the by clause (class Derived() : Base by BaseImpl(42) using Kotlin's documentation example). However,
this prevents me from accessing the anonymous delegate, as there is no way that I know to reference it.
I want to do something similar to the following. The following however doesn't compile with error 'this' is not defined in this context.
class Derived() : Base by this.b {
val b: Base = BaseImpl(42)
override fun printMessage() {
b.printMessage()
print("abc")
}
}
I do need a separate delegate for each instance of my Derived class. So moving b as a global variable is not an option for me.
The closest I got to what I need is with an optional parameter to the constructor. This is not a good option neither, as I don't want to allow the construction of my Derived class with arbitrary delegates.
You can do this using a private primary constructor and a public secondary constructor:
class Derived private constructor(val b: Base) : Base by b {
constructor(): this(BaseImpl(42))
override fun printMessage() {
b.printMessage()
print("abc")
}
}
If you don't need a reference to the delegate, you can also say simply,
class Derived : Base by BaseImpl(42)
With Kotlin 1.5 was introduce the sealed interface. Even that I know the difference between classes and interfaces, I'm not clear what are the best practices and beneficies of using sealed interface over sealed class
Should I always use interface now even when is a simple case? Or will be a case by case?
Thanks
Obs: Didn't found similar questions, only about sealed classes
A major reason to choose to use a sealed class instead of interface would be if there is common property/function that you don't want to be public. All members of an interface are always public.
The restriction that members must be public can be worked around on an interface using extension functions/properties, but only if it doesn't involve storing state non-publicly.
Otherwise, sealed interfaces are more flexible because they allow a subtype to be a subclass of something else, an enum class, or a subtype of multiple sealed interface/class hierarchies.
I would also add that sealed interface can be chosen instead of a class to mark an object with additional characteristics and use it in the when statement. For example let's say we have some number of classes that inherited from a sealed class Device:
sealed class DeviceItem(val name: String) {
object Camera : DeviceItem("Camera")
object Lamp : DeviceItem("Lamp")
// ... etc, more devices
}
And we need to use an instance of DeviceItem in when statement, but we don't want to handle all the items, only specific items:
fun onDeviceItemClicked(item: DeviceItem) {
when (item) {
// ....
}
}
In this case we should either add all device items to the when statement with an empty body for devices that we don't want to handle, and the code becomes cumbersome, or use else statement to handle those device items with the empty body. But if we use else we will not be notified of the error, when a new device item is added and requires some handling, which can lead to bugs. Starting from Kotlin 1.7 it will be a compilation error if when operator is not exhaustive. So basically to handle such cases we can provide a sealed interface and handle only items, which implement it:
sealed interface ClickableItem
sealed class DeviceItem(val name: String) {
object Camera : DeviceItem("Camera"), ClickableItem
object Lamp : DeviceItem("Lamp")
// ... etc, more devices
}
fun onDeviceItemClicked(item: ClickableItem) {
when (item) {
Camera -> { /* do something */ }
}
}
In this case when a new device item, which implements ClickableItem interface, is added there will be a compilation error, saying that when statement should be exhaustive and we must handle 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.
I've bumped into this code and I'm not sure why would anyone do this. Basically the author decided for making the class constructor private so that it cannot be instantiated outside the file, and added a public method to a companion object in the class that creates a new instance of this class. What is the benefit of this approach?
This is what I found:
class Foo private constructor(private val arg1: Any) {
//more code here..
companion object {
fun newFoo(arg1: Any) = Foo(arg1 = arg1)
}
}
Why is it better than this?
class Foo(private val arg1: Any) {
//more code here..
}
There are several benefits to providing a factory method instead of a public constructor, including:
It can do lots of processing before calling the construstor. (This can be important if the superclass constructor takes parameters that need to be calculated.)
It can return cached values instead of new instances where appropriate.
It can return a subclass. (This allows you to make the top class an interface, as noted in another answer.) The exact class can differ between calls, and can even be an anonymous type.
It can have a name (as noted in another answer). This is especially important if you need multiple methods taking the same parameters. (E.g. a Point object which could be constructed from rectangular or polar co-ordinates.) However, a factory method doesn't need a specific name; if you implement the invoke() method in the companion object, you can call it in exactly the same way as a constructor.
It makes it easier to change the implementation of the class without affecting its public interface.
It also has an important drawback:
It can't be used by subclass constructors.
Factory methods seem to be less used in Kotlin than Java, perhaps due to Kotlin's simpler syntax for primary constructors and properties. But they're still worth considering — especially as Kotlin companion objects can inherit.
For much deeper info, see this article, which looks at the recommendation in Effective Java and how it applies to Kotlin.
If you want to change Foo into an interface in the future the code based on the method will keep working, since you can return a concrete class which still implements Foo, unlike the constructor which no longer exists.
An example specific to android is, that Fragments should be constructed with an empty constructed, and any data you'd like to pass through to them should be put in a bundle.
We can create a static/companion function, which takes in the arguments we need for that fragment, and this method would construct the fragment using the empty constructor and pass in the data using a bundle.
There are many useful cases, for example what Kiskae described. Another good one would be to be able to "give your constructors names":
class Foo<S: Any, T: Any> private constructor(private val a: S, private val b: T) {
//more code here...
companion object {
fun <S: Any> createForPurposeX(a: S) = Foo(a = a, b = "Default value")
fun createForPurposeY() = Foo(a = 1, b = 2)
}
}
Call site:
Foo.createForPurposeX("Hey")
Foo.createForPurposeY()
Note: You should use generic types instead of Any.