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

add filter, deprecate unsafeSelect #988

Merged
merged 2 commits into from
Dec 11, 2020
Merged

add filter, deprecate unsafeSelect #988

merged 2 commits into from
Dec 11, 2020

Conversation

julien-truffaut
Copy link
Member

@julien-truffaut julien-truffaut commented Dec 10, 2020

This PR adds Optional.filter and filter method on all Optics and ApplyOptics.

filter allows to select the targets which satisfy a predicate, for example:

val positiveNumbers = Traversal.fromTraverse[List, Int].filter(_ > 0)
val list = List(1,2,-3,4,-5)

positiveNumbers.getAll(list) == List(1,2,4)
positiveNumbers.modify(_ * 10)(list) == List(10,20,-3,40,-5) // only the positive numbers are multiplied by 10

filter can break the fusion law that says that modify(f).modify(g) == modify(f andThen g), for example:

val list       = List(1, 5, -3)
val firstStep  = positiveNumbers.modify(_ - 3)(list)            // List(-2, 2, -3)
val secondStep = positiveNumbers.modify(_ * 2)(firstStep)       // List(-2, 4, -3)
val bothSteps  = positiveNumbers.modify(x => (x - 3) * 2)(list) // List(-4, 4, -3)

In bothSteps, the first value is -4 = (1 - 3) * 2 but in secondStep it is -2 = (1 - 3).
The second update _ * 2 wasn't applied because the target became negative after the first update _ - 3.

In other words, filter breaks the property if replace or modify invalidate the predicate.

A safe usage would be to filter on one field and update another one, for example:

case class User(name: String, coins: Int, address: Address)
case class Address(line1: String, country: String)

val users: Traversal[State, User] = ...
val coins: Lens[User, Int] = ...

users
  .filter(_.address.country == "UK")
  .andThen(coins)
  .modify(_ - 5) // remove 5 coins to all UK users

Copy link
Collaborator

@cquiroz cquiroz left a comment

Choose a reason for hiding this comment

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

Cool, this will be useful

@jdegoes
Copy link
Contributor

jdegoes commented Dec 10, 2020

Yes, please!

@julien-truffaut julien-truffaut merged commit ec4d877 into master Dec 11, 2020
@julien-truffaut julien-truffaut deleted the filter-select branch December 11, 2020 08:51
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.

3 participants