Call Java method with alternatives from Scala - android

I am trying to use the put method of the ContentValues class in the Android API from Scala, but I can't figure out a way to make Scala narrow down the type of list elements. For example :
val a: List[(String, Any)](...)
val cv = new ContentValues
for ((k,v) <- a) cv.put(k,v)
...yields an error that roughly says it can't resolve the "overloaded put method with alternatives put(String, String), put(String, Int),...".
My intuition is telling me I should probably use reflection, but I can't figure out how to do it exactly. Any pointer?

The type of your list is too imprecise. ContentValues.put has overloads for a number of types, but they are all specific (Integer, Float, etc.), and no alternative for Object.
You can:
make the list type more precise, in case the list has only elements of one type (say, Int).
use an HList, but beware of type wizardry. It may be overkill in this case
as a last resort, do a type test:
for ((k, v) <- a) v match {
case n: Int => cv.put(k, v)
case d: Double => cv.put(k, d)
//...
}

This is a very famous and common problem in Scala. The type system works correctly, and developers are simply not used to it.
In strongly typed programming languages the compiler verifies rules on the types you are using and this prevents painful runtime errors. If you use reflection or casts you are allowed to force the type system and this can produce unexpected errors and problems at runtime.
Why would you want to break the rules which you largely benefit from ? A good reason is when you are designing a library and you know exactly what is going to happen in your internals (see scala collections).
When you end up using types such as Any or AnyRef you should be worried and ask yourself:
why I am going so up in the hierarchy ?
Am I probably using an anti pattern or a bad constructor for a strongly typed programming language?
In fact I guess you are, and I propose we further investigate together why you have a List[(String,Any)]. Let's assume you had no problems in putting data into the ContentValues , what if later you would need to extract something from there? How would you know if it was an Int, a Double, a Float?

Related

Is there a way to convert a string into literal code that you can use in Kotlin?

This might be a very silly question, but I am logging the methods that are triggered in my app as strings. When an issue is submitted, I would like to automatically input the text of the strings as parameters for methods. E.g:
For method:
fun assignPot(potType: PotType, ball: DomainBall, action: PotAction) {...}
I'd like to somehow call method:
assignPot(FOUL(2, BLUE(5), SWITCH))
From String:
"FOUL(2, BLUE(5), SWITCH)"
The only workaround I can think of is to split the string and create a when -> then function to get actual classes from strings, but I wondered if there's a more concise way for this.
This is not what you want to do. You should design your app in a way that prevents users from providing input similar to actual code.
However, you can achieve this. Complex parsings like this oftenly use regex-based approaches.
As you said, you should map your string part to class. If your PotType is enum, you can do something like
val re = Regex("[^A-Za-z\s]")
val reNumbers = Regex("[^0-9\s]")
// get classes
val classNames = originalString.replace(re, "").split(" ")
// get their constructor numerical arguments
val classArgs = originalString.replace(reNumbers, "").split(" ")
After that you can implement mapping with when expression. You probably will use some collection of Any type.
As you see, this sadly leads you to parsing code by code. Concise way to solve is to implement your own script compiler/interpreter and use it in your application :) That will later lead you to dealing with security breaches and so on.
If you are logging problematic method calls and want to repeat them immediately after issue is submitted, you probably want to programatically save the calls to lambdas and call them when you receive an issue log.

What does the single exclamation "!" mean after the type in Kotlin?

I'm learning to Develop Android Apps using Kotlin. I previously used to Develop using Java. While coding in Android Studio, I can see that the return types, parameters, etc. used in the Lambdas, methods, etc. are written as View!.
I know that the ? after the type in Kotlin means a Nullable type. Though what does the ! mean.
For example:
val item = mySpinner.selectedItem
The return type is Any! What does the ! mean? Is it the same as a Nullable type i.e. Any? ?
Thanks.
It's a platform type indicating that Kotlin is not sure whether it will be null or not null, it's like saying "maybe".
platform types can't be mentioned explicitly in the program, so there's no syntax for them in the language. Nevertheless, the compiler and IDE need to display them sometimes (for example, in error messages or parameter info), so there is a mnemonic notation for them:
T! means "T or T?",
(Mutable)Collection! means "Java collection of T may be mutable or not, may be nullable or not",
Array<(out) T>! means "Java array of T (or a subtype of T), nullable or not"
And because it can either be null or not null, it is up to you how you will treat it.
Also check this another post

Why is there no ClosedRange IN ClosedRange Operator in Kotlin?

Let val a, b, x, y: LocalDate.
Then a..b in x..y is no valid expression: ClosedRange in ClosedRange is undefined.
However, (a..b).toRange() in (x..y).toRange() does work since Range in Range is defined.
Except when b < a or y < x since ranges can't be negative.
Please note that i'm developing for Android, which is where the .toRange() originates: androidx.core/core-ktx
3 Questions arise
Is this an oversight of the android / kotlin team?
Is this a deliberate decision? (e.g. because of some unintuitive behavior)
in case it's a deliberate decision: how to best circumvent it?
ClosedRange is part of the Kotlin standard library. Range is part of Android's SDK. These two libraries are made by different companies and were made with different goals in mind, so you can't necessarily call it an oversight. Maybe the Kotlin developers decided the meaning of a range being in another range might be ambiguous, and the Android developers didn't. Or maybe the Kotlin developers have a higher criteria for what functions are useful enough to include in the standard library.
One difference between the two classes is that the Android Range class forbids a range with the start value higher than the lower, but Kotlin ClosedRange allows it. This makes the concept of a ClosedRange containing another more ambiguous than with Ranges. What would it mean for a negative-direction ClosedRange to be in another ClosedRange? It's empty, but it has a span.
I'm not sure what you mean by circumventing it. You can define your own extension function for ClosedRange if you want, with behavior that depends on how you want to interpret the meaning of an empty range being contained.
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
other.start in this && other.endInclusive in this
// or
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
other.isEmpty() || (other.start in this && other.endInclusive in this)
// or
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
(other.isEmpty() && (other.start in this || other.endInclusive in this)) ||
(other.start in this && other.endInclusive in this)
Disclaimer: I'm not an Android developer and have no experience with androidx.core, so take my answer with a pinch of salt.
So assuming that you can do a..b to create a ClosedRange (which is something not available by default in the Kotlin stdlib, but maybe core-ktx defines its own extension for that), according to the Kotlin documentation, x in y gets translated to y.contains(x). Now, ClosedRange defines some contains methods, but none of them accepts another ClosedRange as a parameter, hence your error.
Now, apparently the Android stdlib defines its own concept of Range, which is unrelated to Kotlin's ClosedRange (as one does not extend the other). However, core-ktx defines a function to transform a ClosedRange to a Range, and that function is .toRange(). In addition to that, Range defines a contains(Range) method, hence why the second example compiles correctly.
So to summarise: Kotlin doesn't allow (1) to create ranges of dates by default, and (2) to check if one range is fully included in another range. However, you can easily overcome (1) by creating your own function to create a ClosedRange for dates (by creating a rangeTo extension function), and (2) by creating your own contains(Range) function.
Coming back to why a..b works when using core-ktx, I can't find a satisfactory answer. That library contains a rangeTo extension function to create a range out of any Comparable (and LocalDate is-a Comparable), but that function returns a Range, not a ClosedRange, so I'm not sure why a..b in x..y doesn't work in the first place.

Android Studio 4.2.2 - Why debbuger doesn't evaluate parameter in a inner funcion?

Android Studio 4.2.2 evaluates a local and global variable, but doesn't evaluate parameter funcion when is inside a inner function.
Until the previous version this worked perfectly.
fun a(p:param) {
fun b(){
var v = p+1 // Here
}
}
Suppose that one try to evaluate the parameter p in the line with comment
// Here with Alt F8
The message in evaluate window is
Cannot find the local variable 'p' with type
This hurts a lot because it forces you to replicate the parameter as a local variable in each routine to be visible in the debugger.
var p = p
Has anyone noticed this? Is there any workaround?
Notice that Variables windows display a parameter with $ prefix, but it also doesn't work in evaluate window.
I've posted this issue in JetBrains.
First things first:
Is there any workaround?
Yes, bind the parameter p to a local variable inside b:
fun a(p: Param) {
fun b() {
val p = p
var v = p + 1
}
}
and it will all work as expected.
The root cause is slightly more convoluted.
Kotlin grew up on a language tool chain tied very closely to the IntelliJ language plug-in for Kotlin. The original JVM compiler was a code generator that consumed the data structures of semantic information used by the IntelliJ language plug-in for diagnostics, quick fixes, and so on.
This architecture was very good for providing language support to an IDE, but less so for building a fast batch compiler.
With Kotlin 1.5, the "IR backend" was enabled as the default code generator for JVM. It uses a more traditional compilation approach of gradually translating an abstract syntax tree (AST) to progressively simpler intermediate languages before outputting JVM byte code.
With this change, a number of new compilation strategies were implemented. In particular, in the old strategy, local functions were treated as lambdas bound to a local variable. Their free variables were recorded in the state of the allocated Function object at the declaration site. When the local function is called, it translates to a call to invoke on that function object. End of story.
In the new approach, local functions are lifted into private static functions on the same class as the outer function. Free variables in the local function are closed by parameters to that lifted function, and instead of recording them at the declaration site in a lambda object, they are passed at the call site as arguments.
In your example. the p is free in the inner function b, so an additional parameter $p is added to b.
While this works for "release builds", the surrounding tooling has not caught up until recently. The "Evaluate Expression..." mechanism has been hit particularly hard, as it's quite sensitive to the layout and shape of the resulting JVM byte code.
In this specific case, it was a matter of adjusting the mechanism in the debugger that maps free variables of the fragment to local variables at the breakpoint. With this change aimed at 2022.3, you should hopefully stop noticing this specific bug, and a host of other improvements as a new and revised version of the evaluation mechanism ships.

Why is Google pushing new Devs to Kotlin for Android App? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
Considering that starting from version 8 Java is much more clear and readable than Kotlin.
At the and Kotlin code get translated into Java anyway and it is very hard to understand what the code is really doing without plenty of comments that explains it, or autocompletition.
For example:
override fun onClick(v: View) {
val amountTv: EditText = view!!.findViewById(R.id.editTextAmount)
val amount = amountTv.text.toString().toInt()
val action = SpecifyAmountFragmentDirections.confirmationAction(amount)
v.findNavController().navigate(action)
}
How do I know what kind of object is the val "action"?
Considering that starting from version 8 Java is much more clear and readable than Kotlin
Its just matter of taste, everybody has his own opinion, similar to your consideration Google team may found Kotlin good option to be more clear and concise.
Why pushing new dev so much on kotlin if it has nothig more than java?
Kotlin is alot different than just plain Java, the docs itself say much about it, here's brief differences:
Null-safety - Kotlin's type system is aimed at eliminating the danger of null references from code, also known as the The Billion Dollar Mistake.
Your app won't even compile until you remove all possibilities of NPE, otherwise you decide to axing your own feet by null-assertion operator (!!)
Coroutines - Light weight implementation of concurrency model, not only limited to multi-threading but also to the extent of doing deep-recursion, shared mutable-state and structured-concurrency, and also provides a lot of standard utilities for faster development like Flows. Being a lightweight implementation it is slightly faster in many situations than its competitors like RxJava.
Immutability - Proper handling of Collections (difference in read-only and mutable).
Similar goes to variables, Kotlin by default instructs you to use val until you required to change it later in order to provide a thread-safety.
Declaration-site Variance - Kotlin allows you to specify generic variances at declaration-site that will save you a lot of time, and hence less bugs.
Proper function types (i.e. lambda) and higher order functions - There's native support for the lambda expressions, and the support for the inline function makes it possible to counter the performance overhead of memory allocations (both for function objects and classes) and virtual calls introduce runtime overhead.
Smart-casts - no need to cast an object when checks have been made.
if (variable is String) {
println(variable.length) // no need to cast to String :P
}
Functional extensions - let, run, also, apply, with, use. These are very useful in concise code and hence boosts productivity.
// Java version
var a = Api.result();
Log.i(Tag, a.toString());
return a;
// Kotlin version
return Api.result().also { Log.i(Tag, it.toString()) }
Default parameters - You can mark a field as optional and just use 1 single function which is easier to manage later on rather than overloading function like 5 times and manage them all when updating a piece of code.
Native support for delegation - Defining getters and setters once and use them for as many field/properties as you want. There are delegates provided by std-lib like lazy (do-not allocate memory in RAM till property is accessed for the first time), observable (observe the changes in variable with both old and new value), etc.
Delegation of classes - You can implement a class using another object, useful when you want to extend some functionality of class but want to let other untouched. For examples see: Delegation of Classes
Inline functions and reified generics - In java it is impossible to use generics inside of a function because of JVM type-erasure. But this is not the case in Kotlin, you can embed the function into the callsite (at the compile time) using inline modifier and access generics via making it reified.
Destructing Declarations - Create multiple variable in same line using a destructing object, see Kotlin: Destructuring Declarations for examples.
Edit:
Forgot to put the answer to the code block, the amount has the same type returned by toInt(), and action has the same type as returned by confirmationAction(amount). Using an IDE will show that to you the inferred types in front of the variable names, you can also jump at the sources through some Ctrl+MouseClick at the call-site.
type of val action is same as the return type of confirmationAction method in SpecifyAmountFragmentDirections class
It's just that you have been using Java for long time and new to kotlin so you finding kotlin hard to understand.It's just matter of time and once you start using it regularly you will find it easier to understand and read.Moreover lines of code usually becomes less in kotlin.
UPDATE based on comments-
Kotlin has some advantages in comparison to java like it is more safe against NullPointerException which all android developers face many times in java and it is less verbose and less code can mean chances of fewer bugs.So new developers are recommended to learn kotlin for android.

Categories

Resources