If I have app.kt file in kotlin, can I create instance like appKt()? Thanks.
Kotlin has top level function. For example I can write in app.kt:
val a = 123
fun abc() {}
appKt.abc()
my question is if I can create appKt instance and call instance method
Only classes can be instanced.
Instead of loose function fun abc() {}, this should be the method of a class:
class appKt() {
// private var a: Integer = 123
fun abc() {}
}
No, you can't put arbitrary code at the top level.
You can put only definitions of classes (just as in Java), objects, functions, and properties.
It wouldn't make much sense to put loose code there, anyway: when would it run?
It's not clear what you're trying to achieve with this. If you want some code that gets run when your program starts up, then you could put it into a top-level function — but you'd then have to call that function (e.g. from your main() method). Or you could put it in the init block of the companion object to a class that you know will be loaded. Or if you're using a framework such as Android or Spring, then that will probably provide ways to specify code to be run at start-up.
Related
I am new to kotlin and I want to make an abstract/open class or interface, something that can be implemented by other classes. Let's call it Test. Now Test needs to have a HashSet (the docs say it requires less memory than a normal set) that every derived class will implement and fill with its own values.
interface Test {
val players: HashSet<String>
}
class Supa: Test {
override val players = hashSetOf<String>()
fun later() {
players.add("new player")
}
}
fun main() {
Supa().later()
println(Supa().players)
}
The above will output []. It seems that for some reason players doesn't get updated. After playing around in the kotlin playground I found out that if I print players from inside later() it will show the added element. Maybe it creates a new instance of player that exists in the scope of the function?? Could someone please show me how I can make an abstract hashSet that the derived class can override and fill with values that stay in the set?
The problem here is that you create two separate instances of Supa. You invoke later() on one of them and then print players of another one. Each Supa() creates a new instance.
You need to store Supa instance inside a variable and use it in both places:
val supa = Supa()
supa.later()
println(supa.players)
This isn't really specific to Kotlin. Your code would work the same in other languages as well.
I am calling a function in a class S3FileOperationsAdapter from the main function in my kotlin code. I am injecting the class S3FileOperationsAdapter in the main function file. So it looks like
class Runner {
#set:Inject
lateinit var s3FileOperationsAdapter: S3FileOperationsAdapter
fun main(args: Array<String>) {
s3FileOperationsAdapter.readFunction()
}
}
Now the issue is:
When I try to run the above code, I get the error Error: Main method is not static in class com.amazon.bram.sim.BatchJobRunner, please define the main method as:. This is understandable.
And we can only make a static function within an object in kotlin. So upon doing that, I cannot Inject the dependency, because Dagger does not support injection into Kotlin objects. So it feels like a deadlock.
My question is, I want to inject the dependency in this file anyhow so that I can call the respective function. And I am calling this function from the "fun main()" in kotlin. How can I achieve this? Has anyone ever faced this before?
In order to inject anything in Dagger, you must first create an instance of your component. Since no code at all will run before fun main(), this needs to be done during main itself (or in a field initializer).
After creating an instance of the component, you can ask it for an instance of S3FileOperationsAdapter directly.
fun main(args: Array<String>) {
// Create the component.
val component = DaggerMyComponent.create()
// or use the Component.Builder or Component.Factory you defined for MyComponent.
// Get an object from the component.
// This method should be defined in your component interface.
val adapter = component.s3FileOperationsAdapter()
// Use the object.
adapter.readFunction()
}
If your actual code is more complicated, with multiple injected objects and a longer main() function, this may be a bit unwieldy. In that case, you can extract your current main() into its own class and let Dagger provide that class in main().
I've bumped into this code and I'm not sure why would anyone do this. Basically the author decided for making the class constructor private so that it cannot be instantiated outside the file, and added a public method to a companion object in the class that creates a new instance of this class. What is the benefit of this approach?
This is what I found:
class Foo private constructor(private val arg1: Any) {
//more code here..
companion object {
fun newFoo(arg1: Any) = Foo(arg1 = arg1)
}
}
Why is it better than this?
class Foo(private val arg1: Any) {
//more code here..
}
There are several benefits to providing a factory method instead of a public constructor, including:
It can do lots of processing before calling the construstor. (This can be important if the superclass constructor takes parameters that need to be calculated.)
It can return cached values instead of new instances where appropriate.
It can return a subclass. (This allows you to make the top class an interface, as noted in another answer.) The exact class can differ between calls, and can even be an anonymous type.
It can have a name (as noted in another answer). This is especially important if you need multiple methods taking the same parameters. (E.g. a Point object which could be constructed from rectangular or polar co-ordinates.) However, a factory method doesn't need a specific name; if you implement the invoke() method in the companion object, you can call it in exactly the same way as a constructor.
It makes it easier to change the implementation of the class without affecting its public interface.
It also has an important drawback:
It can't be used by subclass constructors.
Factory methods seem to be less used in Kotlin than Java, perhaps due to Kotlin's simpler syntax for primary constructors and properties. But they're still worth considering — especially as Kotlin companion objects can inherit.
For much deeper info, see this article, which looks at the recommendation in Effective Java and how it applies to Kotlin.
If you want to change Foo into an interface in the future the code based on the method will keep working, since you can return a concrete class which still implements Foo, unlike the constructor which no longer exists.
An example specific to android is, that Fragments should be constructed with an empty constructed, and any data you'd like to pass through to them should be put in a bundle.
We can create a static/companion function, which takes in the arguments we need for that fragment, and this method would construct the fragment using the empty constructor and pass in the data using a bundle.
There are many useful cases, for example what Kiskae described. Another good one would be to be able to "give your constructors names":
class Foo<S: Any, T: Any> private constructor(private val a: S, private val b: T) {
//more code here...
companion object {
fun <S: Any> createForPurposeX(a: S) = Foo(a = a, b = "Default value")
fun createForPurposeY() = Foo(a = 1, b = 2)
}
}
Call site:
Foo.createForPurposeX("Hey")
Foo.createForPurposeY()
Note: You should use generic types instead of Any.
Code
import kotlin.reflect.full.*
class FooBar(val bar: String)
fun FooBar.baz(): Unit {println(this.bar)}
fun main(args: Array<String>) {
FooBar::class.declaredMemberExtensionFunctions.forEach {
println(it)
}
FooBar::class.memberExtensionFunctions.forEach {
println(it)
}
}
Output is empty
This is because declaredMemberExtensionFunctions only returns extension functions that are declared inside a class (as seen in the docs) and FooBar.baz() is a top level declaration (So it is not declared inside FooBar.
class FooBar(val bar: String) {
fun FooBar.baz(): Unit {
println(this.bar)
}
}
While I imagine this is not what you want, structuring the extension function like this would make your main method output lines.
TLDR: You aren't going to be able to do this. Because extension functions can be declared everywhere, you are limited in what the reflection system can do for you.
There is a thread on kotlinlang.org that covers this exact question and why it is not possible.
Essentially, Kotlin's declaredMemberExtensionFunctions function is able to list extension functions which are declared as part of the class, not externally. The docs state:
Returns extension functions declared in this class.
And of course, memberExtensionFunctions behaves similarly:
Returns extension functions declared in this class and all of its superclasses.
Here's what #Yole says in that thread as to why this is not possible:
The task of finding all extension functions for Foo is equivalent to finding all methods which have Foo as the first parameter. Neither of these is possible without accessing every single class in your application through reflection.
#Yole is on here, he might be able to provide a more authoritative answer for you.
If I create a Kotlin file MyTest.kt
package my.test
fun sayHello(): String = "Hello"
A class MyTestKt will be generated and it can be accessed from java like this:
MyTestKt.sayHello() // Returns "Hello"
MyTestKt myTestKt = new MyTestKt() // Instantiate
I would like to make that constructor private. Is that possible? If so, how?
I know I can use an object to create a singleton, that is not my question. I know I can create a class with a companion object inside, that is also not my question.
You can do something like this
#file:JvmName("Utils")
package demo
fun foo() {}
class Utils private constructor()
When you try to call Utils constructor from Java you get a "Utils has private access"
UPDATE
When using a private constructor() you are not able to access foo function.
I think this could be a design flaw, having a function not associated to any class-object. I have look into several kotlin standard library and I only found extension-functions as you want. In that case, for example, CollectionKt, it cannot be instantiated.