Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AutoClose and Resource rehaul/cleanup #3431

Open
wants to merge 6 commits into
base: arrow-2
Choose a base branch
from

Conversation

kyay10
Copy link
Collaborator

@kyay10 kyay10 commented May 18, 2024

This PR simplifies the implementations of AutoCloseScope and ResourceScope and allows some of their functions to be inline. It also makes onRelease not suspending.

@kyay10 kyay10 changed the base branch from main to arrow-2 May 18, 2024 04:37
@kyay10 kyay10 marked this pull request as draft May 18, 2024 04:38
Copy link
Contributor

@kyay10 kyay10 requested a review from nomisRev May 18, 2024 05:04
@kyay10 kyay10 marked this pull request as ready for review May 18, 2024 05:04
@kyay10 kyay10 requested a review from serras May 18, 2024 05:04
Copy link
Member

@nomisRev nomisRev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kyay10 amazing work like always ☺️ Very glad you're being critical of all code you come across!! 🙏

Okay, so you made the "single abstract method" installing the onClose, or onRelease finaliser. That indeed affects the AcquireStep in resource, as we've discussed on Slack, but this gives more flexibility.

So both these types, give us the ability to install a non-suspending finaliser, and a suspending finaliser. I think that's a fair DSL, although quite different from where we started. This is great, because in a lot of these cases I've kind-of gotten tunnel vision after so many years.

I'd like to wait the feedback of others.

Copy link
Member

@nomisRev nomisRev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting some changes, or want to discuss some changes:

  • Quite some source compatible breaking changes, which introduces complexity for migration. I would prefer to avoid this, unless we have a strong reason to do so.
  • A lot of unrelated code was changed from bodies to expression, introducing a lot of scoped functions (also). I am personally not a fan of those, especially not of using also within a function body. Can we keep the changes smaller? I 100% support improving readability of operations for users. but I would prefer to keep them separate from actual changes.

Thank you again for the great work @kyay10 👏 👏 Excited by these changes!

@PublishedApi
internal actual fun Throwable.throwIfFatal(): Throwable =
when(this) {
is VirtualMachineError, is ThreadDeath, is InterruptedException, is LinkageError, is CancellationException -> throw this
is VirtualMachineError, is ThreadDeath, is InterruptedException, is LinkageError -> throw this
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hate that this function cannot be private. I really do not want to expose it 😓

This is why I had the CancellationException explicitly in the try/catch, because I rather had a correct definition here, than one specific to AutoCloseable...

public data class Cancelled(val exception: CancellationException) : ExitCase()
public data class Failure(val failure: Throwable) : ExitCase()
public sealed interface ExitCase {
public data object Completed : ExitCase
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

data object 🥳

Comment on lines +22 to +27
public val ExitCase.throwableOrNull: Throwable? get() = when (this) {
ExitCase.Completed -> null
is ExitCase.Cancelled -> exception
is ExitCase.Failure -> failure
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we define this inside ExitCase so that we don't need an import for it? Preferably as a function I'd say, that'd be more in line with the APIs we now from Result.

I also think exceptionOrNull is a more common name, than throwableOrNull.

return a
cancelAll(ExitCase(e))
error("Unreachable, cancelAll should throw the exception passed to it. Please report this bug to the Arrow team.")
}.also { cancelAll(Completed) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove also here? I'd prefer regular function invocation after } if possible.

I try to avoid scoping function everywhere where they might be redundant. I also see you changed a lot of function bodies, to expressions, and rely on also instead. I personally feel this really degrades readability.

This is a common occurrence in this PR, I rather not have these unrelated code changes purely for style reasons. It introduces a lot of code churn for no strong reason. Also takes away the focus of this PR.

* It results either in [ExitCase.Completed], [ExitCase.Cancelled] or [ExitCase.Failure] depending on the terminal state of [Resource] lambda.
*/
@ResourceDSL
public suspend inline fun <A> ResourceScope.install(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these being defined as extension functions, this breaks source compatibility with 1.x.x. Why not define this in the interface directly?

@PublishedApi
internal class DefaultAutoCloseScope : AutoCloseScope {
private val finalizers = Atomic(emptyList<(Throwable?) -> Unit>())
public inline fun <A> AutoCloseScope.autoClose(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idem, this introduces a source breaking change, to support suspend in the acquire step. If that is needed, I think users should prefer onClose, or Resource instead.

So I would prefer to revert this also.

@serras
Copy link
Member

serras commented May 18, 2024

Thanks for your work on making the DSL better, @kyay10. I really like everything which removes constraints from our DSLs, so if we can have suspend and non-suspend functions when before we had only the former, that's a huge win for me!

Having said so, we promised to keep source compatibility between 1.2.x and 2.0 (except for the changes in Optics KSP), and some of these changes break that source compatibility. I would really like to keep this promise: we've already broken code in the past, and I really want to make things right this time. This means that, at the very least, the same functions need to be exposed from the same package or class they originally were.

Going also in the direction pointed by @nomisRev, maybe this could be easier to review if the fundamental changes were broken from the refactoring changes. In general in Arrow we try to not refactor things like val to let style, or vice versa, and just keep the original author's code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants