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

["Request"] Allow composition of nullable Lenses #3113

Open
FWest98 opened this issue Aug 3, 2023 · 2 comments
Open

["Request"] Allow composition of nullable Lenses #3113

FWest98 opened this issue Aug 3, 2023 · 2 comments

Comments

@FWest98
Copy link

FWest98 commented Aug 3, 2023

What version are you currently using?
1.2.0

What would you like to see?
Currently, we can compose Optionals, but we cannot do the same for Lenses with a nullable target type. Composing such lenses is very useful when there is a nested nullable path, but you still want to treat the final property as a nullable instance of that property, instead of an Optional.

So, consider:

@optics
data class Outer(val inner: Inner? = null) { companion object }

@optics
data class Inner(val foo: String? = null) { companion object }

// I would like to be able to do
Outer.nullableInner.nullableFoo.get(instance) // get null when either inner or foo are null
// Now I can only do
Outer.inner.foo.getOrNull(instance)
// or
Outer.inner.nullableFoo.getOrNull(instance)
// but there are no extension properties for
Outer.nullableInner.???

While, of course, the Optional route works fine in most cases, I am using some custom logic that needs to deal with lenses for any kind of property, and I do not want to treat all properties as nullable (by accepting Optionals everywhere) and I prefer to keep the "nullability" of a property just a detail of the usage, where the nullability just comes out of the type parameters (you pass it a Lens with nullable target, you get an instance of a nullable type out as well)

My current workaround is using a custom conversion, like the following:

fun <S, A> Optional<S, A>.toNullableLens(): Lens<S, A?> = Lens(
    { s -> getOrNull(s) },
    { s, a -> if(a == null) s else set(s, a) }
)
@serras
Copy link
Member

serras commented Aug 23, 2023

Note that in Arrow 2.0 fields of nullable types will generate Lens instead of Optional, as explained in this section of the docs. Unfortunately this change cannot be made before, because it break compatibility with our current users.

In any case, I'm wondering if what you're proposing here is a new type of composition which would with nullable types. In general, if we have Lens<A, B?> and Lens<B, C>, we can build a new Lens<A, C?> with the method you describe. Note that this is not exactly the same as the optional composition.

@FWest98
Copy link
Author

FWest98 commented Aug 23, 2023

I had missed that this will change with v2.0. I am curious to see how things work there! But indeed, you can see this as some "new" composition type, however, that might become "messy" with things like reverseGet I am afraid.

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