I'm actively experimenting with `raise()` and I th...
# arrow
n
I'm actively experimenting with
raise()
and I thought that I would like
x.ensureNotNull { ... }
better than
ensureNotNull(x) {}
. But then I've run into some compilation errors, see the code in my next message. 1. Maybe do you know if the internal compiler error in the first example is already reported? (I use Kotlin 1.8.0 and Arrow 1.1.6-alpha.36 but I have also tried with Kotlin 1.8.10 and 1.8.20-Beta) 2. How can I specify the "context" in the second example? Thanks.
Copy code
import arrow.core.raise.Raise
import arrow.core.raise.RaiseDSL
import arrow.core.raise.ensureNotNull
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

context(Raise<R>)
@OptIn(ExperimentalContracts::class)
@RaiseDSL
public inline fun <R, B : Any> B?.ensureNotNull(raise: () -> R): B {
    contract {
        callsInPlace(raise, InvocationKind.AT_MOST_ONCE)
        returns() implies (this@ensureNotNull != null)
    }
    return this ?: raise(raise())
}

object E1
object E2

context(Raise<E1>, Raise<E2>)
fun f() {
    // Using arrow's ensureNotNull()
    ensureNotNull(1) { E1 } // 1: Internal error occurred while analyzing this expression: "IllegalStateException: Arguments and parameters size mismatch: arguments.size = 2, parameters.size = 3"

    // Using my ensureNotNull()
    1.ensureNotNull { E1 } // 2: How to workaround the compilation error "Multiple arguments applicable for context receiver"?
}
a
unfortunately due to erasure the compiler sometimes has problems figuring out
in theory you can use something like
context(r1@Raise<E1>, r2@Raise<E2>)
and then use the labels when calling the different things
n
Thanks, it really works for both examples but the syntax becomes uglier and less readable 😞
Copy code
context(r1@Raise<E1>, r2@Raise<E2>)
fun f() {
    // Using arrow's ensureNotNull()
    with(this@r1) {
        ensureNotNull(1) { E1 }
    }

    // Using my ensureNotNull()
    with(this@r2) {
        1.ensureNotNull { E2 }
    }
}
s
You should be able to call:
Copy code
context(r1@Raise<E1>, r2@Raise<E2>)
fun f() {
    // Using arrow's ensureNotNull()
    r1.ensureNotNull(1) { E1 }
}
c
I haven't seen that
r1@
syntax in the KEEP, where is it documented?
n
@simon.vergauwen it does not compile unfortunately:
Copy code
context(r1@Raise<E1>, r2@Raise<E2>)
fun f() {
    with(this@r1) {
        ensureNotNull(1) { E1 }
    }

    r1.ensureNotNull(1) { E1 } // Compile error: "Unresolved reference: r1
}
s
this@r1.ensureNotNull(1) { E1 }
? @CLOVIS I remember seeing a discussion somewhere 🤔 but I cannot seem to find it anymore. It was about specific things like this so I guess it's not fully implemented yet.
c
There was a big discussion on the KEEP on whether to allow
context(name: Type)
, from what I remember Roman Elizarov explained that adding labels was not in line with their goals. I'm surprised they added syntax to do it, in the end.
n
this@r1.ensureNotNull(1) { E1 }
This works :)
s
There needs to be some way to distinct between different elements, right? 🤔 So some form of labels is required, I'd say that
label@
is much more in line with what we already have in the language comaared to
name: Type
n
I would have preferred the
name: Type
decision because then we would not need to always write the
this@
prefix - but that's just my opinion :)
c
Well the KEEP originally forbid having the same type multiple times as receiver, so there was no need to disambiguate, and the type could be used as label (e.g.
this@Raise
). I liked the parameter name because they are a kind of parameter, but Roman brought very good arguments against that. I'm sure that discussion was part of the decision for that label syntax. @Norbi I think your probably happens because it's not stable yet, and when it is you won't need to explicitly label receivers in your examples
n
I think your probably happens because it's not stable yet, and when it is you won't need to explicitly label receivers in your examples
Let's hope so 🙂 I've reported it just to be sure: https://youtrack.jetbrains.com/issue/KT-57176/Internal-compiler-error-when-using-multiple-context-receivers
@CLOVIS, it seems that the explicit label will be required with K2 as well:
With K2:
Copy code
With implicit context receiver, call is ambiguous. Specify the receiver explicitly
c
I understand that to mean "with the current build of K2" and not "with the final version of K2", but I could be wrong.