Description
The use case
Consider the code here: https://github.com/AndreiKingsley/kmath-tensors-example-jupyters/blob/master/kmath_tensors_examples.ipynb. KMath extensively uses context-oriented programming so each section on the code should be encapsulated with the appropriate receiver. Usually, we just do something like fun main() = DoubleTensorAlgebra{...}
to avoid additional clutter. In jupyter one have to wrap each cell in it which looks ugly.
Additional use cases:
- Implicit
CoroutineScope
for the notebook to allow convenient coroutines without explicit top-level scopes (and to avoid GlobalScope). - Use aspects like logging (just add logger object as an implicit receiver).
- Prototype multiple receiver API without actually having this feature in the language.
Proposed syntax
/**
* Add an implicit receiver to all subsequent cells. The `typeOf<T>` is used as a key for the stored receiver
*/
public inline fun <reified T: Any> Notebook.withReceiver(obj: T)
/**
* Remove receiver with the appropriate key from subsequent cells
*/
public inline fun <reified T: Any> Notebook.removeReceiver()
Functions are used on Notebook
to improve discoverability and avoid accidentally calling them.
Risks
Broad usage of implicit (including implicit receivers) could cause a lot of confusion in a large code, so this feature should not be used in large notebooks. The receiver should be declared in the notebook explicitly so it probably should not be used in plugins.
Adding multiple receivers which export the same functions and properties could produce unexpected behavior since the resolution could depend on the order. So there should be cell magic to list currently loaded receivers.