https://kotlinlang.org logo
#arrow
Title
# arrow
c

CLOVIS

11/24/2023, 4:04 PM
Has there been any talk of providing a
early {}
DSL with a
Raise<Unit>
, so you can use
ensure
etc for early-returns without any error message?
y

Youssef Shoaib [MOD]

11/24/2023, 4:18 PM
That seems interesting. Do you propose providing overloads for ensure etc that expect a
Raise<Unit>
and hence don't require an ugly empty block?
c

CLOVIS

11/24/2023, 5:08 PM
Yes. It would essentially be the same as
nullable
, but for "purely impure functions" (those that do only side effects)
y

Youssef Shoaib [MOD]

11/24/2023, 5:09 PM
Sounds worth a PR! Only annoying thing is we'll likely need to introduce a new Raise variant specifically for Raise Unit so that we can support member extension functions without using context receivers
I think that's what nullable does for the same reasons, but maybe I'm misremembering
c

CLOVIS

11/24/2023, 5:12 PM
Here's an example of such function:
Copy code
fun MutableSet<AccessRight>.addRightsForUser(user: User) = early {
    ensure(…)
    ensure(…)

    add(AccessRight(…, user))
}
I don't know if it's useful enough to warrant its own builder, but it's kinda ugly to have to go back to
if (!condition) …
in these cases Name candidates: •
early
(it uses Raise as an early return) •
do
(it's just a block of code, and
run
is already taken) •
unit
(it returns
Unit
)
I think that's what nullable does for the same reasons,
I remember the same
Maybe it could be another DSL that uses
NullableRaise
under the hood?
Raise<Nothing?>
and
Raise<Unit>
are isomorphic, they're both raising a singleton, so all utilities are probably the same
By "utilities", I mean lambda-less
ensure
, the
ignoreErrors
helper, etc
y

Youssef Shoaib [MOD]

11/24/2023, 5:14 PM
Another candidate:
breakable
c

CLOVIS

11/24/2023, 5:16 PM
I like the idea, but I would expect it to work with the
break
keyword. Maybe
raisable
? But that might be confused as "the primary way to use
Raise
, since it shares the name", whereas it's really a narrow use-case
Maybe
impure {}
?
y

Youssef Shoaib [MOD]

11/24/2023, 5:16 PM
I don't think implementing it in terms of
NullableRaise
would change much. The only reason we need it is so that we can define those utils without needing context receivers, but other than that
NullableRaise
doesn't have any custom behaviour
impure {}
is interesting because this builder will be returning Unit anyways, so this makes it clear that we're only performing side effects that can also fail and end the computation early
1
c

CLOVIS

11/24/2023, 5:19 PM
For the implementation, it's probably just
Copy code
inline fun unit(block: NullableRaise.() -> Unit): Unit =
    fold({ block(this) }, recover = { Unit }, transform = { Unit })
y

Youssef Shoaib [MOD]

11/24/2023, 5:20 PM
Well, if we just make a
UnitRaise
, the implementation is then:
Copy code
inline fun unit(block: UnitRaise.() -> Unit) = merge(block)
c

CLOVIS

11/24/2023, 5:20 PM
> other than that
NullableRaise
doesn't have any custom behaviour It already has lambda-less ensure, ignoreErrors etc, and these would be useful for the same reasons
y

Youssef Shoaib [MOD]

11/24/2023, 5:21 PM
Yes, I meant it doesn't have any logic inside, only those utils, so using
NullableRaise
as an implementation detail won't give us anything really
c

CLOVIS

11/24/2023, 5:21 PM
Well, if you create a
UnitRaise
, you have to duplicate them, right?
y

Youssef Shoaib [MOD]

11/24/2023, 5:23 PM
Yeah, I was assuming that we want to 1) be able to
raise(Unit)
and 2) not give any special behaviour to nulls
👀 1
But if not, then we can indeed just use a
NullableRaise
Note that
OptionRaise
exists as well, even though it could be implemented in terms of
NullableRaise
, but that's because we want the available utils to be slightly different
c

CLOVIS

11/24/2023, 5:25 PM
Yeah,
raise(null)
is weird here.
I'll think about it some more 🙂 If you think it's worth creating an issue, please ping me in it (
@clovis-ai
on GitHub)
👍 1
y

Youssef Shoaib [MOD]

11/24/2023, 5:32 PM
I think part of this might be due to bindAll extensions, which differ between
NullableRaise
and
OptionRaise
in their types. I think in a context receivers world we'd just have nullable, impure, and option all giving us a
context(Raise<Null>, Raise<None>, Raise<Unit>)
and we'd have the same utilities thus for each one, with the only difference being the ultimate return type at the end. I'll make a PR for impure, and we can continue the discussion there
👍 1
c

CLOVIS

11/24/2023, 5:35 PM
Yeah, I expect all XXXRaise classes to disappear with context receivers. Ah, I'm so hyped 😅
y

Youssef Shoaib [MOD]

11/30/2023, 2:58 AM
https://github.com/arrow-kt/arrow/pull/3305 I've tagged you on Github as well :)
thank you color 2