Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add support for Iterable to sizeIs #11047

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

Open
wants to merge 1 commit into
base: 2.13.x
Choose a base branch
from

Conversation

wernerschram
Copy link

This allows the sizeIs function to also cover the sizeCompare(Iterable[_]) variation.

The main motivation for adding this is that sizeIs currently returns an unintuitive result when used in the form col1.sizeIs == col2.sizeIs. This notation is not documented and likely not intended, but it is valid and it feels intuitive that it should result in comparing the size of the two collections.

The reason for that is that col1.sizeIs == 5 is the functional equivalent of col1.size == 5 and calls col1.sizeCompare(5) == 0. Given that sizeCompare has a second implementation: sizeCompare(Iterable[_]), I would expect that col1.sizeIs == col2.sizeIs would be the functional equivalent to col1.size == col2.size and call col1.sizeCompare(col2) == 0. The problem is that the syntax col1.sizeIs == col2.sizeIs is valid, but this is because col1.sizeIs returns a value class for col1. This causes the == operator to be handled by Any.==() which calls the equals method for the collections.

So the result doesn't represent the equality of the sizes of the collections, but the equality of the collections itself. So currently Seq(1,2).sizeIs == Seq(2,3).sizeIs results in false.

@scala-jenkins scala-jenkins added this to the 2.13.17 milestone Apr 16, 2025
@SethTisue
Copy link
Member

@scala/collections @NthPortal

@SethTisue SethTisue added library:not-forward-bincompat library:collections PRs involving changes to the standard collection library labels Apr 17, 2025
@NthPortal
Copy link
Contributor

NthPortal commented Apr 17, 2025

the problem is, col1.sizeIs == col2.sizeIs is semantically awful/nonsensical in English (the language of the Scala stdlib API).

sizeIs already stretches English semantics. take for example, col.size < 4—that code reads as "col's size is less than 4". consequently, < in that snippet means "is less than". if we then consider the equivalent code with sizeIs, we would have col.sizeIs < 4, which consequently reads as "col's size is is less than 4". thankfully, we tend to have no problem dropping the "is" from the reading of < (and all the other comparison operators), so we can instead read it as "col's size is less than 4".

this does not work when comparing two collections. if we take your example of col1.sizeIs == col2.sizeIs, that reads as "col1's size is equal to col2's size is", which just doesn't work in English.

if you can come up with an API that reads fine as prose in English, I would love to add it, but the best I've ever been able to come up with is col1.sizeIs <_sizeOf(col2), which is an ugly method name with an underscore in the middle which we in general strongly do not like. I agree that it's a gap in the API, but I have found no good solution and unfortunately I am not in favour of this particular one.


Personally, I sometimes read if (x < 5) as "if x less than 5" rather than "if x is less than 5", so it feels quite natural to me at least

@SethTisue
Copy link
Member

SethTisue commented Apr 17, 2025

Hmm. Perhaps we could provide a different way to do this that reads better, but since universal equality means we have no way of preventing col1.sizeIs == col2.sizeIs from being legal, shouldn't it behave sensibly?

@lrytz
Copy link
Member

lrytz commented Apr 17, 2025

Mhm.. Maybe sizeIs should have been called sizeComp. That name would not attempt to be English language as much, and also make the connection to sizeCompare more obvious.

@wernerschram
Copy link
Author

Tough one. I think that ideally the name should convey that you can use it to compare the size without actually calculating it, to distinguish it from size.

Perhaps deferredSize: col1.deferredSize == col2.deferredSize, so it reads "col1s deferred size equals col2s deferred size", so it emphasizes the fact that the size isn't necessarily calculated to evaluate the result.

@SethTisue
Copy link
Member

or lazySize?

I'm not sure it's actually worth changing, though, given that the sizeIs == sizeIs case is unusual. we could document as it working (once it does) and just mention/acknowledge in the doc that it reads strangely?

@NthPortal
Copy link
Contributor

NthPortal commented Apr 24, 2025

we could document as it working (once it does)

I don't actually think we should change the behaviour of a.sizeIs == b.sizeIs—I think it's an ugly API, and even if we add a deprecated override, having them compare as equal just for being the same size just encourages people to use it and suppress the deprecation warning. I'd rather it not even compile, though I don't think we have an annotation for that.

Maybe sizeIs should have been called sizeComp

I disagree with this. there is a strong API correspondence with the Ordered API, and I think breaking that correspondence would be a mistake.

a.size.compare(b.size) <-> a.sizeCompare(b)
a.size.compare(4)      <-> a.sizeCompare(4)
(a.size < 4)           <-> (a.sizeIs < 4)

calling it sizeComp would muddy that correspondence by putting its name in between the different operations:

a.size.compare(4) <-> a.sizeCompare(4)
(a.size < 4)      <-> (a.sizeComp < 4)

I've been thinking about this a lot, and had a thought: there's a discrepancy in the #sizeCompare(Iterable[_]), API, and I'm wondering if we might use it as the basis for expanding the API. consider the following:

a.size.compare(b.size) <-> a.sizeCompare(b)

there are two ways to think of sizeCompare here: as a contraction of size.compare, or as a special type of comparison operation called sizeCompare. if we read it as the former, then there is a discrepancy in that size is missing from the second collection (in terms of reading the code). by similar logic, does the following read well enough to be acceptable?

(a.size < b.size) <-> (a.sizeIs < b)

does that read clearly/cleanly? can/does one's mind translate "a's size is less than b" to "a's size is less than b's size" automatically?

thoughts?

@NthPortal
Copy link
Contributor

since it hasn't been linked already, prior discussion happened at scala/collection-strawman#338 and #6950

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
library:collections PRs involving changes to the standard collection library library:not-forward-bincompat
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants