An introduction to context-oriented programming in Kotlin

Usually, functional-oriented languages have better scoping rules (pedant’s comment: again, not all procedural languages are C, so there are some with good scoping), which allow to perform more fine-grained visibility control for functions based on module system, but overwise, the dispatch is performed based on compile-time types of arguments.What is this?In case of object programming, when we call an object method, we have all of its parameters, but additionally we have an explicit (in case of Python) or implicit parameter representing the instance of calling class (here and later all examples are written in Kotlin):class A{ fun doSomething(){ println("This method is called on $this") }}Nested classes and closures complicate things a bit:interface B{ fun doBSomething()}class A{ fun doASomething(){ val b = object: B{ override fun doBSomething(){ println("This method is called on $this inside ${this@A}") } } b.doBSomething() }}In this case there are two implicit this parameters for function doBSomething..One comes form the instance of class B and another one comes form enclosing A instance..The same works for much more common case of lambda closure..The important note about this is that it works not only as an implicit parameter, but also as a scope or context for all functions and objects called in a lexical scope where it is defined..Meaning that method doBSomething in fact has access to any public or private members of A as well as members of B itself.Here comes KotlinKotlin brings a completely new toy to the playground: extension functions (pedant’s comment: not really new, C# has extension functions)..In Kotlin one can define an extension function like A.doASomething() which could be defined anywhere in the program, not just inside of A..Inside this function one has implicit this parameter called receiver and pointing to the instance of A on which the method is called:class Afun A.doASomthing(){ println("This extension method is called on $this")}fun main(){ val a = A() a.doASomthing()}Extension function do not have access to private members of its receiver, so it does not violate encapsulation.The next important thing Kotlin brings to the table are the scoped code blocks..One can run an arbitrary code block using something as a receiver:class A{ fun doInternalSomething(){}}fun A.doASomthing(){}fun main(){ val a = A() with(a){ doInternalSomething() doASomthing() }}In this example both functions could be called without additional the beginning, because withfunction moves all code in the following block inside a context..Which means that all function in this block are called as if they are called on provided a object.The final (at this moment) step to context-oriented programming is called member extension..In this case an extension function is defined inside another class, like this:class Bclass A{ fun B.doBSomething(){}}fun main(){ val a = A() val b = B() with(a){ b.doBSomething() // this will work } b.doBSomething() // won't compile}The important thing is that B acquires some new behaviors, but only when called in specific parametric lexical context..The member extension function is regular member of the class A.. More details

Leave a Reply