-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Optimize Chain length methods #4166
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
f331cc8
Optimize Chain.length implementation
bplommer 4ec151c
Optimize Chain.knownLength
bplommer 237c2ed
Remove stack-unsafe recursion
bplommer d5000f3
Fix scala 3 compilation
bplommer bb24501
Tail-recursive length loop
bplommer 718dc8d
Remove dead code
bplommer 2125218
Fix comment
bplommer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package cats.data | ||
|
||
private[data] trait ChainCompat[+A] { _: Chain[A] => | ||
|
||
/** | ||
* The number of elements in this chain, if it can be cheaply computed, -1 otherwise. | ||
* Cheaply usually means: Not requiring a collection traversal. | ||
*/ | ||
final def knownSize: Long = | ||
this match { | ||
case Chain.Empty => 0 | ||
case Chain.Singleton(_) => 1 | ||
case _ => -1 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package cats | ||
package data | ||
|
||
private[data] trait ChainCompat[+A] { self: Chain[A] => | ||
|
||
/** | ||
* The number of elements in this chain, if it can be cheaply computed, -1 otherwise. | ||
* Cheaply usually means: Not requiring a collection traversal. | ||
*/ | ||
final def knownSize: Long = | ||
this match { | ||
case Chain.Empty => 0 | ||
case Chain.Singleton(_) => 1 | ||
case Chain.Wrap(seq) => seq.knownSize.toLong | ||
case _ => -1 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if we have a test for this, but if not we should add that
chain.length == chain.toList.length.toLong
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really wondering how come
Chain#length
becameLong
rather than justInt
(which is used for all other collections' length). Is there any chance thatChain#length
can outgrowInt
type?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's annoying - it means
Chain
can never extendIterable
orSeq
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure it can, just cast to Int, but I don't think that's a good idea anyway. Make a wrapper and call
toSeq
and just implement the methods that way.Why is the length an Int in scala? I think because java did this in java.util. Why did java.util do it? In those days computers were all 32 bits, so Long was more expensive (that isn't the case now, I don't think), also the idea of an arraylist with more than 2 billion items seemed crazy in the late 90s.
With scala List, there is nothing that I know of that prevents you from making a list more than 2 billion long: it is just a series of pointers. But if you do, I guess
length
will just throw or return junk.In cats, we preferred Long for two reasons:
So, if you want to implement
def toSeq: Seq[A]
on Chain, you can totally do it. The length being cast toInt
is no more of a lie than whenList
does it, and we live with that all the time. I don't see the problem.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not without return type polymorphism (the method name
length
is already taken by theLong
version)- but yeah, you can still do a conversion.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, but the
toSeq
ortoIterable
without doing a deep copy does work.