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 some Iterable tests (#2894) #3040

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open

Conversation

jsoizo
Copy link
Contributor

@jsoizo jsoizo commented Apr 13, 2023

This is an additional test to increase coverage of Iterable #2894 .
I will add a few more except for the ones with @deprecated annotations.

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.

Looks great! Thank you @jsoizo 🙌

I will add a few more except for the ones with @deprecated annotations.

Do you want to add them in this PR, or another one? Whatever works best for you is fine ☺️

import io.kotest.property.arbitrary.boolean
import io.kotest.property.arbitrary.int
import io.kotest.property.arbitrary.list
import io.kotest.property.arbitrary.orNull
import io.kotest.property.arbitrary.pair
import io.kotest.property.arbitrary.string
import io.kotest.property.arbitrary.*
Copy link
Member

Choose a reason for hiding this comment

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

We don't use * imports in the Arrow codebase.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't use * imports in the Arrow codebase.

I've put that back in.

Do you want to add them in this PR, or another one?

I will create another one.

Copy link
Contributor Author

@jsoizo jsoizo Apr 17, 2023

Choose a reason for hiding this comment

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

@nomisRev I have added some tests and kDocs, could you please review them again?
Also, I have a question about the crosswalk implementation and left a comment with a question.

@nomisRev nomisRev requested a review from a team April 16, 2023 12:50
Comment on lines +1269 to +1270
* Applies function [f] to each element
* and returns a list for the applied result Iterable<B>.
Copy link
Contributor Author

@jsoizo jsoizo Apr 17, 2023

Choose a reason for hiding this comment

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

I am not sure if this explanation is adequate and would be happy to receive a revised proposal.
The same goes for crosswalkMap and crosswalkNull.

* res shouldBe listOf("x2")
* }
* ```
*/
public fun <A, B> Iterable<A>.crosswalkNull(f: (A) -> B?): List<B>? =
Copy link
Contributor Author

@jsoizo jsoizo Apr 17, 2023

Choose a reason for hiding this comment

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

If you pass emptyList() as the first argument of fold, the results of Ior.fromNullables and croswalkNull will also not be null, since bs is always non-null. If you expect croswalkNull to be null if Iterable<A> is empty or all results of applying the function f are null, it is better to pass null as the first argument of fold.
Furthermore, it appears that if we modify it as described, crosswalkNull will no longer return an empty list, so it would be a good idea to set the return type to NonEmptyList<B>? ?

Copy link
Member

Choose a reason for hiding this comment

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

If I understand correctly, this function should:

  • return null if (and only if) f(it) returns null for some component,
  • return emptyList() if the Iterable is empty
  • return non-empty for a non-empty list where evey application of f returns non-null.

Does this make sense? Does this coincide with the behavior here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@serras Thank you for your reply.

Does this make sense?

I have the same understanding as you have written.

Does this coincide with the behavior here?

However, the behavior seems not to coincides with the understandings.
The first and third case of following tests fails.

class CrosswalkNullTest : FunSpec({
    test("return null if f(it) returns null") {
        val list = listOf(1, 2, 3)
        val result = list.crosswalkNull { null }
        // This test fails because result is emptyList()
        result shouldBe null
    }

    test("return emptyList() if Iterable is empty") {
        val list = emptyList<Int>()
        val result = list.crosswalkNull { it.toString() }
        // This test passes
        result shouldBe emptyList()
    }

    test("return non-empty if Iterable is non-empty and f(it) returns not-null") {
        val list = listOf(1, 2, 3)
        val result = list.crosswalkNull { it.toString() }
        // This test fails because result is listOf("3", "2", "1")
        result shouldBe listOf("1", "2", "3")
    }
})

* fun test() {
* val ints = listOf(1, 2)
* val res = ints.crosswalk { i -> listOf("a${i}", "b${i}", "c${i}") }
* res shouldBe listOf(listOf("a2", "a1"), listOf("b2", "b1"), listOf("c2", "c1"))
Copy link
Contributor Author

@jsoizo jsoizo Apr 17, 2023

Choose a reason for hiding this comment

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

The third argument to ior.fold, listOf(l) + r, makes the list appear to be in reverse order of the original list. I would think that r +l would be a better behavior, but what do you think?

f(a).align(bs) { ior ->
      ior.fold(
        { listOf(it) },
        ::identity,
        { l, r -> listOf(l) + r }
      )
    }

Copy link
Member

Choose a reason for hiding this comment

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

I agree, this seems wrong to me too. WDYT, @nomisRev?

@serras
Copy link
Member

serras commented Jul 5, 2023

@jsoizo I've talked with @nomisRev, and we've agreed that it makes sense to fix the different crosswalk implementations, based on your findings in this PR.

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.

4 participants