Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In this article I will try to describe a new interesting phenomenon which appeared as a by-product of fascinating progress made by Kotlin development team. Namely, the new approach to library and application architecture design, which I call context-oriented programming.

A few words about

...

function resolution

It is well known, that there are three main programming paradigms (pedant's comment: there are other paradigms as well):

  • Procedural programming
  • Object-oriented programming
  • Functional programming

All those approaches work with functions with one or another way. Let’s look on them from the point of function resolution or dispatch (meaning which function will be used in which case). Procedural programming tends to use global functions and dispatch resolve them statically based on the name and argument type. Of course types have meaning only in case of strongly statically typed languages. In python, for example one calls function by name and if the parameters are wrong, an exception will be thrown in runtime. The dispatch function resolution in procedural language is based on procedure/function name and its parameters only and in most cases static.

One of primary features of object-oriented programming is that the functions are no longer Object-oriented programming style  tends to limit function visibility. Functions are not global, but instead are members of objects which means that they could be called only on the instance of a specific object (pedant's comment: some classic procedural languages have module system and therefore visibility scopes, procedural language != C). Of course one can always replace a object member function with global function with additional argument with the type of the calling object, but from syntactic point of view the difference is rather large. For example, now methods are grouped by the object they are called upon and so one could clearly see what methods or behaviors are supported by this type of object. Of course, the most important part is the encapsulation which means that some of object fields or behaviors could be private and accessible only from this object members (you can’t do it in purely procedural approach) and polymorphism, which means that actually used method is decided not based upon the method name, but also on runtime type of the object it is called upon. Object-oriented dispatch is based on caller runtime type, method name and compile-time types of arguments.

Functional programming does not bring anything principally new in terms of dispatchfunction resolution. Usually, functional-oriented languages have better scoping rules, 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.

...

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 passed as a parameter (here and later all examples are written in Kotlin):

...

Current development in context-driven way is limited by the fact that one needs to define member extension in order to get some context-scoped behavior of class. It is OK, when it is a user-defined class, but what if we need to define some context-scoped behavior for a library class? Or if we want to create extension for already scoped behavior (for example add some extension inside CoroutineScope)? Currently Kotlin does not allow more then one receiver on an extension function. But multiple receivers could be added to language in a non-breaking backward-compatible way. The multiple receivers feature is currently being discussed (KT-10468) and will lead to a KEEP request in nearest future. The problem (or maybe the feature) of nested contexts is that it allows to cover most if not all use-cases of type-classes, another sought-after possible feature. It is quite unprobable that both features will be implemented in the language at the same time.

Addendum

I would like to thank our friendly neighborhood Haskell-loving pedant Alexey Khudyakov for his remarks on the text and correction of my rather unconstrained usage of terms.