I just came across a data class as follows.
class A{
}
sealed class B
data class C(val isNext: Boolean = false, val builder: () -> A): A
class D: A{
}
To create an instance of the class, the developer used the following declaration.
C{D()}
My understanding of lambda, () -> A is that its a function without name that takes no arguments and creates an instance of A, however given that A's constructor is called, can I presume that its a function?
A constructor is a type of function, but you aren't passing it as a function here, because you have wrapped it by calling it in a lambda function. So you have passed a function that internally calls the constructor.
You can pass the constructor directly as a function, like this:
val c = C(::D)
I tidied up your setup:
open class A
class C(val isNext: Boolean = false, val builder: () -> A) : A()
class D : A()
With that in place the following are all equivalent:
val bldr: () -> A = { D() }
C { D() }
// is the same as:
C(isNext = false, builder = { D() })
// is the same as:
C(isNext = false, builder = bldr)
So the lambda is just an instance variable named builder of C just like isNext is. If it gets invoked in will create a new D that happens to be a subclass of A
Related
I can define invoke inside a class
class A {
fun invoke(x: Double): Double {
...
}
}
and then use class instance as a functiion
val a: A()
val b = a(2.3)
right?
But can I define class instance to simulate function with receiver?
val o: MyClass()
val a: A()
val b = o.a(2.3)
Is it possible?
and then use class instance as a functiion
The invoke operator is just a way to define what happens when using the syntax () on some instance. Just like you can overload what + means, you can overload what () means. It's not exactly making an instance of A "usable as a function", but rather defining the operator () on instances of A. This is why I think it cannot really translate to "making it usable as a function with receiver".
The obvious easy way to declare an extension function would be the following:
fun MyClass.a(input: Double): Double = TODO(...)
But this doesn't seem to suit your needs. If what you really want is to add such functions as "capabilities" to some instances dynamically "on the spot" as in your example, I guess you could do so by defining such extension in a class that you provide as scope:
class A {
fun MyClass.a(x: Double): Double {
...
}
}
fun main() {
val o = MyClass()
val b = with(A()) { // brings this instance of A in scope to add the extension
o.a(2.3)
}
}
What is the difference?
val isFinished: Boolean
get() = actor.actions.size == 0
fun isFinished() = actor.actions.size == 0
I have no idea.
I expect them to be the same.
The first statement defines a property and the second statement defines a method.
Assume you define both in a class Foo.
val foo = Foo()
if(foo.isFinished) {} // property
if(foo.isFinished()) {} // method - see () at invocation
Under the hood, both variants call a function.
Class Property
Your first example is a class property:
class MyClass {
val isFinished: Boolean
get() = actor.actions.size == 0
}
This property defines an (optional) explicit get method, often referred to as a "getter". You could also omit the getter and do:
class MyClass {
val isFinished: Boolean = (actor.actions.size == 0) //parens not necessary
}
If omitted, as shown in the last example, the value will rather be a constant value which isn't re-calculated on each access. Both variants serve different use cases but in most cases, the latter will be sufficient.
Regardless, for a client of this class, the property can be accessed like this:
val mc = MyClass()
mc.isFinished
This shows accessing a property in Kotlin.
Class member function
Functions in Kotlin can also define functions, which can be referred to as member functions. Your second example demonstrates this feature:
class MyClass {
fun isFinished() = actor.actions.size == 0
}
Defining a member function is similar to properties with explicit getters but still different for a client, since they have to invoke a function rather than accessing a property:
val mc = MyClass()
mc.isFinished()
Side Note
Note that the shown function utilizes an expression body which is equivalent to the following block body approach:
class MyClass {
fun isFinished() {
return actor.actions.size == 0
}
}
Learn more about functions here.
The following code is posted on Kotlin's website:
class A { // implicit label #A
inner class B { // implicit label #B
fun Int.foo() { // implicit label #foo
val a = this#A // A's this
val b = this#B // B's this
val c = this // foo()'s receiver, an Int
val c1 = this#foo // foo()'s receiver, an Int
val funLit = lambda# fun String.() {
val d = this // funLit's receiver
}
val funLit2 = { s: String ->
// foo()'s receiver, since enclosing lambda expression
// doesn't have any receiver
val d1 = this
}
}
}
}
It isn't clear to me how you call a function in an inner class. For example, how do you call Int.foo()
var a = A()
a.Int.foo() // This is not allowed.
Lets look at a more simple example:
class A {
inner class B {
fun foo() {
// ...
}
}
}
To call a function within an inner class, you must access it using an instance of the outer class, like so:
A().B().foo()
What makes your example more difficult is that Int.foo() is an extension function, so to access it you must call foo() on an Int within the same scope as the extension function:
class A { // outer class A
inner class B { // inner class B
fun Int.foo() { // entension function foo
print("Foo called on integer $this")
}
fun caller(i: Int) { // calls extension function
i.foo()
}
}
}
fun main() {
A().B().caller(10) // calls extension function in inner class B
}
Here we have added a function caller which is in the same scope as the extension function. The code outputs the following:
Foo called on integer 10
In this case, foo is an extension function defined in B. You cannot call these member extension functions from outside by default. However, it's possible to execute the function when you get into the scope of B, which can be achieved with scoping functions such as with. Please be aware that this extension function can only be called on instances of Int.
val a = A()
val b = a.B()
with(b) {
5.foo()
}
I'm trying to assign a callback implementation of an interface (defined inside a class A) to a variabile defined inside another class B. Let's say that class A has the interface OnSomethingHappens which defines a doSomething method.
Inside class B I've defined my callback variable like this:
private lateinit var callback:A.OnSomethingHappens
I need to create an instance of class A passing callback variabile to the constructor in this way:
myinstanceA = A(callback)
I'm trying to assign an instance of an anonymous class that implements A.OnSomethingHappens using this code:
callback = object : A.OnSomethingHappens {
override fun doSomething(..){
//here I put the implementation of this method
}
}
but the compiler says "expecting member declaration" for my callback variable and "name expected" for object.
What I'm doing wrong?
Instead, I'm able to define and at the same time assign the callback variable in this way:
private var callback = object : A.OnSomethingHappens {
override fun doSomething(..){
//here I put the implementation of this method
}
}
Why? Which are the differences and a possible solution?
I'm trying to assign an instance of an anonymous class that implements A.OnSomethingHappens using this code: ...
This should work, but only inside a method:
class B {
private lateinit var callback:A.OnSomethingHappens
fun someMethod() {
callback = object : A.OnSomethingHappens { ... }
}
...
}
Given the error message and that private var compiles (which doesn't inside a method), you are trying to set it directly in the body of the class instead:
class B {
private lateinit var callback:A.OnSomethingHappens
callback = object : A.OnSomethingHappens { ... }
...
}
This is illegal: the only code you can write there is member definitions and init blocks.
Also, if you can initialize callback directly where it's defined or inside init, there's no point to lateinit in the first place.
It's not obvious from the code snippets cut down to such small pieces, but your issue is that you're writing down the assignment inside the body of a class, but not inside a function.
Here's an example of a valid declaration and immediate assignment:
class A {
var x: X? = X()
}
Here's an example of an invalid assignment, which places an arbitrary expression in the body of a class:
class A {
lateinit var x: X
x = X() // expression placed inside the class body, invalid syntax
someFunction() // extra example, calling functions here is invalid in the same way
}
Instead, you could put this initialization inside a function:
class A {
lateinit var x: X
fun initializeX() {
x = X()
}
}
Or inside an initializer block (in this case, you don't even need lateinit):
class A {
var x: X
init {
x = X()
}
}
While I couldn't explain how to solve your exact problem, because I can't quite understand what code is in which class, I hope these examples and explanation helped.
Hmm, let me propose a variant. It's more simple for me:
import android.util.Log
class SomeClass {
fun mainMethod() {
ClassWithCallback(
{ myBackValue: String ->
logMyString(myBackValue)
}
)
//simplify
ClassWithCallback({ logMyString(it) })
}
private fun logMyString(myBackValue: String) {
Log.d("SomeClass", myBackValue)
}
}
class ClassWithCallback(private val myCallBack: (myBackValue: String) -> Unit) {
init {
// we do something here and back it by callback
val myString = "Hello! Pass me back!"
myCallBack.invoke(myString.toUpperCase())
}
}
Using Kotlin lambdas. Hope this will help you.
In C# you can place a new constraint on a generic to create a new instance of the generic parameter type, is there an equivalent in Kotlin?
Right now my work around is this:
fun <T> someMethod(class : () -> T) {
val newInstance = class()
}
and I'm calling someMethod() like this
someMethod<MyClass>(::MyClass)
but I would like to do something like this:
fun <T : new> someMethod() {
val newInstance = T()
}
Is that possible?
Currently, that's not possible. You can give a thumbs-up for the issue https://youtrack.jetbrains.com/issue/KT-6728 to vote for the addition of this feature.
At least, you can leave out the generic type because Kotlin can infer it:
someMethod(::MyClass)
A solution:
1/ use an inline function with preserved param type (reified type)
2/ in this inline function, invoque the needed constructor using class introspection (reflexion *)
/!\ an inline function can't be nested/embedded in a class or function
Let see how it works on a simple example:
// Here's 2 classes that take one init with one parameter named "param" of type String
//!\ to not put in a class or function
class A(val param: String) {}
class B(val param: String) {}
// Here's the inline function.
// It returns an optional because it could be passed some types that do not own
// a constructor with a param named param of type String
inline fun <reified T> createAnInstance(value: String) : T? {
val paramType = String::class.createType() //<< get createAnInstance param 'value' type
val constructor = T::class.constructors.filter {
it.parameters.size == 1 && it.parameters.filter { //< filter constructors with 1 param
it.name == "param" && it.type == paramType //< filter constructors whose name is "param" && type is 'value' type
}.size != 0
}.firstOrNull() //< get first item or returned list or null
return constructor?.call(value) // instantiate the class with value
}
// Execute. Note that to path the type to the function val/var must be type specified.
val a: A? = createAnInstance("Wow! A new instance of A")
val b: B? = createAnInstance("Wow! A new instance of B")
*) kotlin-reflect.jar must be included in the project
In Android Studio: add to build.gradle(Module: app): implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"