class Foo(val param1: String, var param2: Int) {
// class body
companion object {
val NULL = Foo("", 0)
}
}
Is the NULL object valid in Kotlin?
Although Kotlin allows adding default values in the constructor, is there a reason for NULL object to be discouraged, like in the above snippet?
Lets, say I don't need to allow constructing objects just with one param like: Foo("ABC") or Foo(5). (...after modifying the Foo to have default values in the constructor that is)
https://sourcemaking.com/design_patterns/null_object
Singleton isn't the right word for what you have there. A singleton is a class with only one instance allowed. This is a merely a globally accessible instance of a class that can have many instances.
I would advise against calling it NULL because of the meaning of the word null in Kotlin. Could be rather misleading. Maybe call it EMPTY.
Whether it's a bad practice is going to depend on how you're using it, but there's nothing inherently wrong with keeping some long-lived instances of classes.
I would however avoid doing this with a mutable class like this. It is implied that it is a constant, but in your example, someone could change the value of NULL.param2 from anywhere in an app and break code elsewhere that relies on its value being 0.
A null object is a valid Kotlin design pattern.
When you use this pattern, you should create an interface and make both regular class(es) and a null object implement it. Also, the null object should be immutable like all other singletons.
Here is how you can implement the null object design pattern in Kotlin:
interface Foo {
val param1: String
val param2: Int
}
object NullFoo : Foo {
override val param1: String get() = ""
override val param2: Int get() = 0
}
class FooImpl(override val param1: String, override var param2: Int) : Foo
Alternatively, you can use actual null value and extension functions (properties) with nullable receivers:
class Foo(val param1: String, var param2: Int)
val Foo?.param1: String get() = this?.param1 ?: ""
val Foo?.param2: Int get() = this?.param2 ?: 0
You can create a factory function without parameters that will return a null object:
class Foo(val param1: String, var param2: Int) {
// class body
}
private val nullFoo = Foo("", 0)
fun Foo() = nullFoo
Related
My use case:
I have a large number of POJO models that are different types of requests for a third-party API. All of them have several common fields and a couple unique ones.
I was hoping to build something that conceptually looks like this
class RequestBase(
val commonField1: String,
val commonField2: String,
...
val commonFieldX: String
)
class RequestA(
val uniqueFieldA: String
): RequestBase()
class RequestB(
val uniqueFieldB: String
): RequestBase()
fun main() {
val requestA = RequestA(
commonField1 = "1",
commonField2 = "2",
...
uniqueFieldA = "A"
)
}
I can of course override the common fields in every child request and then pass them to the parent constructor, but this ends up producing a lot of boilerplate code and bloats the model. Are there any options I can explore here?
Notice that what you are doing in the parentheses that follow a class declaration is not "declaring what properties this class has", but "declaring the parameters of this class' primary constructor". The former is just something you can do "along the way", by adding var or val.
Each class can have its own primary constructor that take any number and types of parameters that it likes, regardless of what class its superclass is. Therefore, it is not unreasonable to have to specify all the parameters of the constructor:
open class RequestBase(
val commonField1: String,
val commonField2: String,
...
val commonFieldX: String
)
class RequestA(
// notice that the parameters for the inherited properties don't have the
// "val" prefix, because you are not declaring them in the subclass again.
// These are just constructor parameters.
commonField1: String,
commonField2: String,
...
commonFieldX: String,
val uniqueFieldA: String,
): RequestBase(
commonField1,
commonField2,
...
commonFieldX,
)
If you find this unpleasant, there are a bunch of ways to work around this.
One way is to use composition and delegation - create an interface having the common properties. The specific requests' primary constructors will take a RequestBase and their unique properties, and implement the interface by delegating to the RequestBase:
interface Request {
val commonField1: String
val commonField2: String
val commonFieldX: String
}
open class RequestBase(
override val commonField1: String,
override val commonField2: String,
override val commonFieldX: String
): Request
class RequestA(
val requestBase: RequestBase,
val uniqueField: String
): Request by requestBase
This allows you to access someRequestA.commonFieldX directly, without doing someRequestA.requestBase.commonFieldX, but to create a RequestA, you need to create a RequestBase first:
RequestA(
RequestBase(...),
uniqueField = ...
)
Another way is to change your properties to vars, give them default values, and move them out of the constructor parameters:
open class RequestBase {
var commonField1: String = ""
var commonField2: String = ""
var commonFieldX: String = ""
}
class RequestA: RequestBase() {
var uniqueField: String = ""
}
Then to create an instance of RequestA, you would just call its parameterless constructor, and do an apply { ... } block:
RequestA().apply {
commonField1 = "foo"
commonField2 = "bar"
commonFieldX = "baz"
uniqueField = "boo"
}
The downside of this is of course that the properties are all mutable, and you have to think of a default value for every property. You might have to change some properties to nullable because of this, which might not be desirable.
You can't do it with constructors of base class. Without constructors it's possible:
open class RequestBase {
lateinit var commonField1: String
lateinit var commonField2: String
...
lateinit var commonFieldX: String
}
class RequestA(
val uniqueFieldA: String
): RequestBase()
class RequestB(
val uniqueFieldB: String
): RequestBase()
fun main() {
val requestA = RequestA(
uniqueFieldA = "A"
).apply {
commonField1 = "1"
commonField2 = "2"
...
commonFieldX = "X"
}
}
I am writing a class that contains two immutable values, which are set in the primary constructor. I would like to add a secondary constructor that takes a string and parses it to get those two values. However, I can't figure out a way to implement this in Kotlin, as the secondary constructor calls the primary constructor immediately, before parsing the string.
In java, I would call this(a,b) in one of the other constructors, but Java doesn't have primary constructors. How do I add this functionality?
class Object (a: double, b:double)
{
val a = a
val b = b
constructor(str: String) //Parsing constructor
{
//Do parsing
a = parsed_a
b = parsed_b
}
}
You can either replace your parsing constructor with a factory method:
class Object(val a: Double, val b: Double) {
companion object {
// this method invocation looks like constructor invocation
operator fun invoke(str: String): Object {
// do parsing
return Object(parsed_a, parsed_b)
}
}
}
Or make both constructors secondary:
class Object {
val a: Double
val b: Double
constructor(a: Double, b: Double) {
this.a = a
this.b = b
}
// parsing constructor
constructor(str: String) {
// do parsing
a = parsed_a
b = parsed_b
}
}
Secondary constructors are disfavored in Kotlin. Your best solution is to use a factory method. See, e.g.:
class A(val a: Int, val b: Int) {
companion object {
fun fromString(str: String): A {
val (foo, bar) = Pair(1, 2) // sub with your parsing stuff
return A(foo, bar)
}
}
}
This will lead to more readable code. Imagine a class with ten different constructors identified no way other than MyClass as opposed to many more obvious ones enabled by the factory approach: MyClass.fromString(str: String) and MyClass.fromCoordinates(coordinates: Pair<Int, Int>) and so forth.
Secondary constructors weren't even allowed in Kotlin until relatively recently.
I have this enum:
enum class Types(val value: Int) {
FOO(1)
BAR(2)
FOO_BAR(3)
}
How do I create an instance of that enum using an Int?
I tried doing something like this:
val type = Types.valueOf(1)
And I get the error:
Integer literal does not conform to the expected type String
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
fun fromInt(value: Int) = Types.values().first { it.value == value }
}
}
You may want to add a safety check for the range and return null.
Enum#valueOf is based on name. Which means in order to use that, you'd need to use valueof("FOO"). The valueof method consequently takes a String, which explains the error. A String isn't an Int, and types matter. The reason I mentioned what it does too, is so you know this isn't the method you're looking for.
If you want to grab one based on an int value, you need to define your own function to do so. You can get the values in an enum using values(), which returns an Array<Types> in this case. You can use firstOrNull as a safe approach, or first if you prefer an exception over null.
So add a companion object (which are static relative to the enum, so you can call Types.getByValue(1234) (Types.COMPANION.getByValue(1234) from Java) over Types.FOO.getByValue(1234).
companion object {
private val VALUES = values()
fun getByValue(value: Int) = VALUES.firstOrNull { it.value == value }
}
values() returns a new Array every time it's called, which means you should cache it locally to avoid re-creating one every single time you call getByValue. If you call values() when the method is called, you risk re-creating it repeatedly (depending on how many times you actually call it though), which is a waste of memory.
Admittedly, and as discussed in the comments, this may be an insignificant optimization, depending on your use. This means you can also do:
companion object {
fun getByValue(value: Int) = values().firstOrNull { it.value == value }
}
if that's something you'd prefer for readability or some other reason.
The function could also be expanded and check based on multiple parameters, if that's something you want to do. These types of functions aren't limited to one argument.
If you are using integer value only to maintain order, which you need to access correct value, then you don't need any extra code. You can use build in value ordinal. Ordinal represents position of value in enum declaration.
Here is an example:
enum class Types {
FOO, //Types.FOO.ordinal == 0 also position == 0
BAR, //Types.BAR.ordinal == 1 also position == 1
FOO_BAR //Types.FOO_BAR.ordinal == 2 also position == 2
}
You can access ordinal value simply calling:
Types.FOO.ordinal
To get correct value of enum you can simply call:
Types.values()[0] //Returns FOO
Types.values()[1] //Returns BAR
Types.values()[2] //Returns FOO_BAR
Types.values() returns enum values in order accordingly to declaration.
Summary:
Types.values(Types.FOO.ordinal) == Types.FOO //This is true
If integer values don't match order (int_value != enum.ordinal) or you are using different type (string, float...), than you need to iterate and compare your custom values as it was already mentioned in this thread.
It really depends on what you actually want to do.
If you need a specific hardcoded enum value, then you can directly use Types.FOO
If you are receiving the value dynamically from somewhere else in your code, you should try to use the enum type directly in order not to have to perform this kind of conversions
If you are receiving the value from a webservice, there should be something in your deserialization tool to allow this kind of conversion (like Jackson's #JsonValue)
If you want to get the enum value based on one of its properties (like the value property here), then I'm afraid you'll have to implement your own conversion method, as #Zoe pointed out.
One way to implement this custom conversion is by adding a companion object with the conversion method:
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
private val types = values().associate { it.value to it }
fun findByValue(value: Int): Types? = types[value]
}
}
Companion objects in Kotlin are meant to contain members that belong to the class but that are not tied to any instance (like Java's static members).
Implementing the method there allows you to access your value by calling:
var bar = Types.findByValue(2) ?: error("No Types enum value found for 2")
Note that the returned value is nullable, to account for the possibility that no enum value corresponds to the parameter that was passed in. You can use the elvis operator ?: to handle that case with an error or a default value.
If you hate declaring for each enum type a companion object{ ... } to achieve EMotorcycleType.fromInt(...). Here's a solution for you.
EnumCaster object:
object EnumCaster {
inline fun <reified E : Enum<E>> fromInt(value: Int): E {
return enumValues<E>().first { it.toString().toInt() == value }
}
}
Enum example:
enum class EMotorcycleType(val value: Int){
Unknown(0),
Sport(1),
SportTouring(2),
Touring(3),
Naked(4),
Enduro(5),
SuperMoto(6),
Chopper(7),
CafeRacer(8),
.....
Count(9999);
override fun toString(): String = value.toString()
}
Usage example 1: Kotlin enum to jni and back
fun getType(): EMotorcycleType = EnumCaster.fromInt(nGetType())
private external fun nGetType(): Int
fun setType(type: EMotorcycleType) = nSetType(type.value)
private external fun nSetType(value: Int)
---- or ----
var type : EMotorcycleType
get() = EnumCaster.fromInt(nGetType())
set(value) = nSetType(value.value)
private external fun nGetType(): Int
private external fun nSetType(value: Int)
Usage example 2: Assign to val
val type = EnumCaster.fromInt<EMotorcycleType>(aValidTypeIntValue)
val typeTwo : EMotorcycleType = EnumCaster.fromInt(anotherValidTypeIntValue)
A naive way can be:
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
fun valueOf(value: Int) = Types.values().find { it.value == value }
}
}
Then you can use
var bar = Types.valueOf(2)
Protocol orientated way with type-safety
interface RawRepresentable<T> {
val rawValue: T
}
inline fun <reified E, T> valueOf(value: T): E? where E : Enum<E>, E: RawRepresentable<T> {
return enumValues<E>().firstOrNull { it.rawValue == value }
}
enum class Types(override val rawValue: Int): RawRepresentable<Int> {
FOO(1),
BAR(2),
FOO_BAR(3);
}
Usage
val type = valueOf<Type>(2) // BAR(2)
You can use it on non-integer type, too.
I would build the 'reverse' map ahead of time. Probably not a big improvement, but also not much code.
enum class Test(val value: Int) {
A(1),
B(2);
companion object {
val reverseValues: Map<Int, Test> = values().associate { it.value to it }
fun valueFrom(i: Int): Test = reverseValues[i]!!
}
}
Edit: map...toMap() changed to associate per #hotkey's suggestion.
try this...
companion object{
fun FromInt(v:Int):Type{
return Type::class.java.constructors[0].newInstance(v) as Type
}
}
This is for anyone looking for getting the enum from its ordinal or index integer.
enum class MyEnum { RED, GREEN, BLUE }
MyEnum.values()[1] // GREEN
Another solution and its variations:
inline fun <reified T : Enum<T>> enumFromIndex(i: Int) = enumValues<T>()[i]
enumFromIndex<MyEnum>(1) // GREEN
inline fun <reified T : Enum<T>> enumFromIndex(i: Int) = enumValues<T>().getOrNull(i)
enumFromIndex<MyEnum>(3) ?: MyEnum.RED // RED
inline fun <reified T : Enum<T>> enumFromIndex(i: Int, default: T) =
enumValues<T>().getOrElse(i) { default }
enumFromIndex(2, MyEnum.RED) // BLUE
It is an adapted version of another answer. Also, thanks to Miha_x64 for this answer.
Another option...
enum class Types(val code: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
val map = values().associate { it.code to it }
// Get Type by code with check existing codes and default
fun getByCode(code: Int, typeDefault_param: Types = FOO): Types {
return map[code] ?: typeDefault_param
}
}
}
fun main() {
println("get 3: ${Types.getByCode(3)}")
println("get 10: ${Types.getByCode(10)}")
}
get 3: FOO_BAR
get 10: FOO
In Kotlin, if I have a function that calls a constructor (or another function) is there a way to delegate the determination of default argument to the underlying constructor/function?
This syntax isn't valid, but hopefully this illustrates what I'm trying to do:
fun buildMyObject(stringParam: String?, intParam: Int?): MyClass {
return MyClass(stringParam, intParam)
}
class MyClass(val stringParam: String = "Hello world!", val intParam: Int = 42)
There's no support for exactly what you want. However, if you have a bit of flexibility about where buildMyObject lives, you can have something like:
class MyClass(val stringParam: String = defaultString, val intParam: Int = defaultInt) {
private constructor(stringParam: String?, intParam: Int?) : this(
stringParam ?: defaultString,
intParam ?: defaultInt
)
companion object {
private const val defaultString = "Hello world!"
private const val defaultInt = 42
fun buildMyObject(stringParam: String?, intParam: Int?): MyClass {
return MyClass(stringParam, intParam)
}
}
}
This has a couple of nice characteristics:
Lets users still call the null-safe MyClass constructor
Doesn't duplicate where the default values are defined
Doesn't grow exponentially in the number of constructors you'd need if you'd try to use a when and call with or without each param (imagine what would happen if you'd add a third parameter!)
Keeps the nullable constructor private, so callers can only use nullables if they go through the factory method
I have a data class
data class MyModel(private val _data: MyData? = null)
And I want to ensure my data is only accessible when it is not null, else throw.
I use the below which is good.
fun getData(): MyData {
return checkNotNull(_data) { "data shouldn't be null" }
}
However, if I follow the guide as per Override getter for Kotlin data class, the below complaints I need to return MyData? instead of MyData
val data = _data
get(): MyData {
return checkNotNull(field) { "data shouldn't be null" }
}
Is it true that field can't be cast to the Non-null version of it when return?
If your goal is to declare a getter for a Any? property that returns a Any, it's not possible. You'll get the following error:
Getter return type must be equal to the type of the property
So attempting to do something like
val test : String?
get() : String = "hi"
Wouldn't work.
However, you could hide the nullable property and expose a non-nullable property which references the nullable value via casting:
private val test : String? = "hi"
val testNotNull : String = test as String
If test referenced null, an exception will be thrown.
For example:
fun main(args: Array<String>) = print(Demo().testNotNull)
class Demo(private var test: String? = "hi") {
val testNotNull : String
. get() = test as String
}
You can test this snippit out at try.kotlin.org
Although this is not safe. You should rethink your design. If you're not interoping with Java, you shouldn't punish yourself with nullable types.
I don’t think you can. What you did with the fun getData() is a valid approach IMO. Or you could just not use a data class and create a normal class, obviously.
What I think it may work is with something like this:
typealias notNullType = MyData
data class Test(private val _value: MyData? = null) {
val v: notNullType = _value as notNullType
get() { return field }
}
This would totally allow you to do:
fun play() {
val t = Test(null)
print(t.v) //see what I did? :-)
}
THAT BEING SAID… I don’t think “hiding” the ? optional is necessarily a good idea.
It doesn't necessarily mean that the MyData class is null if you cast it like MyData?
The '?' Just allows the object to be null in the instance that it actually becomes null to avoid an exception at runtime.
You can make your class nullable and it can still contain your data.