Kotlin static functions : companion object, #JvmStatic #JvmField - android

I have just started messing around with the Kotlin programming language, which is pretty much cooler than Java. I have some doubts related to static methods and fields:
Q1: Official document says
Kotlin can also generate static methods for functions defined in named
objects or companion objects if you annotate those functions as
#JvmStatic.
But if you see below I can access bar() method as a static method, which works without using #JvmStatic annotation. But on official doc its throwing error -> Kotlin static method.
Class C{
companion object{
#JvmStatic
fun foo() { }
fun bar();
}
}
fun main(args: Array<String>) {
C.foo();
C.bar(); //this line works fine
}
Q2: Do I really need #JvmStatic and #JvmField to make things static?
As you can see with companion object, things are working as expected.

You can access members of a companion object as C.bar() in Kotlin, but not in Java. Without #JvmStatic, you would need to use C.Companion.bar() in Java, just as said in the docs.
Note that, without #JvmStatic, the function is compiled to an instance (non-static) method that is called on C.Companion in Java (and Kotlin simply shortens it to a call on C, but it's the same under the hood), so yes, you need either #JvmStatic and #JvmField to make a declaration in a companion object compile into a static member.
Basically, #JvmStatic and #JvmField are tools for Java interoperation that help with creating Java-friendly APIs, and if you don't need to call the Kotlin members from Java (e.g. they are internal to your Kotlin project, or you are developing a library that is unlikely to be used with Java), you can leave them as they are.

Yep, you do need #JvmStatic. The problem with your code that you call it in Kotlin while in documentation code was called in Java.
To be more precise, this code won't compile:
public void main(String[] args) {
C.foo(); // Ok
C.bar(); // Not ok
}
Kotlin knows about function in companion object so you can call it on class directly, while Java doesn't know anything about it. So you annotate any function with #JvmStatic and it becomes visible from Java code as static method.
And just to clarfiy - purpose of #JvmStatic is interop with Java code. If you write your application in Kotlin only you don't need #JvmStatic at all.

The documentation ("page 2") refers to the case where you call the function from Java, not Kotlin.
When you only use Kotlin, there is no need for the annotation. Instead use the way you declared your bar() method. So you can call C.bar()

Related

Use Companion object in kotlin android is a good practice?

I have ever used Java to programming in android, but a few weeks ago I started to learn kotlin, when I use Java I tried to use object oriented approach and use the less possible static objects or instances, so when I see some materials in internet about some implementations of consume web services in kotlin I see something like this:
/*call of method from activity*/
val message = WebServiceTask.getWebservice(getString(R.string.url_service))
/*Class to do the call to webservice*/
class WebServiceTask {
companion object {
fun getWebService(url: String): WebServiceResponse {
val call =
RetrofitInstance.getRetrofit(url).create(ApiService::class.java).getList()
.execute()
val webServiceResponse = call.body() as WebServiceResponse
return user
}
}
}
/*Class to get Retrofit instance*/
class RetrofitInstance {
companion object{
fun getRetrofit(url: String): Retrofit {
return Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
}
}
Like you see i use companion object in two classes and according to i read companion object is equivalent to static instance in java, so my question is:
is this code following object oriented programming?, this aproach is recommended?, in case that answer is no and which is the best implementation for this code in object oriented
Yes, companion object is Kotlin's equivalent of static members in Java. Everything that applies to static, applies to companion object as well.
The use of companion object depends on how it interacts with the state of class's object.
If you are using some methods which are totally Pure functions Or Some final values which you need to provide access to outside the class itself, in that case using companion object makes total sense.
It is recommended for the above conditions because it does not interfere with the state of the class's object.
So, for the given code snippet it is a valid use of companion object.
Observe that methods inside companion object do not interact with something which is not passed to them as parameters. Everything that you see is created/initialized or used inside the methods only, Just the result it gets out.
Note:
However, if your companion object members(values or functions) interfere with the state of the object, it will cause leaks, which will lead you to troubles you have never faced before.
Yes, it is equivalent to static. No, it is not recommended, as it leads to problems with mocking for testing, for example.

How to use a Kotlin extension function on a class?

I have a pretty short question about an extension function that would help clear some of my code. Basically I have some transformations on the hashCode of a class name and I want an extension function to do the transformations.
Example:
Getting the name hashCode: StateA::class.java.name.hashCode() where StateA is a simple class.
I want to the extension function like:
fun Class<*>.transformName(): String {
var hashString = this.javaClass.name.hashCode()
//Do my stuff on that hashString
return hashString
}
But this doesn't seem to work. When I apply the extension function with StateA.transformName(), the function gives me an error with Unresolved Reference.
I tried various things like applying the function to StateA::class or having the hashString equal to this::class.java.name.hashCode() but nothing works. Any tips?
You can't really achieve the StateA.transformName() syntax, as StateA just on its own refers to the companion object inside that class. So to get that syntax, you'd need to have a companion object inside every class that you want to use this extension on.
What you can do in a very general way is get the KClass that describes your class first. This gives you an object (the KClass instance) that you can then call an extension on:
fun KClass<*>.transformName() {
val clazz: Class<*> = this.java
clazz.name.hashCode()
}
StateA::class.transformName()
Another approach, which is less verbose on the call site could be a generic function like this, where the reified keyword allows you to access the concrete class that was used as the generic type parameter inside the function:
inline fun <reified T> transformName() {
val clazz: Class<*> = T::class.java
clazz.name.hashCode()
}
transformName<StateA>()

Prerequisite to create extension function in kotlin

I am learning Kotlin. As per I learnt, extension functions provides the ability to extend a class with new functionality without having to inherit from the class. I am creating extension function for okhttp3.RequestBody. But I am not able to get method in my activity.
Here is my extension function:
fun RequestBody.createPlainRequestBody(message: String): RequestBody = RequestBody.create(MediaType.parse("text/plain"), message)
while calling function as below I am getting unresolved function
RequestBody.createPlainRequestBody()
while I am creating extension function for toast I am getting perfect result as below:
fun Context.showToast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
by calling:
this#MainActivity.showToast("Upload successfully")
Can any one guide for how to resolve this?
Extension functions can be applied to instances of a particular class, but you're trying to call it on a class, as if it were a static method. Moreover, your extension function expects an argument and you're not providing any.
What you need in your case is a simple function that creates a RequestBody as you're not acting on any particular instance of RequestBody.
Under the hood an extension function is simply a static method where the first argument is the receiver object and any other argument is shifted by one. Your showToast extension function is equivalent to the following Java snippet:
public static void showToast(Context receiver, String message) {
Toast.makeText(receiver, message, ...).show();
}
That's why you can call Kotlin extension functions from Java.
Unfortunately, you cannot do this in OkHttp version 3, however, you
will able to do this in OkHttp4 which is being rewritten completely in
Kotlin, so all the classes will be compatible with Koltin.
You have to extends to its companion object. (You need to make sure that class has a companion object associated with it)
fun RequestBody.Companion.createPlainRequestBody(message: String): RequestBody {
return RequestBody.create(MediaType.parse("text/plain"), message)
}
And after that, you will be able to call it directly from its class.
RequestBody.createPlainRequestBody("message")
Or
RequestBody.Companion.createPlainRequestBody("message")
A companion object is a normal object that associated with or belongs to the class it's similar to static object in Java. In Kotlin, it's called companion object.

Dagger singleton vs Kotlin object

To define a singleton, should I use Kotlin object declaration or to make an ordinary Kotlin class and inject it using dagger? In my opinion the first option is definitely easier but there may be a reason to use dagger in this situation that I'm not aware of.
Option 1 (notice object keyword):
object SomeUtil {
// object state (properties)
fun someFunction(number: Long) {
// ...
}
}
Option 2 (notice class keyword):
class SomeUtil {
// object state (properties)
fun someFunction(number: Long) {
// ...
}
}
#Module
class AppModule {
#Provides
#Singleton
internal fun provideTheUtil() = SomeUtil()
}
class MainActivity : BaseActivity() {
#Inject internal lateinit var util: SomeUtil
}
UPDATE 2019-07-03
#Blackbelt said in comments that we should prefer option 2 for testability. But libraries like MockK can mock objects too. So do you still think option 2 is the preferred one?
You might want to reconsider the need of NumberFormatUtil being a singleton. It might be cheaper if you use #Reusable with Dagger or even a factory without any scope directly.
If NumberFormatUtil is fairly simple and only provides a few utility methods, no state and no need for mocking in tests, you could use an object implementation, maybe using #JvmStatic for Java-inter-operability. But then you could go for global utility (extension) functions as well:
package xyz
fun formatNumber(number: Long) {
// ...
}
fun Long.format() = formatNumber(this)
You should use option 2.
In software engineering, the singleton pattern is a software design
pattern that restricts the instantiation of a class to one "single"
instance. This is useful when exactly one object is needed to
coordinate actions across the system.
From: Singleton Pattern
So, a singleton is single instance in a scope. In case of Android, it is virtual machine instance running the app. In case you need custom scopes, you have to use option 2 only.
But, if you have only static methods inside the object you want to inject its better to keep them as global methods and even get rid of object. No need to inject anything. It is similar to a java class with only static methods (I mentioned this point as it is a usual way of creating Utility classes).
However, if the object also has some state. I would recommend going dagger way. The object way does not provide with dependency injection. It only creates a Singleton. Your purpose for using dagger is dependency injection.

Android studio convert to Kotlin: Use #JvmStatic in some cases

I have been using Kotlin over Android for quite intensively. It does make programming fun again.
Still, in some cases (mostly util classes where the name should be short and handy), when automatically converting Java to Kotlin, I would love to have an option to use #JvmStatic on static methods rather than converting callers to MyClass.Companion.Bar.
That is, in some specific cases, it would be nice to have
public static foo(Barian bar)
converted to
#JvmStatic
fun foo(bar:Barian)
so I can maintain the short calling syntax from Java:
MyClass.foo(bar)
rather than
MyClass.Companion.foo(bar)
Obviously, in most cases I agree it's bad manners for many reasons such as future compatibility, non-Kotlin spirit and many more, but in a few cases it can keep Java code (that uses my classes) shorter.
You don't need to specify the Companion-namespace explicitly, when you decalre your "static" method like this:
class MyClass {
companion object {
fun foo() {}
}
}
In this case you still can call it via:
MyClass.foo()
But nevertheless having static methods is not a Kotlin-idiomic way and should be avoided by using other features of this language.

Categories

Resources