https://kotlinlang.org logo
Title
e

Erik Colban

04/04/2019, 6:03 PM
I've just joined the Slack channel. Hello to you all. I've been working for a couples of days trying to implement something similar to Python decorators in Kotlin. I've created a Github repository [here](https://github.com/ecolban/FunctionDecorators). The README file provides details of what I've achieved so far, and what I'd like to achieve. I'm open to suggestions.
b

bbaldino

04/04/2019, 6:11 PM
i've wanted something like this so much in java/kotlin. will take a look!
what sort of syntax are you thinking for applying them? like what would a method you wanted to add
TimeIt
to look like?
e

Erik Colban

04/04/2019, 6:32 PM
I've used extension functions. I've been playing around with top level functions and classes, but I think that extension functions work best. E.g.,
::myFun.timeIt()(arg1, arg2, ...)
b

bbaldino

04/04/2019, 6:34 PM
that would mean that a caller must know/change to call it this way, right? unless you hide the real function in the class (as
_myFun
or something) and then have
myFun
invoke
_myFun
via the extension?
e

Erik Colban

04/04/2019, 7:04 PM
For an extension such as
timeIt
, the function provider would just provide the function any form she prefers, as a fun or a lambda. The caller would add the decorator as an extension function. For decorators such as memoize, the function provider would have to write the function to be decorated in a special form, which is what I don't like with my approach. This is discussed in detail in the README.
m

Mike

04/04/2019, 11:13 PM
What's the advantage of this over casting the function timeit and having it take a lambda? For this specific case, kotlin has a function like this. https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.system/measure-time-millis.html But I'm not familiar with python decorators so guessing based on quick read on timeit.
b

bbaldino

04/04/2019, 11:35 PM
the thing i think is nicest about them is how easy and unobtrusive they are to add. both the caller and even the method itself can stay just as they are...it's just a transparent wrapper
e

Erik Colban

04/05/2019, 6:49 PM
measureTimeMillis
is different from
timeIt
1.
timeIt
prints the time,
measureTimeMillis
doesn't print anything 2.
measureTimeMillis
is a function that takes a code block as argument, whereas
timeIt
is a decorator, i.e. it takes an object or class of some type
T
and augments or modifies the behavior in some way and returns an object or class of the same type
T
.
Both
measureTimeMillis
and
timeIt
have their usages, and comparing them is not the issue of this post.
timeIt
is just an example of a function decorator. Decorators are well-known and even have their own pattern; the decorator pattern. Kotlin's
by delegate
makes this pattern even easier to adopt. The point I wanted to address is how do you write a decorator on a recursive function in Kotlin that is applied recursively.
b

bbaldino

04/05/2019, 6:58 PM
can you use a delegate on a function though?
e

Erik Colban

04/05/2019, 7:00 PM
You could, but since there is only one method to override (i.e.,
invoke()
) there is no value in doing so.
b

bbaldino

04/05/2019, 7:01 PM
but what is the syntax, it's not
by
like properties, right? are you talking about doing something like
class Foo {
    fun something() = delegate {
    }
}
?
e

Erik Colban

04/05/2019, 7:05 PM
class TimeIt<X, Y>(delegate: (X)->Y): (X)->Y by delegate {
    override fun invoke(x: X): Y {
        val start = System.currentTimeMillis()
        val result = delegate.invoke(x)
        println( System.currentTimeMillis() - start)
        return result
    }
}
b

bbaldino

04/05/2019, 7:06 PM
oh, i thought you mean a way to 'delegate' a method to a decorator (which would invoke the method)
e

Erik Colban

04/05/2019, 7:11 PM
The above code snippet is the standard way of specifying a decorator. You would use it:
TimeIt(::myFun)(x)
or, if you were to use a lambda,
TimeIt({....})(x)
Using an extension function is an alternative, and it's a matter of taste which to prefer.
b

bbaldino

04/05/2019, 7:56 PM
i see. i'd love to be able to do it in a way like python: at the method's definition itself and without neither the method nor the caller having to be aware of it at all. i guess this would be doable at the method definition site (wrapping it in some way) but not as neat as python