Declare member extensions outside the class


#1

Extensions are the brilliant invention of the Kotlin team and I use them a lot. Member extensions are very useful do declare convenience methods and us create DSL and other utility constructs in case one needs to limit some behavior only when a specific class used as a receiver.

Lately I’ve encountered a multiple cases, when I want to declare a member extension to already existing classes. For example, I have some kind of mathematical context and want to declare arithmetic operations on numbers like:

class ContextClass{
  operator fun Number.plus(n: Number): Number{
    ...
  }
}

Another example is when I need to generate a synthetic property for an object but only when it is used as argument of some method in another class.

It could be done easily in kotlin if we are talking about user-defined classes written in kotlin. But It seems to be impossible for java classes or for library classes. From my naive point of view it should be possible to add those member extensions from outside of context class, but Kotlin currently lacks syntax for that.

So my question is: is it done by design and is it possible to add such syntax?


#2

As an extension-function with multiple receivers:

a post from 2014

and from 2017:

So, it wasn’t by design, but I’m not hopefull…

But, maybe it will be possible as inline class?


#3

Thanks, missed that post because of different wording.

So the problem is purely syntactic A agree, that fun A.B.method() looks a bit confusing (not drastically though), but maybe there could be another solution. Something with with maybe?


#4

Want you define your algebra?

object ContextClass{
  operator fun Number.plus(n: Number): Number{
    ...
  }
}

with (ClassContext) {
    val sum = number1 + number2
}

I wrote a long post about this (and more) here

Here how to defien a Ring using the typeclass, but this can be easy translated to Kotlin 1.2

I hope this may help you.


#5

Type classes (while being very interesting idea) are a bit of overkill for the thing I am asking about, since member extension are already in the language, and it should be easy to declare them outside of class scope.The only thing which is not there is a syntax to declare receiver hierarchy.

As for implementation, I’ve already implemented it here and here with resulting code example here. It works just fine in kotlin, and I probably would not be able to implement it using member extensions anyway, since I had to add additional field to context class anyway. The only problem arises in case one wants to use existing Java class as a context.

I promised commons-math guys to back port kotlin solution to java, so in the end I will have to use java classes if I do not want to keep two implementations of the same thing.


#6

Maybe you could try something like this:

object ContextClass
object Number

val ContextClass.plus: Number.(Number) -> Number get() = { TODO() }
val result = ContextClass.run {
  Number.plus(Number)
}

But it seems that the operator keyword won’t work though.


#7

An interesting idea (not for my case, but for global multi-receiver problem). But still, it looks like a workaround, not a good solution.

Creating a wrapper class, which delegates methods to internal implementation looks better.


#8

Your solution looks good,
What is your issue about it?


#9

No problem here, it works. It is just that I recently noticed a few places, where I would like to add member extensions to Java classes. Overall, this request in just a syntactic sugar, but the idea looks so good…