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

Multiple ensures used to validate the same var does not raise errors #3563

Open
0bon opened this issue Jan 12, 2025 · 2 comments
Open

Multiple ensures used to validate the same var does not raise errors #3563

0bon opened this issue Jan 12, 2025 · 2 comments

Comments

@0bon
Copy link

0bon commented Jan 12, 2025

Arrow versions/libs:

implementation('io.arrow-kt:arrow-fx-coroutines-jvm:2.0.0')
implementation('io.arrow-kt:arrow-core-jvm:2.0.0')
implementation('io.arrow-kt:arrow-core-high-arity:2.0.0')

When doing multiple ensure checks for the same variable, if an error condition arises, it is not raised and collected.

See code below

sealed class interface BookProblem {
    data object BookTypeIsRequired: BookProblem
    data object BookTypeCannotBeLarge: BookProblem
}

enum class BookType {
    None,
    Large,
    Small
}

data class Book(val type: BookType, ) {
    companion object {

        fun create(type: BookType) = either {
            zipOrAccumulate(
                { ensure(type != BookType.None) { BookProblem.BookTypeIsRequired } },
                { ensure(type != BookType.Large) { BookProblem.BookTypeCannotBeLarge } },
            ) { _, _ ->
                Book(type)
            }
        }
    }
}

Doing two ensure checks on the type variable does not return a NonEmptyList(BookProblem) if one of the conditions fails i.e. if type == BookType.None the error will not be raised and the code will assume the variable is valid and proceed to create the Book object.

The following code fixes the issue but forces me to use only one BookProblem to describe two different types of errors:

        fun create(type: BookType) = either {
            zipOrAccumulate(
                { ensure(type != BookType.None && ensure(type != BookType.Large) { BookProblem.BookTypeIsRequired } },
            ) { _ ->
                Book(type)
            }
        }
@kyay10
Copy link
Collaborator

kyay10 commented Jan 14, 2025

Your second code block seems to have syntax errors, so I'm struggling to decipher what it does

@0bon
Copy link
Author

0bon commented Jan 16, 2025

Working code below:

import arrow.core.EitherNel
import arrow.core.raise.either
import arrow.core.raise.ensure
import arrow.core.raise.zipOrAccumulate

sealed interface BookProblem {
    data object BookTypeIsRequired: BookProblem
    data object BookTypeCannotBeLarge: BookProblem
}

enum class BookType {
    None,
    Large,
    Small
}

data class Book(val type: BookType, ) {
    companion object {
        fun create(type: BookType): EitherNel<BookProblem, Book> = either {
            zipOrAccumulate(
                { ensure(type != BookType.None) { BookProblem.BookTypeIsRequired } },
                { ensure(type != BookType.Large) { BookProblem.BookTypeIsRequired } }
            ) { _, _  ->
                Book(type)
            }
        }
    }
}

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

No branches or pull requests

2 participants