Feature proposal: lambda flattening syntax to enable RAII and more elegant code

Thanks for the reply, these are really great points.


For #1, I would say it’s definitely a question of tradeoffs. You can absolutely do this in a context-oriented way, however it comes at the following costs:

  1. Having to implement said functions, or ship them with the standard library, when existing functions can be repurposed for this at “no cost,” because they have the same semantic meaning.
  2. One extra layer of indentation (at the risk of sounding pedantic.)
  3. Cost of bookkeeping – taking your method as an example, we would have to allocate a List behind the scenes so that we could traverse the resources at the end and destroy them. While in many situations this is perfectly acceptable, it’s often not for “performance critical” code, i.e. mobile, game, embedded, finance, or scientific computing, where we’d really like to avoid invoking the GC or polluting the cache to the greatest extent possible. (This goes doubly so for multi-threaded code.) Considering that Kotlin already goes to great lengths to conserve performance by not boxing primitives on the JVM (for example), I believe this is a valid concern for the language.

For #2, I’m more interested in alleviating the clutter of many lambdas in one place than I am in supporting full stack-based semantics. (You can actually emulate a lot of this as-is by using ThreadLocals of objects with inline methods, with acceptable performance for real-time use cases. The problem is its a lot of implementation complexity with room for error, and not quite as fast as a true “stack,” especially because nothing is getting saved to registers.)

Nested lambdas are inherently a “stack-like” pattern, however, and while the new context features can reduce this by offering an alternate implementation, they’re not going to remove lambdas from the language. So why not make lambdas more elegant, capitalizing on what we already have? (Also, I wouldn’t expect the standard library to offer a reimplementation of every relevant lambda function in order to accommodate a context-based usage pattern.)

In terms of aligning with the new context features, that was actually the initial motivation for this post - some users were debating a new with val MyContext() feature to inject contexts into the current scope, and I thought this proposal would cover that (e.g. &with(MyContext())) while improving the language more generally, satisfying some other use cases I’ve been running into. I suppose introducing contexts alongside an acquired resource could also be useful:

val resource = &acquireResource() // also introduces a context
resource.doAThing() // context extension method (maybe we don't own resource's class)

I think it would be worthwhile to consider every standard library function this could be used with – once I have some time I’ll try and do that.

1 Like