or other words, this of the lambda is Transaction ...
# coroutines
u
or other words, this of the lambda is Transaction instance and all consumer methods should be a extension on Transcation is it possible to enforce this without a compiler plugin?
g
You cannot limit all methods, but you can limit which suspend functions can be called from suspend block, this how sequence generators are implemented
Also I'm not really sure that limit all methods in general good idea, it would be barely usable
u
Hmm, I meant its not using coroutines at all. I just liked to type safety of suspend funs only called within a coroutinr block.. and if there is a way to mimic this pattern in other custom non-coroutine code
g
I understand I just said that something similar can be achieved with restricted suspension functions
u
whats that? restricted?
g
But semantics of coroutines is not want you want, you want to allow only particular functions, this hot how coroutines work, you can call any non-suspend function from suspend block, so it's not what you described above
If the only what you want to do it allow particular functions to be called only from particular block, it's easy to achieve using standard lambda with receiver
Like: interface TransactionScope { fun startTransaction() fun completeTransaction() } fun transaction (block: TransactionScope.() -> Unit)
So now you can call those transaction related functions only from this block: transaction { startTransaction () doSomething() }
u
hmm yes but doesnt force me to have my method as an extension on TScope, people can forget and just use blocking but you can also do this with coroutines thanks ill dig a bit deeper what is it I want exactly
g
people can forget and just use blocking but you can also do this with coroutines
But you cannot prevent it, I just cannot imagine solution for this you want to prevent calling any other methods? it’s not how suspend functions work, they do not prevent calling any other functions, coroutines just require context, it’s the same as TScope, but it implicit (same for @Compose functions), so you cannot call suspend function out of this context, but do not prevent calling any other functions Compose is good example, to call suspend composable functions, you need both and suspend modifier and @Compose annotation to work, they do not restrict anything Of course it can be some language feature/plugin, which prevents calling any other functions, but it would be incredible unusable:
Copy code
transaction {
  startTransaction ()
  log("starting") // error! Not a transaction function
  val result = doSomething(
      getSomeData() // error!
          .trim() // error!
   )
  result.forEach { // error! 
     val item = it
       .toString() // error!
       .trim() // error!
     doSomethingNonTransactional(item) // error
  }
}
And to cover all those cases you essentially need whole new language just to make it work, which doesn’t really make sense for me, and after all this cannot prevent all cases of “blockling functions”, forEach is blocking function, depends on amount of data