Variable shadowing and the proper use of .apply


#1

Android has a Paint class that you use for all sorts of drawing things. Java uses setter methods to fill in all the details, but Kotlin turns them into properties, making it attractive to do within apply. Below are three variants on how you might do this.

The old-school Java way of doing it:

fun makePaint0(color: Int, textSize: Float, strokeWidth: Float, isAntiAlias: Boolean): Paint {
    val result = Paint()
    result.color = color
    result.isAntiAlias = isAntiAlias
    result.textSize = textSize
    result.strokeWidth = strokeWidth

    return result
}

Leveraging the .apply method, but needing to change the formal parameters to avoid shadowing:

fun makePaint1(_color: Int, _textSize: Float, _strokeWidth: Float, _isAntiAlias: Boolean) =
        Paint().apply {
            color = _color
            isAntiAlias = _isAntiAlias
            textSize = _textSize
            strokeWidth = _strokeWidth
        }

Keeping the formal parameters the same, but now needing prefixes:

fun makePaint2(color: Int, textSize: Float, strokeWidth: Float, isAntiAlias: Boolean) =
        Paint().apply {
            this.color = color
            this.isAntiAlias = isAntiAlias
            this.textSize = textSize
            this.strokeWidth = strokeWidth
        }

I like the conciseness of makePaint1 in this example, but I hate having to tweak the names of the formal parameters to the function to avoid the shadowing. makePaint2 works, but it’s curious because the formal parameter of the function shadow the properties of the Paint object. I guess this makes sense, but it’s not really intuitive.

For fun, I tried using the IntelliJ refactoring tool to rename one of those underscored parameters in makePaint1 to remove the underscore in _color. This had the curious result of leaving the underscore in the formal parameter _color, while changing the code body to say color = color. Clearly, that’s a bug in the refactoring tool, but it’s also suggestive that shadowing is a subtle issue. If you refactor _color to be color, then you have to refactor the reference to the color field inside the apply body to be this.color, or you need to suggest some other alternative.

So my question, I guess, is what the “proper” way to write these sorts of functions should be. Any thoughts?