Kotlin like scope functions (let, also, apply, run) in Groovy - kotlin

I think the title speaks for itself - does Groovy have something like Kotlin scope functions?
obj.apply {
foo()
bar()
baz()
}
// is the same as
obj.foo()
obj.bar()
obj.baz()

Groovy has obj.with { } method that allows you to do the same:
obj.with {
foo()
bar()
baz()
}
There is also obj.tap { } variant (an equivalent of obj.with(true) { }) that does the same, but it returns the incoming object.
def newObj = obj.tap {
foo()
bar()
baz()
}
Source: http://docs.groovy-lang.org/docs/next/html/documentation/style-guide.html#_using_with_and_tap_for_repeated_operations_on_the_same_bean

Related

How to use functional types or lambdas as type for Kotlin's context receivers?

package yamin
typealias Foo = () -> Unit
fun main() {
bar {
baz()
}
}
fun bar(foo: Foo) {
foo()
}
context(Foo)
fun baz() {
//
}
I tried to use a lambda type for the context of a function, which seems to be fine at this point but when I tried to call that function in that context, or at least what I think is that context I'm failing, and Kotlin's compiler is showing me this error for baz():
No required context receiver found: Cxt { context((yamin.Foo /* = () -> kotlin.Unit */)) public fun baz(): kotlin.Unit defined in yamin in file Main.kt[SimpleFunctionDescriptorImpl#7b5e305f] }
Maybe I misunderstood Kotlin's context receivers or I'm expecting something that it's not designed for. I just want to create a function that can only be called in certain context and in this example only in a certain lambda.
As it is right now, your baz can be called like this:
val someFoo: Foo = {}
with(someFoo) {
baz()
}
By using with, I bring an instance of () -> Unit into the context, so someFoo becomes a context receiver with which I can call baz. In baz, I can then access this someFoo by using this#Foo. This is how context receivers are supposed to work.
If you want baz to only be able to be called in bar's lambda, bar's lambda needs to provide the context receiver using a receiver parameter, similar to how with's lambda is declared T.() -> R.
object Foo
fun main() {
bar {
baz()
}
}
fun bar(foo: Foo.() -> Unit) {
Foo.foo()
}
context(Foo)
fun baz() {
// ...
}
I changed the actual context here to just an object, because as far as I can see, there is nothing special about bar's lambda. Of course, if you want, you can make it provide extra information to baz by changing Foo to a class that does contain data.
Note that this does not prevent someone from doing:
with(Foo) {
baz()
}
It is quite hard to prevent against this without adding another layer outside of bar, like:
// note that bar is no longer a global function
import bar.Foo.Companion.bar
class Foo private constructor() {
companion object {
fun bar(foo: Foo.() -> Unit) {
Foo().foo()
}
}
}
context(Foo)
fun baz() {
// ...
}
You can also do something simple like this prevents it from happening from outside the package:
sealed interface FooInterface
private object Foo: FooInterface
fun bar(foo: FooInterface.() -> Unit) {
Foo.foo()
}
context(FooInterface)
fun baz() {
// ...
}
To make a function that can only be called in a certain scope, give the function itself a receiver. Instead of typealias Foo = () -> Unit, you would use something like typealias Foo = MyReceiver.() -> Unit.
You can do this with a regular extension receiver, but it's also possible with context receivers.
Here's a simple version that works for me:
typealias Foo = BarScope.() -> Unit
fun main() {
bar {
baz()
}
}
object BarScope
fun bar(foo: Foo) {
BarScope.foo()
}
context(BarScope)
fun baz() {
}

Kotlin: use generic on interface level as argument type for function

Is it impossible to use generic on interface level as argument type for function?
I read about out and in keywords but as I understand they don't work for this case.
interface BaseB
open class ChildB1: BaseB
open class ChildB2: BaseB
abstract class BaseMapper<V: BaseB> {
open fun test(v: V) {
return
}
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
return
}
}
class TestMapper2: BaseMapper<ChildB2>() {
override fun test(v: ChildB2) {
return
}
}
#Test
fun t() {
//ERROR
val mappers: List<BaseMapper<BaseB>> = listOf(TestMapper1(), TestMapper2())
mappers[0].test(ChildB1())
}
A BaseMapper<ChildB1> is not logically a BaseMapper<BaseB>. It consumes ChildB’s, so if you passed some other implementation of Base it would cause a ClassCastException if the compiler let you do that. There is no common subtype of your two subclasses besides Nothing, so the only way to put both of these types in the same list is to make it a List<BaseMapper<in Nothing>>.
Example of why it is not logically a BaseMapper<BaseB>:
open class ChildB1: BaseB {
fun sayHello() = println("Hello world")
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
v.sayHello() // if v is not a ChildB1, this would be impossible
}
}
//...
val impossibleCast: BaseMapper<BaseB> = TestMapper1()
// TestMapper1 cannot call sayHello() because it's undefined for ChildB2.
// This is impossible:
impossibleCast.test(ChildB2())
// ...so the compiler prevents you from doing the impossible cast in the first place.

MockK spy on top-level private function in Kotlin

I need to verify if bar function is called or not using MockK library.
MyFile.kt
fun foo() {
bar()
}
private fun bar() { ... }
How can I mock the 'bar' function?
I am trying the following.
#Test
fun test() {
mockkStatic("com.mypkg.MyFileKt")
every { bar() } returns Unit
foo()
verify(exactly = 1) { bar() }
}
This gives compile-time error: Cannot access 'bar': it is private in file.
It works fine if I make the bar function internal. Probably I will have to spy on it but cannot find an example to do that.
Although I don't think it's a good idea to mock private methods, since they should most likely be tested in conjunction with the method calling them, MockK does support this:
https://mockk.io/#private-functions-mocking--dynamic-calls
So your code would look something like this:
class TheClass {
fun foo() {
bar()
}
private fun bar() {}
}
#Test
fun theTest() {
val mock = spyk<TheClass>(recordPrivateCalls = true)
every { mock["bar"]() } returns Unit
mock.foo()
verify(exactly = 1) { mock["bar"]() }
}

Why does a member function invocation not infer a required receiver from the calling function?

Consider:
class Foo {
fun CoroutineScope.foo() {
}
}
class Bar {
val f = Foo()
fun CoroutineScope.bar() { // this could also be "suspend fun bar = coroutineScope {"
f.foo() // unresolved reference
with (f) {
foo() // OK
}
with (f) {
with(this) {
foo() // OK
}
}
}
}
It seems like the first attempt at f.foo() should infer the CoroutineScope receiver specified on bar(). It seems it doesn't; but in an attempt to understand receivers better, does anyone have an explanation as to why?
Edit
(Playground link)
After looking over some docs (specifically the "Declaring extensions as members") and Rene's response, I tried a few more things:
import kotlinx.coroutines.*
class Foo {
fun CoroutineScope.foo() { println("Foo.foo")}
fun Baz.fed(){ println("Foo.fed") }
}
class Baz {
fun CoroutineScope.foo() { println("Baz.foo") }
fun Foo.fed(){ println("Baz.fed") }
}
fun CoroutineScope.foo() { println("CoroutineScope.foo") }
fun foo() { println("Global.foo") }
fun bar(scope: CoroutineScope) {
val f = Foo()
val b = Baz()
println ("Test 1")
foo() // foo() from Global
scope.foo() // foo() from CoroutineScope
//f.foo() // unresolved reference
println ("\nTest 2")
with(scope) {
foo() // foo() from CoroutineScope
//f.foo() // unresolved reference
}
println ("\nTest 3")
with(f) {
scope.foo() // foo() from Foo
foo() // foo() from Global
}
println ("\nTest 4")
with(scope) {
with (f) {
foo() // foo() from Foo
scope.foo() // foo() from Foo
}
}
println ("\nTest 5")
with(f) {
with (scope) {
foo() // foo() from Foo
scope.foo() // foo() from Foo
}
}
println ("\nTest 6")
with(b) {
with(f) {
with (scope) {
foo() // foo() from Foo
fed() // fed() from Baz
}
}
}
println ("\nTest 7")
with(f) {
with(b) {
with (scope) {
foo() // foo() from Baz
fed() // fed() from Foo
}
}
}
}
fun main() = runBlocking {
bar(this)
}
It's interesting to see that when both contexts are made available via with, it is able to figure out which one is the dispatch context and which the extension context, regardless of what order they are provided. But if you specify the extension context directly like f.bar(), it will only look for versions of bar with extension receiver of type Foo, or a direct member of Foo (I'm still a bit hazy about how it views dispatch and extension receivers for a function that is simply defined in the class definition). So it seems the logic is something like:
Given expression x.y():
Find all functions y() that take extension receiver x
For each receiver available c, starting with the most recently added, choose the first x.y() that explicitly takes a dispatch receiver of type c - note that fun CoroutineScope.foo() in global scope acts like it has no dispatch receiver, since tests 6 and 7 show that even though scope is added to the available context list last, Foo (or Baz) version of foo() is used.
Given expression y():
Try to find an x.y() with both a dispatch receiver and extension receiver (x) defined and in the list of available contexts. (note: it chooses the most recently added extension receiver first, then tries to find a matching dispatch receiver (see test 6 and 7 with fed())
If #1 returned nothing, choose most recently added context with dispatch receiver x in available contexts that define function y()
Still nothing? Choose the most recently added context with extension receiver x that define function y()
Fall back to global version of y()
Your declaration:
class Foo {
fun CoroutineScope.foo() {
}
}
defines an extension function foo of CoroutineScope in the context of an instance of the class Foo. This means you can only invoke foo on an instance of CoroutineScope if you are in a scope where this is of the type Foo.
The first attempt f.foo() does exactly the opposite. You invoke foo() on an instance of Foo and this references a CoroutineScope.
The two other examples uses with to set the this reference to Foo and therefor you can invoke foo on the outer CoroutineScope instance.
BTW: with(this) makes no sense, because this will be set to this.

On Kotlin receiver object and extensions

I'm trying to get familiar with the more advanced kotlin features, but i don't know why my little code example compiles and prints "Test A" while not printing "Test B".
Can anybody tell me why Test B is not printed?
class One{
fun delegate(operation: One.()-> Unit){
operation()
}
fun main(args: Array<String>){
val one= One()
fun One.doIt(){
println("Test A")
}
one.delegate { doIt() } //prints Test A
one.delegate {
fun One.doItDifferently(){
println("Test B") //not printed
}
}
}
That's because you don't call the function .toItDifferently(), you only define it (it is a local function, i.e. a function defined inside another function). Modify your example to call the function:
one.delegate {
fun One.doItDifferently(){
println("Test B")
}
doItDifferently() // <- here
}
(UPD, based on the comment) You can call delegate with an anonymous function like this:
one.delegate( // note the parenthesis, not the curly braces
fun One.(){
println("Test B")
}
)
This declaration
one.delegate {
fun One.doItDifferently(){
println("Test B") //not printed
}
}
will just create an empty function with a nested function. doItDifferently() is just declared, but never invoked. Hence, println("Test B") will never be executed.
You're not calling the function.
That is a local extension function on the class One and you are just declaring it. It now exists and is usable in the current scope, but does nothing by itself.
You would need to call/invoke it for it to do anything, as with any normal method:
one.delegate {
fun One.doItDifferently(){
println("Test B")
}
doItDifferently()
}
IntelliJ will actually give you a warning that this function is never used.
Edit: as per your comment, you aren't passing the function at all. This is not possible yet if you want to return the function as reflection does not support local functions.
If you try this:
class One {
fun delegate(operation: One.() -> KFunction<*>) {
operation().call(this)
}
}
fun main(args: Array) {
val one = One()
fun One.doIt() {
println("Test A")
}
one.delegate {
fun One.doItDifferently() {
println("Test B") //not printed
}
this::doItDifferently
}
}
You'll get:
Exception in thread "main" kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Introspecting local functions, lambdas and anonymous functions is not yet fully supported in Kotlin reflection