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

Result 2.0: unsafe unwrapping of Result.value and Result.error #104

Open
kirillzh opened this issue Jun 3, 2024 · 3 comments
Open

Result 2.0: unsafe unwrapping of Result.value and Result.error #104

kirillzh opened this issue Jun 3, 2024 · 3 comments

Comments

@kirillzh
Copy link
Contributor

kirillzh commented Jun 3, 2024

I noticed that the new inline value class in API 2.0 lets us access result.value directly without checking if it’s actually safe, which wasn’t the case before. Here’s what I mean:

val result: Result<Int, SomeError> = getResult()
result.value // This compiles even if the result is an error, leading to potential runtime errors.

This could lead to runtime exceptions that were harder to make before when the API required type checking and more explicit unwrapping using getOrThrow() (which is a lot easier to catch or denylist through code analysis).

It seems like API 2.0 introduces a downgrade in compile-time safety compared to the previous version. Could we consider reinstating some form of this safety, perhaps through Kotlin contracts or another mechanism, to prevent potential runtime errors?

@kirillzh kirillzh changed the title Result 2.0: unsafe unwrapping via Result.value Result 2.0: unsafe unwrapping of Result.value and Result.error Jun 3, 2024
@michaelbull
Copy link
Owner

michaelbull commented Jun 5, 2024

Could we consider reinstating some form of this safety, perhaps through Kotlin contracts or another mechanism, to prevent potential runtime errors?

Do you have a proposal of which compiler contract would achieve this? We effectively need user-defined guards, such that you can't call .value unless you've done an isOk/isErr check - I don't think such a thing exists in Kotlin?

@raamcosta
Copy link

raamcosta commented Jun 26, 2024

If value is always available, then maybe it should be nullable. This way we can check if it is null, and get smart cast.

It would also mean that people are more likely to use better approaches such as doing .onSuccess { value -> } given that inside the lambda, "value" wouldn't be null.

But I may be missing something?

@michaelbull
Copy link
Owner

It being nullable would force it to be boxed at all call sites. See the following example from Kotlin's docs:

interface I

@JvmInline
value class Foo(val i: Int) : I

fun asNullable(i: Foo?) {}

fun main() {
    val f = Foo(42)

    asNullable(f)  // boxed: used as Foo?, which is different from Foo
}

https://kotlinlang.org/docs/inline-classes.html#representation

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

No branches or pull requests

3 participants