Is there a way to make the first digit of int always start with 1 in Kotlin - kotlin

Let's say I have the following class constructor:
class Car(val brand: Brand,val modelName: String, val version: Int){}
If for example, I want the version number to always start with 1. Is there a way to manipulate it in the class body to achieve this ?
Meaning:
val firstdigit:Int = abs(version).ToString().Substring(0,1)
And then parse it to Int. But how to replace the original first digit after that?
I'm just learning Kotlin and I got a bit stuck with this

Is this what you had in mind?
class Car(val brand: Brand, val modelName: String) {
val version = getNextVersion()
companion object {
private var nextVersion = 0
private fun getNextVersion(): Int {
nextVersion++
if (nextVersion.toString()[0] != '1') {
nextVersion = (10.0.pow(ceil(log10(nextVersion.toDouble())))).toInt()
}
return nextVersion
}
}
}

You already said in the comments that you want the number to increment per instance, so the caller shouldn't be providing that number in the first place really! But just generally, here's two approaches to sanitising your input parameters:
1) Make it the caller's responsibility to provide valid data
init {
require(version.toString().first() == '1') { "Needs to start with 1 thanks" }
}
require throws an IllegalArgumentException if it fails, which is the standard exception for "the value of this argument is invalid". Should the class be responsible for taking bad data and trying to "fix" it, or should the caller be handling that - and maybe not constructing an instance at all if it doesn't have valid data?
2. create a newInstance function that uses valid data, and keep the constructor private
class Thing private constructor(val number: Int){
companion object {
fun newInstance(num: Int): Thing {
return Thing(abs(num))
}
}
}
fun main() {
Thing.newInstance(-2).let { println(it.number)}
}
If it makes sense for the class itself to sanitise the input parameters, you can delegate construction to a function that takes care of that, and prevent things from calling the constructor directly with potentially bad data.
This can cause issues with e.g. serialisation libraries (which want to call the constructor directly) but in that case you could leave the constructor public, and just advise callers to call newInstance instead. Not ideal, but it's an option!

Related

Strange kotlin checkNotNullParameter error

we received a crash on Firebase for a kotlin method:
Fatal Exception: java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter code
at [redacted].DeliveryMethod.<init>(:2)
at [redacted].DeliveryMethodsUpdater$addSingleDMInAd$clientCall$1.invokeSuspend(DeliveryMethodsUpdater.kt:121)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
the model is this one:
class DeliveryMethod() {
lateinit var code: String
lateinit var name: String
lateinit var description: String
var isAddressRequired: Boolean? = null
var image: JSONObject? = null
var isDefault: Boolean = false
constructor(code: String) : this() {
this.code = code
}
constructor(code: String, name: String, description: String, image: JSONObject? = null) : this() {
this.code = code
this.name = name
this.description = description
this.image = image
}
}
and the method:
private suspend fun addSingleDMInAd(
adId: Long,
deliveryMethodCode: String
): JoinAdDeliveryMethod? {
var addedDeliveryMethod: JoinAdDeliveryMethod? = null
val clientCall = GlobalScope.async(Dispatchers.IO) {
val cd = CountDownLatch(1)
Client.getInstance().addDeliveryMethodInAd(
adId,
DeliveryMethod(deliveryMethodCode),
object : NetworkCallback<JoinAdDeliveryMethod> {
override fun onSuccess(result: JoinAdDeliveryMethod) {
addedDeliveryMethod = result
cd.countDown()
}
override fun onFailure(err: NetworkError?) {
addedDeliveryMethod = null
cd.countDown()
}
}
)
cd.await()
}
clientCall.await()
return addedDeliveryMethod
}
now, I understand that that the constructor for DeliveryMethod is being called with a null value for code, but I don't understand why the exception only come up at this point. As you can see, the method param is also marked as non-null, and so are previous methods. Shouldn't the exception be thrown way before getting to the constructor call for DeliveryMethod?
EDIT:
this is the caller of addSingleDMinAd():
fun addDeliveryMethodsInAd(
adId: Long,
deliveryMethodCodesToAdd: List<String>,
completionListener: (List<JoinAdDeliveryMethod?>) -> Unit
) {
GlobalScope.launch {
val updatedDms: MutableList<JoinAdDeliveryMethod?> = mutableListOf()
for (deliveryCode in deliveryMethodCodesToAdd) {
addSingleDMInAd(adId = adId, deliveryMethodCode = deliveryCode).run {
updatedDms.add(this)
}
}
completionListener.invoke(updatedDms)
}
}
this is the java caller of the addDeliveryMethodsInAd() (this is inside an Android Service):
new DeliveryMethodsUpdater().addDeliveryMethodsInAd(
result.getId(),
deliveryMethodCodesToAdd,
updatedDMs -> {
// on failed delivery method request
for (JoinAdDeliveryMethod updatedDm : updatedDMs) {
if (updatedDm == null) {
//show error
break;
}
}
AdDetailUpdater
.getInstance()
.updateSubscribersWithDeliveryMethods(result.getId(), updatedDMs);
return null;
}
);
Shouldn't the exception be thrown way before getting to the constructor call for DeliveryMethod?
Within Kotlin, it's not possible for a non-null parameter to be given a null value at runtime accidentally (because the code wouldn't have compiled in the first place). However, this can happen if the value is passed from Java. This is why the Kotlin compiler tries to protect you from Java's null unsafety by generating null-checks at the beginning of some methods (with the intrinsic checkNotNullParameter you're seeing fail here).
However, there is no point in doing that in private or suspend methods since they can only be called from Kotlin (usually), and it would add some overhead that might not be acceptable in performance-sensitive code. That is why these checks are only generated for non-suspend public/protected/internal methods (because their goal is to prevent misuse from Java).
This is why, if you manage to call addSingleDMInAd with a null argument, it doesn't fail with this error. That said, it would be interesting to see how you're getting the null here, because usually the checks at the public API surface are enough. Is some reflection or unsafe cast involved here?
EDIT: with the addition of the calling code, this clears up the problem. You're calling a method that takes a List<String> from Java, with a list that contains nulls. Unfortunately Kotlin only checks the parameters themselves (in this case, it checks that the list itself is not null), it doesn't iterate your list to check for nulls inside. This is why it didn't fail at the public API surface in this case.
Also, the way your model is setup is quite strange. It seems the lateinit is lying because depending on which constructor is used, the properties may actually not be set at all. It would be safer to mark them as nullable to account for when users of that class don't set the value of these properties. Doing this, you won't even need all secondary constructors, and you can just use default values:
class DeliveryMethod() {
var code: String? = null,
var name: String? = null,
var description: String? = null,
var image: JSONObject? = null,
) {
var isAddressRequired: Boolean? = null
var isDefault: Boolean = false
}
Other things of note about addSingleDMInAd:
don't use GlobalScope in this case. If you need to run short-lived coroutines, provide them with a smaller scope that is cancelled when the work is not needed anymore - it ensures no coroutines are leaked. You can read more about the potential pitfalls of GlobalScope and possible replacements in its own doc. That said, you probably shouldn't be starting a coroutine at all anyway here, see next point.
don't use async {} if you use await() right after - it's pointless to start something asynchronous if you wait for it right there. If you want to switch the context to IO, use withContext(Dispatchers.IO) { ... } instead. That said, you shouldn't even need to use the IO dispatcher here, see next point.
don't use CountDownLatch for this purpose. The proper way to encapsulate an async API as a suspend function for coroutines is to use suspendCancellableCoroutine (check its doc, it provides an example on how to use it). Once you use this, there is no need anymore for Dispatchers.IO because it will not be blocking the current thread anymore.

Access Implementation's property on variable of type Interface

I'm trying to access the delegate of the property (id) of a class (FooImpl). The problem is, this class implements an interface (Foo), and the property in question overrides a property of this interface. The delegate only exists in the class (not that it could exist in the interface).
The problem is that using the :: operator on a variable of type Foo always returns the property of Foo, not that of the actual instance. The problem in code:
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty0
import kotlin.reflect.jvm.isAccessible
interface Foo {
val id: Int
}
class FooImpl(
id: Int,
) : Foo {
override val id: Int by lazy { id }
}
val <T> KProperty<T>.hasDelegate: Boolean
get() = apply { isAccessible = true }.let { (it as KProperty0<T>).getDelegate() != null }
fun main() {
val foo: Foo = FooImpl(1)
println("foo::id.hasDelegate = ${foo::id.hasDelegate}")
println("(foo as FooImpl)::id.hasDelegate = ${(foo as FooImpl)::id.hasDelegate}")
}
This prints:
foo::id.hasDelegate = false
(foo as FooImpl)::id.hasDelegate = true
But this requires compile-time knowledge of the correct implementation. What I'm looking for is accessing the correct propert without having to specify FooImpl there.
The information is present at runtime because the least (!) intrusive workaround I have found so far is adding fun idProp(): KProperty0<*> to Foo and override fun idProp() = ::id to FooImpl and accessing the property using that.
Is there any better way than that?
I came up with this, but I don't know if there's a better way. The problem to work around is that getDelegate() has to return an actual instance of the delegate, so you need an instance of the class to be able to retrieve a delegate instance. It would really be nice if there was a hasDelegate property built in. Your version of hasDelegate will crash from the cast on unbound KProperty1's, which is all we have to work with when the specific class is unknown.
So to retrieve the delegate instance, we need to do search the class instance's member properties by name, which gives us a KProperty with covariant class type of the super-class type. Since it's covariant, we can call a consuming function like getDelegate() without casting to the invariant type. I think this logically should be safe, since we are passing an instance that we know has the matching type for the ::class that we retrieved the property with.
#Suppress("UNCHECKED_CAST")
fun <T: Any> KProperty1<T, *>.isDelegated(instance: T): Boolean =
(instance::class.memberProperties.first { it.name == name } as KProperty1<T, *>).run {
isAccessible = true
getDelegate(instance) != null
}
fun main() {
val foo: Foo = Foo2()
println("foo::id.hasDelegate = ${Foo::id.isDelegated(foo)}")
}
The problem here is that the owner of the property is resolved on compile time, not on runtime. When you do foo::id then foo (so FooImpl) become its bound receiver, but owner is still resolved to Foo. To fix this we wound need to "cast" property to another owner. Unfortunately, I didn't find a straightforward way to do this.
One solution I found is to use foo::class instead of foo::id as it resolves KClass on runtime, not on compile time. Then I came up with almost exactly the same code as #Tenfour04.
But if you don't mind using Kotlin internals that are public and not protected with any annotation, you can use much cleaner solution:
val KProperty0<*>.hasDelegate: Boolean
get() = apply { isAccessible = true }.getDelegate() != null
fun KProperty0<*>.castToRuntimeType(): KProperty0<*> {
require(this is PropertyReference0)
return PropertyReference0Impl(boundReceiver, boundReceiver::class.java, name, signature, 0)
}
fun main() {
val foo: Foo = FooImpl(1)
println(foo::id.castToRuntimeType().hasDelegate) // true
}
We basically create a new instance of KProperty, copying all its data, but changing the owner to the same type as its bound receiver. As a result, we "cast" it to the runtime type. This is much simpler and it is also cleaner because we separated property casting and checking for a delegate.
Unfortunately, I think Kotlin reflection API is still missing a lot of features. There should be hasDelegate() function, so we don't have to provide receivers, which is not really needed to check if property is delegated. It should be possible to cast KProperty to another type. It should be possible to create bound properties with some API call. But first of all, it should be possible to do something like: Foo::id(foo), so create KProperty of the runtime type of foo. And so on.

how to use a receiver with parameter value in Kotlin?

Ive been trying to do the following:
As an exercise
I need to create a data class with some functions.
One method will use a receiver with a parameter to verify if the parameter is bigger than a class value
The result will be a boolean.
So far I have this:
data class Club(val name: String, val members: Int) {
fun isABigClub(code: Int.() -> Boolean) : String {
val isBig = code(this.members)
return " Your club is a big club? ${isBig}"
}
}
I created the class club with a name and number of members.
I create a method call isABigClub that only checks if is bigger than certain number I send...
I invoke it in this way
fun main() {
val isBigClub = club.isABigClub { this > 9 }
println(isBigClub)
}
Works as expected.
Reading the documentation https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver and other posts What is a purpose of Lambda's with Receiver? What is a "receiver" in Kotlin? find no way to use my receiver while accepting a parameter.
I want to encapsulate the logic of compare inside the data class... something like this
fun isTheBiggestClub(club: Int.(biggestClub: Int) -> Boolean) : Boolean {
return club(this.members, SOME_RECEIVED_VALUE )
}
where I actually want to send something similar on my previous example this > 9
Something like club.isTheBiggestClub { this(10) }
I have no idea how to send it or how to read it on the return, find no information about it yet, is it even possible? any idea how?
Your club method returns a Boolean while the isTheBiggestClub method returns String. This might be the issue.

How can I assign a value to KMutableProperty parameter?

In a method I would like to receive KMutableProperty as parameter and assign a value to it.
Another question is what is the correct way of passing a parameter into such a method.
Basically I would like to have something like that:
class MyBinder {
...
fun bind(property: KMutableProperty<Int>): Unit {
property.set(internalIntValue)
}
}
And then call it in another class
myBinder.bind(this::intProperty)
Kotlin 1.0 does not allow the this::intProperty syntax, but this is being worked currently and will be available soon as a part of the early access preview of 1.1 (issue, KEEP proposal).
With this in mind, I'd consider doing what you're describing in another way, for example making bind accept a lambda which sets the property:
class MyBinder {
fun bind(setProperty: (Int) -> Unit) {
setProperty(internalIntValue)
}
}
...
myBinder.bind { intProperty = it }
Anyway, to answer your question about setting the value of KMutableProperty: to set the value of some property or, technically speaking, to invoke the property setter, you should know its arity, or the number of parameters that property (and its getter/setter) accepts. Properties declared in a file do not accept any parameters, member properties and extension properties require one parameter (the receiver instance), while member properties which are also extensions take two parameters. These kinds of properties are represented by the following subtypes of KMutableProperty respectively: KMutableProperty0, KMutableProperty1, KMutableProperty2 -- the number means the arity and their generic type parameters mean the types of receivers. Each of these property types has a set method with the corresponding parameters. Some examples:
fun setValue(property: KMutableProperty0<Int>, value: Int) {
property.set(value)
}
fun setValue(property: KMutableProperty1<SomeType, Int>, instance: SomeType, value: Int) {
property.set(instance, value)
}
Note that there's no set (or get) method in the abstract KMutableProperty interface precisely because it's impossible to declare it, not knowing the number of required receiver parameters.
Additionally to Alexander's answer, you can try something like this:
import kotlin.reflect.KMutableProperty
class Binder {
val internalIntValue = 10
fun bind(self: Any, aProperty: KMutableProperty<Int>) {
aProperty.setter.call(self, internalIntValue)
}
}
class Foo {
var bar = 1
fun changeBar() {
Binder().bind(this, Foo::bar)
}
}
fun main(args: Array<String>) {
val foo = Foo()
assert(1 == foo.bar)
foo.changeBar()
assert(10 == foo.bar)
}
A more robust/safe way to do the same thing:
fun <T> bind(self: T, aProperty: KMutableProperty1<T, Int>) {
aProperty.set(self, internalIntValue)
}
My thanks to Alexander. His answer gave me the previous idea.

How do I cast a JavaScript object to a Kotlin object?

I have received a JavaScript object in response to a remote HTTP request. I have a kotlin model (trait) that defines the various fields I expect on the object (the nullable ones are optional).
First, I want to do an is check to make sure my object is in fact of the expected type. I initially tried payload is MyModel but that doesn't work due to the way the is operator is written in kotlin.js.
Second, I want to cast to MyModel so I can get auto-complete, etc. on the object while I work with it. Normally, the is alone would be enough but since that doesn't work I need something for this problem as well.
I would like to avoid manually populating my object from a dynamic. I wouldn't mind doing this so much if I could use by Delegates.mapVal(...) but that requires a Map<String, Any?> and I don't know how to get my dynamic/Any? payload into a Map<String, Any?>.
1) We don't have structure check for is in performance reasons.
I don't sure that we need generic solution for this, but anyway I created issue about it, feel free to vote or star it to get updates.
2) is enough if you use smart cast, like:
if (payload is MyModel) {
// call MyModel members on payload
}
But don't forget about (1) :)
3) You can write something like:
class MapDynamic<out V>(val d: dynamic) {
public fun get(thisRef: Any, desc: PropertyMetadata): V {
return d[desc.name]
}
}
class Foo(data: dynamic) {
val field: Int by MapDynamic(data)
}
fun main(args : Array<String>) {
val f = Foo(object { val field = 123 })
println(f.field)
}
But it looks too verbose, but You can add additional logic for e.g. when data don't have requested field. And if You don't need custom logic I think cast is enough.
For the second part, the cast, you can do:
fun responseHandler(payload: dynamic) {
val myModel = payload as MyModel
}
or
fun responseHandler(payload: dynamic) {
val myModel: MyModel = payload
}
This will throw an NPE if payload is null, but it won't actually validate that the payload matches MyModel. In particular, you may end up with null fields/properties that shouldn't be if the payload was missing those fields/properties.