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.
Related
Introduction
Semantically speaking, classes and interfaces act as nouns and methods/functions act as verbs. This is something that I recently read in the Java to Kotlin and it is aligned with how the vast majority of the people naturally name methods and classes.
For example we would expect a Car class to have a getBrand method, not a GetBrand class with an invoke method returning the brand of the car.
However, while reading the recent Guide to app architecture from Google, I have came across their naming convention for use cases, where they suggest this naming:
verb in present tense + noun/what (optional) + UseCase
with the following syntax to use it in Kotlin (example from here):
class FormatDateUseCase(userRepository: UserRepository) {
private val formatter = SimpleDateFormat(
userRepository.getPreferredDateFormat(),
userRepository.getPreferredLocale()
)
operator fun invoke(date: Date): String {
return formatter.format(date)
}
}
Question
Looking at the code above, we just have a class acting as a function. Why does Google recommend using these classes instead os just using top-level functions? Am I missing something here?
Your statement is not completely correct: We don't "have a class acting as a function", but you can say that each instance of the class acts as a function. That is important, since for instance, the constructor of FormatDataUseCase has a parameter of type UserRepository.
So, if we wanted to convert the FormatDataUseCase into a top-level function, it would not have the same signature as the invoke function of FormatDataUseCase, but it should also have userRepository as an additional parameter:
fun formatDateUseCase(userRepository: UserRepository, date: Date): String {
val formatter = SimpleDateFormat(
userRepository.getPreferredDateFormat(),
userRepository.getPreferredLocale()
)
return formatter.format(date)
}
And that is probably the main advantage of the recommended approach: You can have often-needed parameters and values automatically injected when you inject the use case class. This hides the dependencies from the caller of the use case, and makes it more comfortable to use.
Also, in the example the SimpleDateFormat is just initialized once and then reused for every call of the function, but if we converted it to a function, we would need to create a new instance on each call.
I'm trying to create a fake class for my repository to test a view model.
As far as I understood, the key element here is to create two classes with a common interface so both classes would contain the same methods.
The problem is I get a Type mismatch when trying to initialize an object.
I tried to do the same in a simplified manner:
class fakeClass1 : fakeInterface {
override fun getAllData(): String {
return ""
}}}
class fakeClass2 : fakeInterface {
override fun getAllData(): String {
return ""
}}
interface fakeInterface {
fun getAllData(): String}
val fakeClass: fakeClass1 = fakeClass2()
But that didn't work either.
What am I missing?
Ok, I figured it out.
I was wrong to think that those two classes should be interchangeable.
I solved it by making the ViewModel take the common interface in its constructor instead of the actual repository class. This allows the ViewModel to take any class which implement this interface as it's repository.
I think you worked it out, but just so you're clear (this is an important, fundamental thing!)
val fakeClass: fakeClass1 = fakeClass2()
This is defining a variable called fakeClass that refers to an object with the fakeClass1 type. Then you assign an object with the fakeClass2 type.
But a fakeClass2 is not a fakeClass1, neither is a superclass of the other, so you can't treat one as the other. Your example is simple, but imagine you added coolFunction() to fakeClass1 - they'd now happen to have different structures, and trying to call that method on an object that doesn't have it would cause a crash.
The only thing those classes have in common, is that they both have the fakeInterface type - they are fakeInterfaces, and that guarantees they implement the stuff in that interface (your getAllData function in this case). So if you treat them both as that type instead:
val fakeClass: fakeInterface = fakeClass2()
you can use either one, because they're both fakeInterfaces (similar to how Ints and Doubles are different but they're both Numbers). Because fakeClass is now a fakeInterface, you can only access the functions and properties that a fakeInterface has - you can't call coolFunction() even if you happened to pass in a fakeClass1, because fakeInterface doesn't have that.
(You could cast the variable to fakeClass1, basically saying "oh by the way this object is actually this type as well", but at that point the type system can't guarantee you're correct unless you're explicitly checking fakeClass is fakeClass1, and it'll warn you if that's the case)
The Java tutorials are pretty good and they'll give you an overview about how the types each form a kind of "contract" you work with
I'm making an Android app using Kotlin for the first time using MVP pattern. My questions is, why do I need interfaces for View and Presenter as Kotlin provides higher order functions? Can't we just communicate using those higher order functions? Is the use of pattern without interfaces bad?
I have looked and read lots of article and tutorials but non answered my question. Is what I am doing in the code below a wrong practice? Can someone explain it to me?
In my Activity
override fun init() {
btn_login.setOnClickListener {
LoginPresenter.userLogin(et_emailAddress.text.toString(),et_password.text.toString()){
if (it){
//do something
}else{
//do something
}
}
}
}
My Presenter
object LoginPresenter {
fun userLogin(emailId: String, password: String, completion: (Boolean) -> Unit) {
//do something
completion(true)
}
}
Higher-order function costs
Kotlin official documentation on the cost of higher order functions
Using higher-order functions imposes certain runtime penalties: each
function is an object, and it captures a closure, i.e. those variables
that are accessed in the body of the function. Memory allocations
(both for function objects and classes) and virtual calls introduce
runtime overhead.
and if you're replacing all your interfaces with higher-order functions, you may end up with a bad performance.
2.
Interfaces can hold multiple functions, for which you'll need individual function params when using higher-order functions.
Consider the following case,
interface UserLoginInterface {
fun onLoginSuccess(loggedInUser: User)
fun onLoginFailure(error: ErrorResponse)
fun onRedirect(someOtherObjectWithDirectives: SomeDataClass)
}
To translate this to higher-order functions usage, You'll have to use three Function params
why do I need interfaces for View and Presenter as Kotlin provides higher order functions?
This is rather a common practice in software development. And while you may not use interfaces, there is a number of key points why interfaces are preferable. Off the top of my head:
with interface you can have multiple implementations of it without actually caring about the concrete type of the implementation. This is what you're missing with the higher order functions - you're restricted with the only type, LoginPresenter, when using the LoginPresenter.userLogin() method.
most of the design patterns is based on the separation of interfaces from their implementations. So programming into implementation rather than abstraction won't let you make use of those.
you won't be able to properly unit test classes that depend on other implementations as no mocking is possible in this case.
code maintenance and extension becomes much harder with concrete implementation.
Recently at my company a debate started after reviewing a different approach for writing heavy duty classes.
A big Java class holding component specific logic (no standard OOP principles made sense) had to be rewritten in Kotlin. The solution provided was splitting the logic in categories and the categories into separate files with internal extension functions to the main class.
Example:
Main.kt
class BigClass {
// internal fields exposed to the extension functions in different files
// Some main logic here
}
BusinessLogic.kt
internal fun BigClass.handleBussinessCase() {
// Complex business logic handled here accessing the exposed internal fields from BigClass
}
What are your thoughts on this? I haven't seen it used anywhere maybe for a good reason, but the alternative of thousand lines classes seems worse.
You have to consider that an extension function is nothing more than a function with an implicit first parameter which is referenced with this.
So in your case you'd have something like:
internal fun handleBussinessCase(ref: BigClass)
which would translate to Java as:
static void handleBussinessCase(BigClass ref)
But this could be assumed to be a delegate pattern, which could be encapsulated much cleaner in Kotlin as well.
Since the properties have to be internal anyhow, you could just inject these as a data class into smaller use-cases. If you define an interface around these (which would make the properties public though), you could create a delegate pattern with it and still reference each property with this in your implementation.
Here are some thoughts on making extension functions for the class:
It will be a utility function that will operate with the object you're extending, it will not be an object function, meaning that it will have access to only public methods and properties;
If you're planning to use class that being extended in unit tests, these methods (extensions) will be harder to mock;
Most likely they wont behave as you expect when used with inherited objects.
Maybe I missed something, so please read more about extensions here.
It´s a good idea to use kotlin extensions all over the code?
I miss a lot the extensions from iOS, but this is a good way to use those kind of things in android?
Refering to http://antonioleiva.com/kotlin-android-extension-functions/
Is there a better solution for this?
To expand a little bit more on Andrey Breslav's answer a bit, Kotlin extension functions do compile down to static java methods, so most general purpose extension functions carry no overhead. But there is one edge case you need to look out for that Jake Wharton calls out in the first few min of this talk at Google IO.
That is when you pass in higher order functions (lambdas), as a parameter to the extension function like so:
fun View.doSomething(block: () -> Unit) {
//do something
}
This code would take a performance hit because lambda's under the hood have to create an anonymous class under the hood which can eat up methods and cause class loading. This is a very simple fix by adding the inline keyword to the function which will essentially inline your code into all of this call sites functions so you will not take a performance hit each time the extension function is called.
inline fun View.doSomething(block: () -> Unit) {
//do something
}
Extension functions in Kotlin are compiled to normal Java methods. For example, when you define a function in your package it turns into a static method in a Java class. There's no overhead compared to simply calling a static utility