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

Fix the return type of Enumerable#sum/product for union elements #15314

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

rvprasad
Copy link

Using the first type of a union type as the type of the result of Enumerable#sum/product() call can cause runtime failures, e.g. [1, 10000000000_u64].sum/product will result in an OverflowError. A safer alternative is to flag/disallow the use of union types with Enumerable#sum/product() and recommend the use of Enumerable#sum/product(initial) with an initial value of the expected type of the sum/product call.

@Blacksmoke16 Blacksmoke16 added breaking-change topic:stdlib:numeric kind:bug A bug in the code. Does not apply to documentation, specs, etc. labels Dec 26, 2024
@Blacksmoke16 Blacksmoke16 linked an issue Dec 26, 2024 that may be closed by this pull request
@rvprasad
Copy link
Author

This PR expands on the (accidentally closed) PR 15308.

Tagging @Blacksmoke16, @straight-shoota, and @BlobCodes to continue the discussion here.

Using the first type of a union type as the type of the result of
`Enumerable#sum/product()` call can cause runtime failures, e.g. `[1,
10000000000_u64].sum/product` will result in an ``OverflowError``. A
safer alternative is to flag/disallow the use of union types with
`Enumerable#sum/product()` and recommend the use of
`Enumerable#sum/product(initial)` with an initial value of the
expected type of the sum/product call.
Comment on lines 2302 to 2304
raise("Enumerable#sum/product() does support Union types. " +
"Instead, use Enumerable#sum/product(initial) with an " +
"initial value of the expected type of the sum/product call.")
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: Polish the error message:

Suggested change
raise("Enumerable#sum/product() does support Union types. " +
"Instead, use Enumerable#sum/product(initial) with an " +
"initial value of the expected type of the sum/product call.")
raise("`Enumerable#sum` and `#product` cannot determine the initial value from a union type. " +
"Please pass an initial value of the intended type to the call.")

Copy link
Author

@rvprasad rvprasad Dec 27, 2024

Choose a reason for hiding this comment

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

After reading your fix, I realized a missing negation in the first sentence of error message I committed :)

Also, how about we update the error message as follows?

raise("Enumerable#sum` and #product do not support union types. Instead, use Enumerable#sum/product(initial) with an initial value of the expected type of the sum/product call.")

Following is my reasoning for the above change.

  1. The existing logic fails to identify an appropriate/safe type that can hold the final value of the call.
  2. Using the identity is a way of determining the appropriate/safe type. Since it is an implementation detail, I think surface such details in documentation while mentioning what (not how) is wrong and its fix in the error message may be better.

Copy link
Member

Choose a reason for hiding this comment

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

"do not support union types" isn't entirely accurate. They do support them. Just without automatically determining the return type, hence the need to specify explicitly.

Copy link
Author

Choose a reason for hiding this comment

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

With this change, "sum()" and "product()" will not support union types (but "sum(initial)" and "product(initial)" will support union types). So, do you mean that we should be precise in the error message and the doc by referring to the no-arg variant of the methods?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, we could differentiate between the different overloads by signature.

Enumerable#sum() and #product() do not support union types.`

It's a bit of a subtle detail though. Hence my suggestion to write out the issue explicitly:

Enumerable#sum and #product cannot determine the initial value from a union type.

I'm fine either way though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:stdlib:collection
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Return type of Enumerable#sum and #product for union elements
3 participants