Kev
06/18/2024, 1:43 PMCLOVIS
06/18/2024, 1:53 PMAlejandro Serrano.Mena
06/18/2024, 1:54 PMKev
06/18/2024, 2:11 PMCLOVIS
06/18/2024, 2:17 PMeither {}
, nullable {}
etc introduce a Raise<>
receiver. But that receiver doesn't actually do much. How it works "for real" is that the builder has a try … catch
on a specific exception, and Raise.raise
throws the exact exception the try … catch
expects. This is how raise can "communicate" with the caller, and short-circuit the code. [It's a bit more complex than that for performance/… reasons, but that's not important].
So, you can imagine that
either {
raise("foo")
}
becomes something like
try {
throw ASpecificException("foo")
} catch (e: ASpecificException)
Now, what happens if you try to use the raise
function outside of the DSL? Imagine we write:
lateinit var r: Raise<String>
either {
r = this
}
r.raise("foo")
This is a leaking raise: the Raise
is "leaked" outside of the builder that created it. You can imagine it gets compiled to something like:
lateinit var r: Raise<String>
try {
r = …
} catch (ASpecificException) { … }
throw ASpecificException("foo")
As you can see, the internal exception is now thrown outside of the try-catch, so it can't be caught by the builder, and now you have a weird exception moving around 😅Kev
06/18/2024, 4:05 PMCLOVIS
06/18/2024, 4:16 PMFlowCollector
(the receiver of flow {}
) has the same problem, but for completely different reasons.
In general, objects given to you in a DSL as receiver are really only meant to be used from within the DSL, and if you use them outside, strange stuff can happen.phldavies
06/18/2024, 6:31 PM<http://log.info|log.info> { "msg" }
Alejandro Serrano.Mena
06/18/2024, 6:33 PMphldavies
06/18/2024, 6:36 PM