ernstJ
ernstJ

Reputation: 3

How to pass context Implicitly for constructors in Kotlin

I am trying to make the construction of instances of a class depending on the scope in which they are defined without using explicit parameters.

This is part of a port from Python to Kotlin but the main idea would be something like:

var d = MyClass()

use_scope(contextAForScope) {
    var a = MyClass()
    use_scope(contextBForScope) {
        var b=MyClass()
    }
}

In this example the d constructor would use a default context, a constructor would use contextAForScope and b constructor would use contextBForScope (use_scope is just a placeholder here). Something like implicit contexts?

Of course, I could make the constructor parameter explicit but this will potentially be used many times in a single scope and I would prefer not to define an additional variable.

Upvotes: 0

Views: 2725

Answers (2)

Rene
Rene

Reputation: 6148

class MyClass(val context: Int)

fun MyClass() = MyClass(0)

interface MyClassScope {
    fun MyClass(): MyClass
}

object ContextAForScope : MyClassScope {
    override fun MyClass() = MyClass(1)
}

object ContextBForScope : MyClassScope {
    override fun MyClass() = MyClass(2)
}

inline fun useScope(scope: MyClassScope, block: MyClassScope.() -> Unit) {
    scope.block()
}

fun main(args: Array<String>) {
    val d = MyClass()

    useScope(ContextAForScope) {
        val a = MyClass()
        useScope(ContextBForScope) {
            val b = MyClass()
        }
    }
}

Use a factory function to create your class. If you name the function like the class, it looks like a constructor.

Define an interface with the same factory function and two objects for the scopes.

Define a function that takes the scope and the initializer block.

Now you can use the useScope-Function and within the block the right factory function is invoked.

Upvotes: 1

Willi Mentzel
Willi Mentzel

Reputation: 29844

with is what you are looking for:

class MyClass()

var d = MyClass()

fun main(args: Array<String>){
  var c = "c: Could be any class"
  var d = "d: Could be any class"

  with(c) {
    // c is "this"
    var a = MyClass()
    print(c) // prints "c: Could be any class"

    with(d) {
        // d is "this"
        var b = MyClass()
    }
    // b is undefined in this scope
  }
  // a is undefined in this scope
}

with takes a lambda as argument an everything in that lambda is only defined in that scope.

Upvotes: 0

Related Questions