Home > Mobile >  How can I write the same code without .run{...} and .wth{...} in Kotlin?
How can I write the same code without .run{...} and .wth{...} in Kotlin?

Time:06-06

The Code B is a class, but I can't understand the Code B fully.

I can use the class NewCoordinate in Code A.

Can you write a the same function as Code A without using .run{..} or .wth{..} ?

Code A

fun doTo(){
    val mCoordinate = NewCoordinate(2.0f, 3.0f)
    mCoordinate.run { 
        var mPoint =3.0f.toX
    }
    
    with(mCoordinate){
        var mPoint =3.0f.toX
    }
}

Code B

class NewCoordinate(private val xOrigin: Float, private val yOrigin: Float) {  
    val Float.toX: Float get() = xOrigin   this                  
    val Float.toY: Float get() = yOrigin - this                   
}

Added Content

To cactustictacs: Thanks!

In Code C, I have added a extension function .ext for the class NewCoordinate, it wrapped with .run {...}.

But I still get the wrong, why?

Code C

fun doTo() {
    val mCoordinate = NewCoordinate(2.0f, 3.0f)
    mCoordinate.ext {
        var mPoint =3.0f.toX  //It's wrong
    }
}

fun NewCoordinate.ext(block: ()->Unit){
    this.run {
        block()
    }
}


class NewCoordinate(private val xOrigin: Float, private val yOrigin: Float) {  
    val Float.toX: Float get() = xOrigin   this                  
    val Float.toY: Float get() = yOrigin - this                   
}

Added Content Again

The Code D is answer based by cactustictacs's thinking. It's great, thanks again.

Code D

fun drawDial(drawScope: DrawScope){   
    val mCoordinate = NewCoordinate(drawScope.size.width / 2.0f, drawScope.size.height / 2.0f)

    mCoordinate.draw(drawScope){
        it.drawCircle(Offset(x = 0.0f.toX, y = 0f.toY), Radius, paintDial)
    }
}

fun NewCoordinate.draw(drawScope: DrawScope, block: NewCoordinate.(canvas: Canvas) -> Unit ){
    drawScope.drawIntoCanvas{
        block(it)
    }
}


class NewCoordinate(private val xOrigin: Float, private val yOrigin: Float) {  
    val Float.toX: Float get() = xOrigin   this                  
    val Float.toY: Float get() = yOrigin - this                   
}

CodePudding user response:

This:

val Float.toX: Float get() = xOrigin   this

is an extension property. It allows you to "add" a property to a class (in this case the Float class) without needing to modify the source of that class. So when that extension property is in scope (where the code you're running can "see" it) you can call toX on any Float, and it'll run that code.

If an extension is declared at the top level of the current file, anything in that file can access it - it's in scope. If it's at the top level of another file, and visibility modifiers allow it, you can import it - now it's in scope.

But if it's declared inside a class, only code inside that class (or its subclasses) can see it - it's not accessible from the outside. (If you look at the link up there, and scroll down to the Declaring extensions as members section, you can see an example where they explicitly demonstrate this)


So that's a problem - but what receiver-style scope functions like run, apply and with do is allow you to run code "inside" the object you're calling them on. It's as if your code is part of the object's class - and that means those Float extension properties are now in scope, and you can use them!

This doesn't allow you to get around visibility modifiers - if you make those properties private in NewCoordinate, you won't be able to access them. If you like, run is a bit like an extension function on NewCoordinate - you can "add" functionality that behaves as though it's part of the class's code, which makes use of stuff that's publicly accessible on the class.

It's shifting your point of reference, so you can access things more easily - but nothing that you couldn't access before! It's just that in this case, the language didn't allow you to reference Float.toX from outside the scope - the property is still public, but right now there's no way to say mCoordinate::toX or mCoordinate::Float::toX or anything like that. You have to put yourself in scope so you can call it the usual way!

  • Related