`run` named function

#1

Currently, Kotlin supports running anonymous functions as “code blocks”:

run {
  // do something
}

In this post, I’ve presented the case for support of running named inner functions:

var x: Int = 0
run myFunction(x) {
  println(x)
}

Please see the post for detailed justification.

#2

I don’t really see the advantage. How is run mySpecialName { ... } better than run { ... }. Ok you can name the block, but that’s nothing more than a comment with a special syntax, since the name is never used again.
The idea about renaming arguments is nice, but I don’t think it’s important enough to create an entire new language feature for it. After all it would be the same as

run {
    val someNewName = theOldName
    // doSomething
}

One thing I don’t understand from your post is this part of code

fun replace(): String {
  val symbolPattern = Pattern.compile("\\$([a-zA-Z]\\w*)")
  val symbolMatcher = symbolPattern.matcher(stringToReplace)
  while (symbolMatcher.find()) {
    val symbolName: String = symbolMatcher.group(1)
    run replaceAllInstances(symbolName) {
      if (getSymbol(symbolName) != null &&
          symbolName !in alreadyReplaced) {
        alreadyReplaced.add(symbolName)
        stringToReplace = stringToReplace.replace(
            "$" + symbolName, translate(symbolName))
      }
    }
  }
  return stringToReplace
}

Why does your new kind of run block need symbolName as a parameter:

run replaceAllInstances(symbolName) {...

Why not just

run replaceAllInstances {

symbolName is captured anyways (which has no cost due to inlining). Which leads back to my earlier question why we need a name for the block at all, simplifying it to

run { ...

Ok, I understand the idea that you want to have nice looking code like

fun replace(): String {
  val symbolPattern = Pattern.compile("\\$([a-zA-Z]\\w*)")
  val symbolMatcher = symbolPattern.matcher(stringToReplace)
  while (symbolMatcher.find()) {
    val symbolName: String = symbolMatcher.group(1)
    replaceAllInstances(symbolName)
  }
  return stringToReplace
}

private fun replaceAllInstances(symbolName: String) = TODO()

And I agree, that with code folding, the named version could be made to look like that, but this is also true if you use a comment.

I personally don’t like code folding much. IMO code is bad, if you need code folding to understand it.
Instead I would love to see improvements made to the way inner functions work. Maybe a way to explicitly state, that you don’t want to capture any value or the ability to declare your inner functions at the end of the main function (just throwing some ideas out there).

#3

All the reasons why the proponents of small functions advocate for them in the first place:

  • Ability to test in separation (you cannot test an anonymous lambda inside a function)
  • Name as a form of comment
  • Name appears on the stack trace
  • Can kotlindoc-link to the semi-function
  • Can quickly navigate to the semi-function within IDE

This is a self-imposed restriction to increase safety. You cannot capture and use the wrong variable from the scope by mistake. This also allows unit-testing semi-functions in separation from the containing functions.

There is essential complexity vs. accidental complexity. When something that you have to accomplish (the algorithm) is intrinsically complex enough, there is really no way to make simple and elegant code that solves the problem and doesn’t require any comments. The goal of semi-functions is to make it easier to work and understand such essentially complex code and increase its robustness (minimize the probability that you, as a programmer, make a mistake in that complex code) by reducing the visibility of local variables and limiting the internal complexity of functions. To some extent, this is similar to why there is no goto in modern programming languages.

#4

I was under the impression that you wanted the code inlined, but even if it’s not inlined it should at least be private, so how exactly are you planning on testing semi-functions in unit tests? You can only test public or internal functions.

Exactly my point, why is it better to have a special syntax for this kind of comment?

I guess it’s possible, but why you would want to link to implementation details from your documentation is not clear to me.

I agree totally. I just don’t think that adding a code block (you have to hide using code folding is the way to go). I would rather use a private or inner function to achieve the same. This is IMO more readable, since you don’t have a big code-block you have to skip (or hide) while providing the same advantages.
Also this is already part of the language. Ok I would love to be able to specify the inner function at the end of the main function, but this is a change to the language which is smaller, probably easier to implement in the compiler and wouldn’t need to introduce a new syntactic feature.
And it would not require tooling to be useable and I am not sure how many people use code folding, but I don’t and don’t want to.
Basically, my point is that I don’t see the advantage over other alternatives. If you really want the semi-function to be inline in the main function you can use run. It does not have entirely the same tooling support but it basically works the same, except for the testing maybe.
Otherwise you can use private or inline functions, giving you all the pros you listed above, but they already exist within the language. The only downside is that they can’t appear exactly where you call them, but I’d argue that this is good and not bad.

#5

Anonymous lambda blocks already can have custom labels in Kotlin. The proposed additional feature is not different enough to be worth the change.

1 Like
#6

I realized that semi-functions, as proposed, can be entirely a feature of IDE presentation (code editor) interface, while the source code still has ordinary extracted functions. I’ve described the idea here: IDEA-211820.