fix(runtime): values() in scalar context returns count, not last element#619
Closed
fix(runtime): values() in scalar context returns count, not last element#619
Conversation
Previously, `scalar(values %h)` worked when called directly, but `return values %h` from a sub collapsed to the last value instead of the count when the caller was in scalar context. Same for arrays. Root cause: RuntimeHash.keys() set scalarContextSize on the returned RuntimeArray so list-to-scalar conversion later yields the count. RuntimeHash.values() and RuntimeArray.values() did not, so any list-collapse path (sub return, comma operator) used last-element semantics. Fix: - RuntimeHash.values() sets scalarContextSize on the returned array for both regular and TIED_HASH paths. - RuntimeArray.values() returns a fresh array aliasing the elements (so `for (values @A) { $_++ }` still mutates @A) with scalarContextSize set, so the original @A's scalar-context behaviour is unaffected. Surfaced by Moose's `Class::MOP::Class::get_all_attributes` ending in `return values %attrs`, which made every `scalar $meta->get_all_attributes` return a stringified Attribute instead of a count, breaking 3 subtests in MooseX::Role::Parameterized's t/001-parameters.t. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Owner
Author
|
Superseded — commit moved to PR #618 (fix/walker-gate-property-based) |
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Fix
values()losing its scalar-context count when the result passes through a sub return (or any list-collapse path).In real Perl,
scalar(values %hash)returns the number of values, just likescalar(keys %hash). PerlOnJava already did this for direct calls, but as soon as the result went through a sub return the scalar context degraded to "last list element" semantics:Root cause
RuntimeHash.keys()setscalarContextSizeon the returnedRuntimeArrayso the later list-to-scalar conversion yielded the count.RuntimeHash.values()andRuntimeArray.values()did not, so any list-collapse path (sub return, comma operator, etc.) treated the result as a plain list and applied last-element semantics.Fix
RuntimeHash.values()setsscalarContextSizeon the returned array for both the regular andTIED_HASHpaths.RuntimeArray.values()now returns a freshRuntimeArrayaliasing the elements (sofor (values @a) { $_++ }still mutates@a) withscalarContextSizeset on the new array, so the original@a's own scalar-context behaviour is not affected.How this surfaced
Class::MOP::Class::get_all_attributesends inreturn values %attrs. Everyscalar $meta->get_all_attributestherefore returned a stringifiedMoose::Meta::Attribute=HASH(0x…)instead of a count, breaking 3 subtests inMooseX::Role::Parameterized'st/001-parameters.t(and any downstream code using the same pattern).Test plan
makepasses (full unit test suite)prove src/test/resources/unitshows identical pass/fail set vs master (no regressions; same pre-existing failures only)scalar(values %h)still returns countreturn values %hfrom a sub returns count in scalar contextfor (values @a) { $_ *= 10 }still mutates@a(alias semantics preserved)for (values %h) { $_ *= 10 }still mutates hash valuesGenerated with Devin