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
More problems with push/keys $scalar #10896
Comments
From @cpansprout$ perl5.13.7 -le 'push 42, 1,2,3; print "@42"' $ perl5.13.7 -le 'push ${\42}, 1,2,3; print "@42"' So, with strict mode off, symbolic deferencing is allowed unless it is detected at compile-time. Let’s try something else: $ perl5.13.7 -le 'use strict; push *f, 1,2,3; print "@::f"' $ perl5.13.7 -le 'use strict; use constant g=>*f; push g, 1,2,3; print "@::f"' So push is sometimes stricter than strict. The edge cases for keys are obviously even more weird: $ perl5.13.7 -le '%foo = qw(a 1 b 1 c 1); $,=" ";print keys foo =>' $ perl5.13.7 -le '%foo = qw(a 1 b 1 c 1); $,=" ";print keys "foo"' I thought foo => and "foo" were equivalent. $ perl5.13.7 -le '%foo = qw(a 1 b 1 c 1); $,=" ";print keys *foo' But *foo is a perfectly valid array/hash reference (even under strict). Why cannot it be resolved like a blessed scalar with @{} and %{} overloading? More inconsistencies: $ perl5.13.7 -le 'keys %$x = 7' Also, to bring this up again, what if I have an object that is a blessed array (I do) the contents of which are part of the public API (they are) and the blessing exists for the sake of calling methods on it? What if I want to add %{} overloading to it as an alternate interface? In that case, I am not changing the API (even by David Golden’s standards), as ref() returns the same thing. But that will break any code doing keys $object. So, could we please make this simpler? This set of rules for dealing with constants and overloading does not match anything elsewhere in Perl. So it is just another set of edge cases for people to learn. Oh look, there is a patch attached hereto. (This also eliminates the undocumented ‘keys undef’ behaviour and makes keys $foo consistent with keys %$foo in terms of autovivification.) Flags: Site configuration information for perl 5.13.7: Configured by sprout at Thu Dec 9 14:53:58 PST 2010. Summary of my perl5 (revision 5 version 13 subversion 7) configuration: Locally applied patches: @INC for perl 5.13.7: Environment for perl 5.13.7: |
From @cpansproutInline Patchdiff --git a/doop.c b/doop.c
index 550e6fb..35efba6 100644
--- a/doop.c
+++ b/doop.c
@@ -1436,9 +1436,8 @@ Perl_do_kv(pTHX)
register HE *entry;
const I32 gimme = GIMME_V;
const I32 dokv = (PL_op->op_type == OP_RV2HV || PL_op->op_type == OP_PADHV);
- /* op_type is OP_RKEYS/OP_RVALUES if pp_rkeys delegated to here */
- const I32 dokeys = dokv || (PL_op->op_type == OP_KEYS || PL_op->op_type == OP_RKEYS);
- const I32 dovalues = dokv || (PL_op->op_type == OP_VALUES || PL_op->op_type == OP_RVALUES);
+ const I32 dokeys = dokv || (PL_op->op_type == OP_KEYS);
+ const I32 dovalues = dokv || (PL_op->op_type == OP_VALUES);
if (!hv) {
if (PL_op->op_flags & OPf_MOD || LVRET) { /* lvalue */
diff --git a/embed.h b/embed.h
index d484a10..e4b83ea 100644
--- a/embed.h
+++ b/embed.h
@@ -939,7 +939,6 @@
#define ck_method(a) Perl_ck_method(aTHX_ a)
#define ck_null(a) Perl_ck_null(aTHX_ a)
#define ck_open(a) Perl_ck_open(aTHX_ a)
-#define ck_push(a) Perl_ck_push(aTHX_ a)
#define ck_readline(a) Perl_ck_readline(aTHX_ a)
#define ck_repeat(a) Perl_ck_repeat(aTHX_ a)
#define ck_require(a) Perl_ck_require(aTHX_ a)
@@ -1334,7 +1333,6 @@
#define pp_rand() Perl_pp_rand(aTHX)
#define pp_range() Perl_pp_range(aTHX)
#define pp_rcatline() Perl_pp_rcatline(aTHX)
-#define pp_reach() Perl_pp_reach(aTHX)
#define pp_read() Perl_pp_read(aTHX)
#define pp_readdir() Perl_pp_readdir(aTHX)
#define pp_readline() Perl_pp_readline(aTHX)
@@ -1355,14 +1353,12 @@
#define pp_rewinddir() Perl_pp_rewinddir(aTHX)
#define pp_right_shift() Perl_pp_right_shift(aTHX)
#define pp_rindex() Perl_pp_rindex(aTHX)
-#define pp_rkeys() Perl_pp_rkeys(aTHX)
#define pp_rmdir() Perl_pp_rmdir(aTHX)
#define pp_rv2av() Perl_pp_rv2av(aTHX)
#define pp_rv2cv() Perl_pp_rv2cv(aTHX)
#define pp_rv2gv() Perl_pp_rv2gv(aTHX)
#define pp_rv2hv() Perl_pp_rv2hv(aTHX)
#define pp_rv2sv() Perl_pp_rv2sv(aTHX)
-#define pp_rvalues() Perl_pp_rvalues(aTHX)
#define pp_sassign() Perl_pp_sassign(aTHX)
#define pp_say() Perl_pp_say(aTHX)
#define pp_scalar() Perl_pp_scalar(aTHX)
diff --git a/ext/Opcode/Opcode.pm b/ext/Opcode/Opcode.pm
index 0766940..a9e746f 100644
--- a/ext/Opcode/Opcode.pm
+++ b/ext/Opcode/Opcode.pm
@@ -311,7 +311,7 @@ invert_opset function.
rv2av aassign aelem aelemfast aslice av2arylen
rv2hv helem hslice each values keys exists delete aeach akeys avalues
- boolkeys reach rvalues rkeys
+ boolkeys
preinc i_preinc predec i_predec postinc i_postinc postdec i_postdec
int hex oct abs pow multiply i_multiply divide i_divide
diff --git a/op.c b/op.c
index 4c3c876..ea75d0e 100644
--- a/op.c
+++ b/op.c
@@ -310,12 +310,6 @@ Perl_Slab_Free(pTHX_ void *op)
#define RETURN_UNLIMITED_NUMBER (PERL_INT_MAX / 2)
-#define CHANGE_TYPE(o,type) \
- STMT_START { \
- o->op_type = (OPCODE)type; \
- o->op_ppaddr = PL_ppaddr[type]; \
- } STMT_END
-
STATIC const char*
S_gv_ename(pTHX_ GV *gv)
{
@@ -7413,47 +7407,67 @@ Perl_ck_fun(pTHX_ OP *o)
"Useless use of %s with no values",
PL_op_desc[type]);
- if (kid->op_type == OP_CONST &&
- (kid->op_private & OPpCONST_BARE))
- {
- OP * const newop = newAVREF(newGVOP(OP_GV, 0,
- gv_fetchsv(((SVOP*)kid)->op_sv, GV_ADD, SVt_PVAV) ));
- Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
+ if (kid->op_type != OP_RV2AV && kid->op_type != OP_PADAV) {
+ SV * const kidsv =
+ kid->op_type == OP_CONST ? ((SVOP*)kid)->op_sv : NULL;
+ OP * const newsubop =
+ kidsv && !isGV(kidsv) && !SvROK(kidsv)
+ ? newGVOP(
+ OP_GV, 0, gv_fetchsv(kidsv, GV_ADD, SVt_PVAV)
+ )
+ : kid;
+ OP * const newop = newAVREF(newsubop);
+
+ if (kid->op_type == OP_CONST &&
+ (kid->op_private & OPpCONST_BARE))
+ Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
"Array @%"SVf" missing the @ in argument %"IVdf" of %s()",
SVfARG(((SVOP*)kid)->op_sv), (IV)numargs, PL_op_desc[type]);
+
+ if (newsubop == kid)
+ kid->op_sibling = NULL;
+ else
#ifdef PERL_MAD
- op_getmad(kid,newop,'K');
+ op_getmad(kid,newop,'K');
#else
- op_free(kid);
+ op_free(kid);
#endif
kid = newop;
kid->op_sibling = sibl;
*tokid = kid;
}
- else if (kid->op_type != OP_RV2AV && kid->op_type != OP_PADAV)
- bad_type(numargs, "array", PL_op_desc[type], kid);
op_lvalue(kid, type);
break;
case OA_HVREF:
- if (kid->op_type == OP_CONST &&
- (kid->op_private & OPpCONST_BARE))
- {
- OP * const newop = newHVREF(newGVOP(OP_GV, 0,
- gv_fetchsv(((SVOP*)kid)->op_sv, GV_ADD, SVt_PVHV) ));
- Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
+ if (kid->op_type != OP_RV2HV && kid->op_type != OP_PADHV) {
+ SV * const kidsv =
+ kid->op_type == OP_CONST ? ((SVOP*)kid)->op_sv : NULL;
+ OP * const newsubop =
+ kidsv && !isGV(kidsv) && !SvROK(kidsv)
+ ? newGVOP(
+ OP_GV, 0, gv_fetchsv(kidsv, GV_ADD, SVt_PVHV)
+ )
+ : kid;
+ OP * const newop = newHVREF(newsubop);
+
+ if (kid->op_type == OP_CONST &&
+ (kid->op_private & OPpCONST_BARE))
+ Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
"Hash %%%"SVf" missing the %% in argument %"IVdf" of %s()",
SVfARG(((SVOP*)kid)->op_sv), (IV)numargs, PL_op_desc[type]);
+
+ if (newsubop == kid)
+ assert(!kid->op_sibling);
+ else
#ifdef PERL_MAD
- op_getmad(kid,newop,'K');
+ op_getmad(kid,newop,'K');
#else
- op_free(kid);
+ op_free(kid);
#endif
kid = newop;
kid->op_sibling = sibl;
*tokid = kid;
}
- else if (kid->op_type != OP_RV2HV && kid->op_type != OP_PADHV)
- bad_type(numargs, "hash", PL_op_desc[type], kid);
op_lvalue(kid, type);
break;
case OA_CVREF:
@@ -8256,7 +8270,7 @@ Perl_ck_shift(pTHX_ OP *o)
return newUNOP(type, 0, scalar(argop));
#endif
}
- return scalar(modkids(ck_push(o), type));
+ return scalar(modkids(ck_fun(o), type));
}
OP *
@@ -9122,48 +9136,6 @@ Perl_ck_substr(pTHX_ OP *o)
}
OP *
-Perl_ck_push(pTHX_ OP *o)
-{
- dVAR;
- OP *kid = o->op_flags & OPf_KIDS ? cLISTOPo->op_first : NULL;
- OP *cursor = NULL;
- OP *proxy = NULL;
-
- PERL_ARGS_ASSERT_CK_PUSH;
-
- /* If 1st kid is pushmark (e.g. push, unshift, splice), we need 2nd kid */
- if (kid) {
- cursor = kid->op_type == OP_PUSHMARK ? kid->op_sibling : kid;
- }
-
- /* If not array or array deref, wrap it with an array deref.
- * For OP_CONST, we only wrap arrayrefs */
- if (cursor) {
- if ( ( cursor->op_type != OP_PADAV
- && cursor->op_type != OP_RV2AV
- && cursor->op_type != OP_CONST
- )
- ||
- ( cursor->op_type == OP_CONST
- && SvROK(cSVOPx_sv(cursor))
- && SvTYPE(SvRV(cSVOPx_sv(cursor))) == SVt_PVAV
- )
- ) {
- proxy = newAVREF(cursor);
- if ( cursor == kid ) {
- cLISTOPx(o)->op_first = proxy;
- }
- else {
- cLISTOPx(kid)->op_sibling = proxy;
- }
- cLISTOPx(proxy)->op_sibling = cLISTOPx(cursor)->op_sibling;
- cLISTOPx(cursor)->op_sibling = NULL;
- }
- }
- return ck_fun(o);
-}
-
-OP *
Perl_ck_each(pTHX_ OP *o)
{
dVAR;
@@ -9171,30 +9143,16 @@ Perl_ck_each(pTHX_ OP *o)
const unsigned orig_type = o->op_type;
const unsigned array_type = orig_type == OP_EACH ? OP_AEACH
: orig_type == OP_KEYS ? OP_AKEYS : OP_AVALUES;
- const unsigned ref_type = orig_type == OP_EACH ? OP_REACH
- : orig_type == OP_KEYS ? OP_RKEYS : OP_RVALUES;
PERL_ARGS_ASSERT_CK_EACH;
if (kid) {
- switch (kid->op_type) {
- case OP_PADHV:
- case OP_RV2HV:
- break;
- case OP_PADAV:
- case OP_RV2AV:
- CHANGE_TYPE(o, array_type);
- break;
- case OP_CONST:
- if (kid->op_private == OPpCONST_BARE)
- /* we let ck_fun treat as hash */
- break;
- default:
- CHANGE_TYPE(o, ref_type);
+ if (kid->op_type == OP_PADAV || kid->op_type == OP_RV2AV) {
+ o->op_type = (OPCODE)array_type;
+ o->op_ppaddr = PL_ppaddr[array_type];
}
}
- /* if treating as a reference, defer additional checks to runtime */
- return o->op_type == ref_type ? o : ck_fun(o);
+ return ck_fun(o);
}
/* caller is supposed to assign the return to the
diff --git a/opcode.h b/opcode.h
index 122c67f..71f46c5 100644
--- a/opcode.h
+++ b/opcode.h
@@ -394,9 +394,6 @@ EXTCONST char* const PL_op_name[] = {
"lock",
"once",
"custom",
- "reach",
- "rkeys",
- "rvalues",
"transr",
};
#endif
@@ -771,9 +768,6 @@ EXTCONST char* const PL_op_desc[] = {
"lock",
"once",
"unknown custom operator",
- "each on reference",
- "keys on reference",
- "values on reference",
"transliteration (tr///)",
};
#endif
@@ -1162,9 +1156,6 @@ EXT Perl_ppaddr_t PL_ppaddr[] /* or perlvars.h */
Perl_pp_lock,
Perl_pp_once,
Perl_unimplemented_op, /* Perl_pp_custom */
- Perl_pp_rkeys, /* Perl_pp_reach */
- Perl_pp_rkeys,
- Perl_pp_rkeys, /* Perl_pp_rvalues */
Perl_pp_trans, /* Perl_pp_transr */
}
#endif
@@ -1334,11 +1325,11 @@ EXT Perl_check_t PL_check[] /* or perlvars.h */
Perl_ck_null, /* lslice */
Perl_ck_fun, /* anonlist */
Perl_ck_fun, /* anonhash */
- Perl_ck_push, /* splice */
- Perl_ck_push, /* push */
+ Perl_ck_fun, /* splice */
+ Perl_ck_fun, /* push */
Perl_ck_shift, /* pop */
Perl_ck_shift, /* shift */
- Perl_ck_push, /* unshift */
+ Perl_ck_fun, /* unshift */
Perl_ck_sort, /* sort */
Perl_ck_fun, /* reverse */
Perl_ck_grep, /* grepstart */
@@ -1550,9 +1541,6 @@ EXT Perl_check_t PL_check[] /* or perlvars.h */
Perl_ck_rfun, /* lock */
Perl_ck_null, /* once */
Perl_ck_null, /* custom */
- Perl_ck_each, /* reach */
- Perl_ck_each, /* rkeys */
- Perl_ck_each, /* rvalues */
Perl_ck_match, /* transr */
}
#endif
@@ -1932,9 +1920,6 @@ EXTCONST U32 PL_opargs[] = {
0x00007b04, /* lock */
0x00000300, /* once */
0x00000000, /* custom */
- 0x00001b00, /* reach */
- 0x00001b08, /* rkeys */
- 0x00001b08, /* rvalues */
0x00001804, /* transr */
};
#endif
diff --git a/opnames.h b/opnames.h
index 609c6e2..86781a3 100644
--- a/opnames.h
+++ b/opnames.h
@@ -381,14 +381,11 @@ typedef enum opcode {
OP_LOCK = 363,
OP_ONCE = 364,
OP_CUSTOM = 365,
- OP_REACH = 366,
- OP_RKEYS = 367,
- OP_RVALUES = 368,
- OP_TRANSR = 369,
+ OP_TRANSR = 366,
OP_max
} opcode;
-#define MAXO 370
+#define MAXO 367
#define OP_phoney_INPUT_ONLY -1
#define OP_phoney_OUTPUT_ONLY -2
diff --git a/pod/perldiag.pod b/pod/perldiag.pod
index 7250057..71fd181 100644
--- a/pod/perldiag.pod
+++ b/pod/perldiag.pod
@@ -76,17 +76,6 @@ on the operator (e.g. C<CORE::log($x)>) or declare the subroutine
to be an object method (see L<perlsub/"Subroutine Attributes"> or
L<attributes>).
-=item Ambiguous overloaded argument to %s resolved as %s
-
-(W ambiguous) You called C<keys>, C<values> or C<each> on an object that had
-overloading of C<%{}> or C<@{}> or both. In such a case, the object is
-dereferenced according to its overloading, not its underlying reference type.
-The warning is issued when C<%{}> overloading exists on a blessed arrayref,
-when C<@{}> overloading exists on a blessed hashref, or when both overloadings
-are defined (in which case C<%{}> is used). You can force the interpretation
-of the object by explictly dereferencing it as an array or hash instead of
-passing the object itself to C<keys>, C<values> or C<each>.
-
=item Ambiguous range in transliteration operator
(F) You wrote something like C<tr/a-z-0//> which doesn't mean anything at
diff --git a/pod/perlfunc.pod b/pod/perlfunc.pod
index 6a498bc..095c6aa 100644
--- a/pod/perlfunc.pod
+++ b/pod/perlfunc.pod
@@ -1455,7 +1455,7 @@ typo.
=item each HASH (or HASHREF)
X<each> X<hash, iterator>
-=item each ARRAY (or ARRAYREF)
+=item each ARRAY
X<array, iterator>
When called in list context, returns a 2-element list consisting of the key
@@ -1494,16 +1494,11 @@ but in a different order:
print "$key=$value\n";
}
-When given a reference to a hash or array, the argument will be
+When given a reference to a hash, the argument will be
dereferenced automatically.
while (($key,$value) = each $hashref) { ... }
-If the reference is a blessed object that overrides either C<%{}> or
-C<@{}>, the override will be used instead of dereferencing the underlying
-variable type. If both overrides are provided, C<%{}> will be the default.
-If this is not desired, you must dereference the argument yourself.
-
See also C<keys>, C<values> and C<sort>.
=item eof FILEHANDLE
@@ -2615,7 +2610,7 @@ first argument. Compare L</split>.
=item keys HASH (or HASHREF)
X<keys> X<key>
-=item keys ARRAY (or ARRAYREF)
+=item keys ARRAY
Returns a list consisting of all the keys of the named hash, or the indices
of an array. (In scalar context, returns the number of keys or indices.)
@@ -2672,16 +2667,11 @@ C<keys> in this way (but you needn't worry about doing this by accident,
as trying has no effect). C<keys @array> in an lvalue context is a syntax
error.
-When given a reference to a hash or array, the argument will be
+When given a reference to a hash, the argument will be
dereferenced automatically.
for (keys $hashref) { ... }
- for (keys $obj->get_arrayref) { ... }
-
-If the reference is a blessed object that overrides either C<%{}> or
-C<@{}>, the override will be used instead of dereferencing the underlying
-variable type. If both overrides are provided, C<%{}> will be the default.
-If this is not desired, you must dereference the argument yourself.
+ for (keys $obj->get_fields) { ... }
See also C<each>, C<values> and C<sort>.
@@ -7385,7 +7375,7 @@ recognized; barewords are considered filenames.
=item values HASH (or HASHREF)
X<values>
-=item values ARRAY (or ARRAYREF)
+=item values ARRAY
Returns a list consisting of all the values of the named hash, or the values
of an array. (In a scalar context, returns the number of values.)
@@ -7413,16 +7403,11 @@ modify the contents of the hash:
for (values %hash) { s/foo/bar/g } # modifies %hash values
for (@hash{keys %hash}) { s/foo/bar/g } # same
-When given a reference to a hash or array, the argument will be
+When given a reference to a hash, the argument will be
dereferenced automatically.
for (values $hashref) { ... }
- for (values $obj->get_arrayref) { ... }
-
-If the reference is a blessed object that overrides either C<%{}> or
-C<@{}>, the override will be used instead of dereferencing the underlying
-variable type. If both overrides are provided, C<%{}> will be the default.
-If this is not desired, you must dereference the argument yourself.
+ for (values $obj->get_fields) { ... }
See also C<keys>, C<each>, and C<sort>.
diff --git a/pp.c b/pp.c
index 47cf756..00cb9c0 100644
--- a/pp.c
+++ b/pp.c
@@ -4661,71 +4661,6 @@ PP(pp_aslice)
RETURN;
}
-/* Smart dereferencing for keys, values and each */
-PP(pp_rkeys)
-{
- dVAR;
- dSP;
- dPOPss;
-
- if (!SvOK(sv))
- RETURN;
-
- if (SvROK(sv)) {
- SvGETMAGIC(sv);
- if (SvAMAGIC(sv)) {
- /* N.B.: AMG macros return sv if no overloading is found */
- SV *maybe_hv = AMG_CALLun(sv,to_hv);
- SV *maybe_av = AMG_CALLun(sv,to_av);
- if ( maybe_hv != sv && maybe_av != sv ) {
- Perl_ck_warner(aTHX_ packWARN(WARN_AMBIGUOUS), "%s",
- Perl_form(aTHX_ "Ambiguous overloaded argument to %s resolved as %%{}",
- PL_op_desc[PL_op->op_type]
- )
- );
- sv = maybe_hv;
- }
- else if ( maybe_av != sv ) {
- if ( SvTYPE(SvRV(sv)) == SVt_PVHV ) {
- /* @{} overload, but underlying reftype is HV */
- Perl_ck_warner(aTHX_ packWARN(WARN_AMBIGUOUS), "%s",
- Perl_form(aTHX_ "Ambiguous overloaded argument to %s resolved as @{}",
- PL_op_desc[PL_op->op_type]
- )
- );
- }
- sv = maybe_av;
- }
- else if ( maybe_hv != sv ) {
- if ( SvTYPE(SvRV(sv)) == SVt_PVAV ) {
- /* %{} overload, but underlying reftype is AV */
- Perl_ck_warner(aTHX_ packWARN(WARN_AMBIGUOUS), "%s",
- Perl_form(aTHX_ "Ambiguous overloaded argument to %s resolved as %%{}",
- PL_op_desc[PL_op->op_type]
- )
- );
- }
- sv = maybe_hv;
- }
- }
- sv = SvRV(sv);
- }
-
- if ( SvTYPE(sv) != SVt_PVHV && SvTYPE(sv) != SVt_PVAV ) {
- DIE(aTHX_ "Type of argument to %s must be hashref or arrayref",
- PL_op_desc[PL_op->op_type] );
- }
-
- /* Delegate to correct function for op type */
- PUSHs(sv);
- if (PL_op->op_type == OP_RKEYS || PL_op->op_type == OP_RVALUES) {
- return (SvTYPE(sv) == SVt_PVHV) ? Perl_do_kv(aTHX) : Perl_pp_akeys(aTHX);
- }
- else {
- return (SvTYPE(sv) == SVt_PVHV) ? Perl_pp_each(aTHX) : Perl_pp_aeach(aTHX);
- }
-}
-
PP(pp_aeach)
{
dVAR;
@@ -4771,7 +4706,7 @@ PP(pp_akeys)
EXTEND(SP, n + 1);
- if (PL_op->op_type == OP_AKEYS || PL_op->op_type == OP_RKEYS) {
+ if (PL_op->op_type == OP_AKEYS) {
n += i;
for (; i <= n; i++) {
mPUSHi(i);
diff --git a/pp.sym b/pp.sym
index 11e8f78..594a752 100644
--- a/pp.sym
+++ b/pp.sym
@@ -30,7 +30,6 @@ Perl_ck_match
Perl_ck_method
Perl_ck_null
Perl_ck_open
-Perl_ck_push
Perl_ck_readline
Perl_ck_repeat
Perl_ck_require
@@ -410,9 +409,6 @@ Perl_pp_getlogin
Perl_pp_syscall
Perl_pp_lock
Perl_pp_once
-Perl_pp_reach
-Perl_pp_rkeys
-Perl_pp_rvalues
Perl_pp_transr
# ex: set ro:
diff --git a/proto.h b/proto.h
index a05f2b9..091bf50 100644
--- a/proto.h
+++ b/proto.h
@@ -424,12 +424,6 @@ PERL_CALLCONV OP * Perl_ck_open(pTHX_ OP *o)
#define PERL_ARGS_ASSERT_CK_OPEN \
assert(o)
-PERL_CALLCONV OP * Perl_ck_push(pTHX_ OP *o)
- __attribute__warn_unused_result__
- __attribute__nonnull__(pTHX_1);
-#define PERL_ARGS_ASSERT_CK_PUSH \
- assert(o)
-
PERL_CALLCONV OP * Perl_ck_readline(pTHX_ OP *o)
__attribute__warn_unused_result__
__attribute__nonnull__(pTHX_1);
@@ -3117,7 +3111,6 @@ PERL_CALLCONV OP * Perl_pp_quotemeta(pTHX);
PERL_CALLCONV OP * Perl_pp_rand(pTHX);
PERL_CALLCONV OP * Perl_pp_range(pTHX);
PERL_CALLCONV OP * Perl_pp_rcatline(pTHX);
-PERL_CALLCONV OP * Perl_pp_reach(pTHX);
PERL_CALLCONV OP * Perl_pp_read(pTHX);
PERL_CALLCONV OP * Perl_pp_readdir(pTHX);
PERL_CALLCONV OP * Perl_pp_readline(pTHX);
@@ -3138,14 +3131,12 @@ PERL_CALLCONV OP * Perl_pp_reverse(pTHX);
PERL_CALLCONV OP * Perl_pp_rewinddir(pTHX);
PERL_CALLCONV OP * Perl_pp_right_shift(pTHX);
PERL_CALLCONV OP * Perl_pp_rindex(pTHX);
-PERL_CALLCONV OP * Perl_pp_rkeys(pTHX);
PERL_CALLCONV OP * Perl_pp_rmdir(pTHX);
PERL_CALLCONV OP * Perl_pp_rv2av(pTHX);
PERL_CALLCONV OP * Perl_pp_rv2cv(pTHX);
PERL_CALLCONV OP * Perl_pp_rv2gv(pTHX);
PERL_CALLCONV OP * Perl_pp_rv2hv(pTHX);
PERL_CALLCONV OP * Perl_pp_rv2sv(pTHX);
-PERL_CALLCONV OP * Perl_pp_rvalues(pTHX);
PERL_CALLCONV OP * Perl_pp_sassign(pTHX);
PERL_CALLCONV OP * Perl_pp_say(pTHX);
PERL_CALLCONV OP * Perl_pp_scalar(pTHX);
diff --git a/regen/opcode.pl b/regen/opcode.pl
index bd3d55a..834934e 100755
--- a/regen/opcode.pl
+++ b/regen/opcode.pl
@@ -106,7 +106,6 @@ my @raw_alias = (
Perl_pp_bit_or => ['bit_xor'],
Perl_pp_rv2av => ['rv2hv'],
Perl_pp_akeys => ['avalues'],
- Perl_pp_rkeys => [qw(rvalues reach)],
Perl_pp_trans => [qw(trans transr)],
);
@@ -807,11 +806,11 @@ lslice list slice ck_null 2 H L L
anonlist anonymous list ([]) ck_fun ms@ L
anonhash anonymous hash ({}) ck_fun ms@ L
-splice splice ck_push m@ A S? S? L
-push push ck_push imsT@ A L
+splice splice ck_fun m@ A S? S? L
+push push ck_fun imsT@ A L
pop pop ck_shift s% A?
shift shift ck_shift s% A?
-unshift unshift ck_push imsT@ A L
+unshift unshift ck_fun imsT@ A L
sort sort ck_sort dm@ C? L
reverse reverse ck_fun mt@ L
@@ -1099,10 +1098,5 @@ once once ck_null |
custom unknown custom operator ck_null 0
-# For smart dereference for each/keys/values
-reach each on reference ck_each % S
-rkeys keys on reference ck_each t% S
-rvalues values on reference ck_each t% S
-
# y///r
transr transliteration (tr///) ck_match is" S
diff --git a/t/op/push.t b/t/op/push.t
index 2804d5b..61666ee 100644
--- a/t/op/push.t
+++ b/t/op/push.t
@@ -14,7 +14,7 @@
-4, 4 5 6 7, 0 1 2 3
EOF
-print "1..", 13 + 2*@tests, "\n";
+print "1..", 14 + 2*@tests, "\n";
die "blech" unless @tests;
@x = (1,2,3);
@@ -52,15 +52,19 @@ use constant CONST_ARRAYREF => [qw/a b c/];
push CONST_ARRAYREF(), qw/d e f/;
if (join(':',@{CONST_ARRAYREF()}) eq 'a:b:c:d:e:f') {print "ok 9\n";} else {print "not ok 9\n";}
-# test implicit dereference errors
+# test implicit symbolic dereference
eval "push 42, 0, 1, 2, 3";
-if ( $@ && $@ =~ /must be array/ ) {print "ok 10\n"} else {print "not ok 10 # \$\@ = $@\n"}
+if (join(":", @42) eq "0:1:2:3") {print "ok 10\n"}
+else {print "not ok 10\n"}
+eval "use strict; push 'foo', 0, 1, 2, 3";
+if ( $@ && $@ =~ /requires explicit package/ ) {print "ok 11\n"}
+else {print "not ok 11 # \$\@ = $@\n"}
$hashref = { };
eval { push $hashref, 0, 1, 2, 3 };
-if ( $@ && $@ =~ /Not an ARRAY reference/ ) {print "ok 11\n"} else {print "not ok 11 # \$\@ = $@\n"}
+if ( $@ && $@ =~ /Not an ARRAY reference/ ) {print "ok 12\n"} else {print "not ok 12 # \$\@ = $@\n"}
-$test = 12;
+$test = 13;
# test context
{
diff --git a/t/op/smartkve.t b/t/op/smartkve.t
index 4cb19f5..9f6e70d 100644
--- a/t/op/smartkve.t
+++ b/t/op/smartkve.t
@@ -79,13 +79,13 @@ keys CONST_HASH(); pass('Void: keys CONST_HASH();');
keys hash_sub(); pass('Void: keys hash_sub();');
keys hash_sub; pass('Void: keys hash_sub;');
keys $obj->hash; pass('Void: keys $obj->hash;');
-keys $array; pass('Void: keys $array;');
-keys $data->{array}; pass('Void: keys $data->{array};');
-keys CONST_ARRAY; pass('Void: keys CONST_ARRAY;');
-keys CONST_ARRAY(); pass('Void: keys CONST_ARRAY();');
-keys array_sub; pass('Void: keys array_sub;');
-keys array_sub(); pass('Void: keys array_sub();');
-keys $obj->array; pass('Void: keys $obj->array;');
+ok(!eval 'keys $array ;1', 'Void: keys $array;');
+ok(!eval 'keys $data->{array};1', 'Void: keys $data->{array};');
+ok(!eval 'keys CONST_ARRAY ;1', 'Void: keys CONST_ARRAY;');
+ok(!eval 'keys CONST_ARRAY() ;1', 'Void: keys CONST_ARRAY();');
+ok(!eval 'keys array_sub ;1', 'Void: keys array_sub;');
+ok(!eval 'keys array_sub() ;1', 'Void: keys array_sub();');
+ok(!eval 'keys $obj->array ;1', 'Void: keys $obj->array;');
# Keys -- scalar
@@ -96,13 +96,13 @@ is(keys CONST_HASH() ,3, 'Scalar: keys CONST_HASH()');
is(keys hash_sub ,3, 'Scalar: keys hash_sub');
is(keys hash_sub() ,3, 'Scalar: keys hash_sub()');
is(keys $obj->hash ,3, 'Scalar: keys $obj->hash');
-is(keys $array ,3, 'Scalar: keys $array');
-is(keys $data->{array} ,3, 'Scalar: keys $data->{array}');
-is(keys CONST_ARRAY ,3, 'Scalar: keys CONST_ARRAY');
-is(keys CONST_ARRAY() ,3, 'Scalar: keys CONST_ARRAY()');
-is(keys array_sub ,3, 'Scalar: keys array_sub');
-is(keys array_sub() ,3, 'Scalar: keys array_sub()');
-is(keys $obj->array ,3, 'Scalar: keys $obj->array');
+is(eval 'keys $array' ,undef, 'Scalar: keys $array');
+is(eval 'keys $data->{array}',undef, 'Scalar: keys $data->{array}');
+is(eval 'keys CONST_ARRAY' ,undef, 'Scalar: keys CONST_ARRAY');
+is(eval 'keys CONST_ARRAY()' ,undef, 'Scalar: keys CONST_ARRAY()');
+is(eval 'keys array_sub' ,undef, 'Scalar: keys array_sub');
+is(eval 'keys array_sub()' ,undef, 'Scalar: keys array_sub()');
+is(eval 'keys $obj->array' ,undef, 'Scalar: keys $obj->array');
# Keys -- list
@@ -116,34 +116,34 @@ is(j(keys CONST_HASH()) ,$h_expect, 'List: keys CONST_HASH()');
is(j(keys hash_sub) ,$h_expect, 'List: keys hash_sub');
is(j(keys hash_sub()) ,$h_expect, 'List: keys hash_sub()');
is(j(keys $obj->hash) ,$h_expect, 'List: keys $obj->hash');
-is(j(keys $array) ,$a_expect, 'List: keys $array');
-is(j(keys $data->{array}) ,$a_expect, 'List: keys $data->{array}');
-is(j(keys CONST_ARRAY) ,$a_expect, 'List: keys CONST_ARRAY');
-is(j(keys CONST_ARRAY()) ,$a_expect, 'List: keys CONST_ARRAY()');
-is(j(keys array_sub) ,$a_expect, 'List: keys array_sub');
-is(j(keys array_sub()) ,$a_expect, 'List: keys array_sub()');
-is(j(keys $obj->array) ,$a_expect, 'List: keys $obj->array');
+is(eval 'j(keys $array)' , undef , 'List: keys $array');
+is(eval 'j(keys $data->{array})', undef , 'List: keys $data->{array}');
+is(eval 'j(keys CONST_ARRAY)' , undef , 'List: keys CONST_ARRAY');
+is(eval 'j(keys CONST_ARRAY())' , undef , 'List: keys CONST_ARRAY()');
+is(eval 'j(keys array_sub)' , undef , 'List: keys array_sub');
+is(eval 'j(keys array_sub())' , undef , 'List: keys array_sub()');
+is(eval 'j(keys $obj->array)' , undef , 'List: keys $obj->array');
# Keys -- undef
undef $empty;
-is(j(keys undef), '', 'Undef: keys undef is empty list');
+is(eval 'j(keys undef)', undef, 'Undef: keys undef is error');
is(j(keys $empty), '', 'Undef: keys $empty is empty list');
-is($empty, undef, 'Undef: $empty is not vivified');
+is(ref $empty, 'HASH', 'Undef: $empty is vivified');
# Keys -- vivification
is(j(keys $empty->{hash}), '', 'Vivify: keys $empty->{hash}');
ok(defined $empty , 'Vivify: $empty is HASHREF');
-ok(!defined $empty->{hash} , 'Vivify: $empty->{hash} is undef');
+is(ref $empty->{hash}, 'HASH','Vivify: $empty->{hash} is undef');
# Keys -- errors
-eval "keys 3";
-ok($@ =~ qr/Type of argument to keys on reference must be hashref or arrayref/,
- 'Errors: keys CONSTANT throws error'
+eval "keys 'foo'";
+ok($@ =~ qr/requires explicit package/,
+ 'Errors: keys "foo" throws error'
);
eval "keys qr/foo/";
-ok($@ =~ qr/Type of argument to keys on reference must be hashref or arrayref/,
+ok($@ =~ qr/Not a HASH reference/,
'Errors: keys qr/foo/ throws error'
);
@@ -161,13 +161,13 @@ values CONST_HASH(); pass('Void: values CONST_HASH();');
values hash_sub(); pass('Void: values hash_sub();');
values hash_sub; pass('Void: values hash_sub;');
values $obj->hash; pass('Void: values $obj->hash;');
-values $array; pass('Void: values $array;');
-values $data->{array}; pass('Void: values $data->{array};');
-values CONST_ARRAY; pass('Void: values CONST_ARRAY;');
-values CONST_ARRAY(); pass('Void: values CONST_ARRAY();');
-values array_sub; pass('Void: values array_sub;');
-values array_sub(); pass('Void: values array_sub();');
-values $obj->array; pass('Void: values $obj->array;');
+ok(!eval 'values $array; 1', 'Void: values $array;');
+ok(!eval 'values $data->{array}; 1', 'Void: values $data->{array};');
+ok(!eval 'values CONST_ARRAY; 1', 'Void: values CONST_ARRAY;');
+ok(!eval 'values CONST_ARRAY(); 1', 'Void: values CONST_ARRAY();');
+ok(!eval 'values array_sub; 1', 'Void: values array_sub;');
+ok(!eval 'values array_sub(); 1', 'Void: values array_sub();');
+ok(!eval 'values $obj->array; 1', 'Void: values $obj->array;');
# Values -- scalar
@@ -178,13 +178,13 @@ is(values CONST_HASH() ,3, 'Scalar: values CONST_HASH()');
is(values hash_sub ,3, 'Scalar: values hash_sub');
is(values hash_sub() ,3, 'Scalar: values hash_sub()');
is(values $obj->hash ,3, 'Scalar: values $obj->hash');
-is(values $array ,3, 'Scalar: values $array');
-is(values $data->{array} ,3, 'Scalar: values $data->{array}');
-is(values CONST_ARRAY ,3, 'Scalar: values CONST_ARRAY');
-is(values CONST_ARRAY() ,3, 'Scalar: values CONST_ARRAY()');
-is(values array_sub ,3, 'Scalar: values array_sub');
-is(values array_sub() ,3, 'Scalar: values array_sub()');
-is(values $obj->array ,3, 'Scalar: values $obj->array');
+is(eval 'values $array' ,undef, 'Scalar: values $array');
+is(eval 'values $data->{array}',undef, 'Scalar: values $data->{array}');
+is(eval 'values CONST_ARRAY' ,undef, 'Scalar: values CONST_ARRAY');
+is(eval 'values CONST_ARRAY()' ,undef, 'Scalar: values CONST_ARRAY()');
+is(eval 'values array_sub' ,undef, 'Scalar: values array_sub');
+is(eval 'values array_sub()' ,undef, 'Scalar: values array_sub()');
+is(eval 'values $obj->array' ,undef, 'Scalar: values $obj->array');
# Values -- list
@@ -198,34 +198,34 @@ is(j(values CONST_HASH()) ,$h_expect, 'List: values CONST_HASH()');
is(j(values hash_sub) ,$h_expect, 'List: values hash_sub');
is(j(values hash_sub()) ,$h_expect, 'List: values hash_sub()');
is(j(values $obj->hash) ,$h_expect, 'List: values $obj->hash');
-is(j(values $array) ,$a_expect, 'List: values $array');
-is(j(values $data->{array}) ,$a_expect, 'List: values $data->{array}');
-is(j(values CONST_ARRAY) ,$a_expect, 'List: values CONST_ARRAY');
-is(j(values CONST_ARRAY()) ,$a_expect, 'List: values CONST_ARRAY()');
-is(j(values array_sub) ,$a_expect, 'List: values array_sub');
-is(j(values array_sub()) ,$a_expect, 'List: values array_sub()');
-is(j(values $obj->array) ,$a_expect, 'List: values $obj->array');
+is(eval 'j(values $array)' , undef , 'List: values $array');
+is(eval 'j(values $data->{array})', undef , 'List: values $data->{array}');
+is(eval 'j(values CONST_ARRAY)' , undef , 'List: values CONST_ARRAY');
+is(eval 'j(values CONST_ARRAY())' , undef , 'List: values CONST_ARRAY()');
+is(eval 'j(values array_sub)' , undef , 'List: values array_sub');
+is(eval 'j(values array_sub())' , undef , 'List: values array_sub()');
+is(eval 'j(values $obj->array)' , undef , 'List: values $obj->array');
# Values -- undef
undef $empty;
-is(j(values undef), '', 'Undef: values undef is empty list');
+is(eval 'j(values undef)', undef, 'Undef: values undef is an error');
is(j(values $empty), '', 'Undef: values $empty is empty list');
-is($empty, undef, 'Undef: $empty is not vivified');
+is(ref $empty, 'HASH', 'Undef: $empty is vivified');
# Values -- vivification
is(j(values $empty->{hash}), '', 'Vivify: values $empty->{hash}');
ok(defined $empty , 'Vivify: $empty is HASHREF');
-ok(!defined $empty->{hash} , 'Vivify: $empty->{hash} is undef');
+ok(defined $empty->{hash} , 'Vivify: $empty->{hash} is not undef');
# Values -- errors
-eval "values 3";
-ok($@ =~ qr/Type of argument to values on reference must be hashref or arrayref/,
- 'Errors: values CONSTANT throws error'
+eval "values 'fee'";
+ok($@ =~ qr/requires explicit package/,
+ 'Errors: values "foo" throws error'
);
eval "values qr/foo/";
-ok($@ =~ qr/Type of argument to values on reference must be hashref or arrayref/,
+ok($@ =~ qr/Not a HASH reference/,
'Errors: values qr/foo/ throws error'
);
@@ -243,13 +243,13 @@ each CONST_HASH(); pass('Void: each CONST_HASH()');
each hash_sub(); pass('Void: each hash_sub()');
each hash_sub; pass('Void: each hash_sub');
each $obj->hash; pass('Void: each $obj->hash');
-each $array; pass('Void: each $array');
-each $data->{array}; pass('Void: each $data->{array}');
-each CONST_ARRAY; pass('Void: each CONST_ARRAY');
-each CONST_ARRAY(); pass('Void: each CONST_ARRAY()');
-each array_sub; pass('Void: each array_sub');
-each array_sub(); pass('Void: each array_sub()');
-each $obj->array; pass('Void: each $obj->array');
+ok(!eval 'each $array; 1', 'Void: each $array');
+ok(!eval 'each $data->{array}; 1', 'Void: each $data->{array}');
+ok(!eval 'each CONST_ARRAY; 1', 'Void: each CONST_ARRAY;');
+ok(!eval 'each CONST_ARRAY(); 1', 'Void: each CONST_ARRAY();');
+ok(!eval 'each array_sub; 1', 'Void: each array_sub');
+ok(!eval 'each array_sub(); 1', 'Void: each array_sub()');
+ok(!eval 'each $obj->array; 1', 'Void: each $obj->array');
# Reset iterators
@@ -260,13 +260,6 @@ keys CONST_HASH();
keys hash_sub();
keys hash_sub;
keys $obj->hash;
-keys $array;
-keys $data->{array};
-keys CONST_ARRAY;
-keys CONST_ARRAY();
-keys array_sub;
-keys array_sub();
-keys $obj->array;
# Each -- scalar
@@ -277,13 +270,13 @@ keys $obj->array;
@tmp=(); while(defined( $k = each hash_sub())){push @tmp,$k}; is(j(@tmp),j(keys hash_sub()), 'Scalar: each hash_sub()');
@tmp=(); while(defined( $k = each hash_sub)){push @tmp,$k}; is(j(@tmp),j(keys hash_sub), 'Scalar: each hash_sub');
@tmp=(); while(defined( $k = each $obj->hash)){push @tmp,$k}; is(j(@tmp),j(keys $obj->hash), 'Scalar: each $obj->hash');
-@tmp=(); while(defined( $k = each $array)){push @tmp,$k}; is(j(@tmp),j(keys $array), 'Scalar: each $array');
-@tmp=(); while(defined( $k = each $data->{array})){push @tmp,$k}; is(j(@tmp),j(keys $data->{array}), 'Scalar: each $data->{array}');
-@tmp=(); while(defined( $k = each CONST_ARRAY)){push @tmp,$k}; is(j(@tmp),j(keys CONST_ARRAY), 'Scalar: each CONST_ARRAY');
-@tmp=(); while(defined( $k = each CONST_ARRAY())){push @tmp,$k}; is(j(@tmp),j(keys CONST_ARRAY()), 'Scalar: each CONST_ARRAY()');
-@tmp=(); while(defined( $k = each array_sub)){push @tmp,$k}; is(j(@tmp),j(keys array_sub), 'Scalar: each array_sub');
-@tmp=(); while(defined( $k = each array_sub())){push @tmp,$k}; is(j(@tmp),j(keys array_sub()), 'Scalar: each array_sub()');
-@tmp=(); while(defined( $k = each $obj->array)){push @tmp,$k}; is(j(@tmp),j(keys $obj->array), 'Scalar: each $obj->array');
+is(eval 'each $array' ,undef, 'Scalar: each $array');
+is(eval 'each $data->{array}',undef, 'Scalar: each $data->{array}');
+is(eval 'each CONST_ARRAY' ,undef, 'Scalar: each CONST_ARRAY');
+is(eval 'each CONST_ARRAY()' ,undef, 'Scalar: each CONST_ARRAY()');
+is(eval 'each array_sub' ,undef, 'Scalar: each array_sub');
+is(eval 'each array_sub()' ,undef, 'Scalar: each array_sub()');
+is(eval 'each $obj->array' ,undef, 'Scalar: each $obj->array');
# Each -- list
@@ -294,34 +287,34 @@ keys $obj->array;
@tmp=@tmp2=(); while(($k,$v) = each hash_sub()){push @tmp,$k; push @tmp2,$v}; is(j(@tmp,@tmp2),j(keys hash_sub(), values hash_sub()), 'List: each hash_sub()');
@tmp=@tmp2=(); while(($k,$v) = each hash_sub){push @tmp,$k; push @tmp2,$v}; is(j(@tmp,@tmp2),j(keys hash_sub, values hash_sub), 'List: each hash_sub');
@tmp=@tmp2=(); while(($k,$v) = each $obj->hash){push @tmp,$k; push @tmp2,$v}; is(j(@tmp,@tmp2),j(keys $obj->hash, values $obj->hash), 'List: each $obj->hash');
-@tmp=@tmp2=(); while(($k,$v) = each $array){push @tmp,$k; push @tmp2,$v}; is(j(@tmp,@tmp2),j(keys $array, values $array), 'List: each $array');
-@tmp=@tmp2=(); while(($k,$v) = each $data->{array}){push @tmp,$k; push @tmp2,$v}; is(j(@tmp,@tmp2),j(keys $data->{array}, values $data->{array}), 'List: each $data->{array}');
-@tmp=@tmp2=(); while(($k,$v) = each CONST_ARRAY){push @tmp,$k; push @tmp2,$v}; is(j(@tmp,@tmp2),j(keys CONST_ARRAY, values CONST_ARRAY), 'List: each CONST_ARRAY');
-@tmp=@tmp2=(); while(($k,$v) = each CONST_ARRAY()){push @tmp,$k; push @tmp2,$v}; is(j(@tmp,@tmp2),j(keys CONST_ARRAY(), values CONST_ARRAY()), 'List: each CONST_ARRAY()');
-@tmp=@tmp2=(); while(($k,$v) = each array_sub){push @tmp,$k; push @tmp2,$v}; is(j(@tmp,@tmp2),j(keys array_sub, values array_sub), 'List: each array_sub');
-@tmp=@tmp2=(); while(($k,$v) = each array_sub()){push @tmp,$k; push @tmp2,$v}; is(j(@tmp,@tmp2),j(keys array_sub(), values array_sub()), 'List: each array_sub()');
-@tmp=@tmp2=(); while(($k,$v) = each $obj->array){push @tmp,$k; push @tmp2,$v}; is(j(@tmp,@tmp2),j(keys $obj->array, values $obj->array), 'List: each $obj->array');
+is(eval 'j(each $array)' , undef , 'List: each $array');
+is(eval 'j(each $data->{array})', undef , 'List: each $data->{array}');
+is(eval 'j(each CONST_ARRAY)' , undef , 'List: each CONST_ARRAY');
+is(eval 'j(each CONST_ARRAY())' , undef , 'List: each CONST_ARRAY()');
+is(eval 'j(each array_sub)' , undef , 'List: each array_sub');
+is(eval 'j(each array_sub())' , undef , 'List: each array_sub()');
+is(eval 'j(each $obj->array)' , undef , 'List: each $obj->array');
# Each -- undef
undef $empty;
-is(j(@{[each undef]}), '', 'Undef: each undef is empty list');
+is(eval 'each undef;1', undef, 'Undef: each undef is an error');
is(j(@{[each $empty]}), '', 'Undef: each $empty is empty list');
-is($empty, undef, 'Undef: $empty is not vivified');
+is(ref $empty, 'HASH','Undef: $empty is vivified');
# Values -- vivification
is(j(@{[each $empty->{hash}]}), '', 'Vivify: each $empty->{hash} is empty list');
ok(defined $empty , 'Vivify: $empty is HASHREF');
-ok(!defined $empty->{hash} , 'Vivify: $empty->{hash} is undef');
+ok(defined $empty->{hash} , 'Vivify: $empty->{hash} is hash ref');
# Values -- errors
-eval "each 3";
-ok($@ =~ qr/Type of argument to each on reference must be hashref or arrayref/,
- 'Errors: each CONSTANT throws error'
+eval "each 'foo'";
+ok($@ =~ qr/requires explicit package/,
+ 'Errors: each "foo" throws error'
);
eval "each qr/foo/";
-ok($@ =~ qr/Type of argument to each on reference must be hashref or arrayref/,
+ok($@ =~ qr/Not a HASH reference/,
'Errors: each qr/foo/ throws error'
);
@@ -337,25 +330,22 @@ my $over_b = Foo::Overload::Both->new;
my $over_h_a = Foo::Overload::HashOnArray->new;
my $over_a_h = Foo::Overload::ArrayOnHash->new;
-my $re_warn_array = qr/Ambiguous overloaded argument to keys on reference resolved as \@\{\}/;
-my $re_warn_hash = qr/Ambiguous overloaded argument to keys on reference resolved as \%\{\}/;
-
{
my $warn = '';
local $SIG{__WARN__} = sub { $warn = shift };
- is(j(keys $over_a), j(keys @$array), "Overload: array dereference");
+ is(eval 'keys $over_a;1', undef, "Overload: array dereference");
is($warn, '', "no warning issued"); $warn = '';
is(j(keys $over_h), j(keys %$hash), "Overload: hash dereference");
is($warn, '', "no warning issued"); $warn = '';
is(j(keys $over_b), j(keys %$hash), "Overload: ambiguous dereference (both) resolves to hash");
- like($warn, $re_warn_hash, "warning correct"); $warn = '';
+ is($warn, '', 'no warning issued for %/@{} object'); $warn = '';
is(j(keys $over_h_a), j(keys %$hash), "Overload: ambiguous dereference resolves to hash");
- like($warn, $re_warn_hash, "warning correct"); $warn = '';
+ is($warn, '', "no warning for array with %{}"); $warn = '';
- is(j(keys $over_a_h), j(keys @$array), "Overload: ambiguous dereference resolves to array");
- like($warn, $re_warn_array, "warning correct"); $warn = '';
+ is(j(keys $over_a_h), 'foo', 'Overload: ambiguous dereference does not resolve to @{}');
+ is($warn, '', 'no warning for hash with @{}'); $warn = '';
} |
From @xdg[from the tail end of the report]
That's a very disingenuous (not to mention sarcastic) way to submit a I understand that you don't like aspects of this feature. However, You cite a handful of edge cases. I'd be happy to collaborate with Regards, |
The RT System itself - Status changed from 'new' to 'open' |
From @cpansproutOn Dec 12, 2010, at 2:02 PM, David Golden via RT wrote:
I was afraid it might be taken that way. I apologise sincerely if I have hurt your feelings.
There were only four days between the submission of your patch and its application. I do not want to get dragged into an argument. So I’ve asked Jesse to decide which version we will have. |
From @demerphqOn 12 December 2010 21:21, Father Chrysostomos
On one hand I think a lot of your comments are important edge cases On the other hand, I dont buy the simple rules argument. I think I feel that it would be pity if we lost this stuff because of an edge Is there some "third way" where you can have your desired and I know you don't want to argue, and wanted Jesse to make a ruling, so How would you feel about writing a patch to add tests for all the Which would leave the only open question "what to do about cheers, -- |
From zefram@fysh.orgdemerphq wrote:
The least-crazy way to keep keys($ref) is for it to always mean -zefram |
From @xdgOn Mon, Dec 13, 2010 at 6:11 PM, Zefram <zefram@fysh.org> wrote:
In the case where $ref is an unblessed arrayref, I think it should -- David |
From zefram@fysh.orgDavid Golden wrote:
That's where the craziness starts. In keys(%$ref) I might have been -zefram |
From @AbigailOn Tue, Dec 14, 2010 at 08:44:08AM +0000, Zefram wrote:
So, you keep using 'keys(%$ref)', and the proposed behaviour of I find "but the old way dies, and code may rely on that" a pretty The savings of a single keystroke isn't something that I find really Abigail |
From @xdgOn Mon, Dec 13, 2010 at 5:43 PM, demerphq <demerphq@gmail.com> wrote:
[This is a moderately pedantic post -- those with limited time (Hi, I want to speak to the overloaded objects ambiguities concern and lay Here are several potential approaches: (0) Do not allow "keys $ref" at all. It would be a syntax error just (1) Allow "keys $ref", but always interpret it as "keys %{$ref}". (2) Allow "keys $ref", but only for unblessed references. Dereference (3) Allow "keys $ref", but only for unblessed references or objects (4) Allow "keys $ref", but only for unblessed references, objects All of the cases 1 - 4 above have no ambiguity in interpretation. The (5) Allow "keys $ref" for any reference or object, regardless of (5a) For ambiguity, dereference with %{} always (5b) For ambiguity, dereference according to the reftype for ARRAY and (5c) For ambiguity, dereference according to the reftype for ARRAY and (5d) For ambiguity, dereference based on overloading if there is only (5e) For ambiguity, dereference based on overloading if there is only For reference, the patch that is now in blead equates to (5e) above. To step back a bit, I see an interesting sharp line between (2) and Between (3) and (4) is a step that maximizes the feature whenever Moving from (4) to (5) is just a less harsh approach than (4), in that CONCLUSION There is a lot of code that just manipulates simple data structures Given the cases I describe above, I see four of them as preferred (2) Defend encapsulation: have "keys $ref" work only for unblessed (5a) Always guess hash: Have "keys $ref" work for blessed or unblessed (5c) Guess by reftype: Have "keys $ref" work for blessed or unblessed (5e) Guess by overload: Have "keys $ref" work for blessed or unblessed I chose (5e) for the original patch because it seemed the most liberal -- David |
From @rjbs* David Golden <xdaveg@gmail.com> [2010-12-15T09:24:22]
Thanks for this post.
I think this is the best way forward, of those in your conclusion. It didn't The problem case that FC mentioned still exists: You used to return an Although I am excited by "push $aref, @values" I think I am back where I spent Is has the significant failing of not yet having been implemented. I think I still find these much better in the long run: push Array $foo->bar, @items; ...and that if it means we spend another year having to wrap things in @{...}, -- |
From @ikegamiOn Wed, Dec 15, 2010 at 9:24 AM, David Golden <xdaveg@gmail.com> wrote:
Hi, I'm against adding more polymorphism based on the current representation of The effects are even predictable. How often to you think "keys $ref" will be - Eric Brine |
From @janduboisOn Wed, 15 Dec 2010, David Golden wrote:
I'm in favor of (1). It is a really simple rule: "keys/values/each work So it doesn't work with array references, but then, it never used to do Cheers, |
From @AbigailOn Wed, Dec 15, 2010 at 09:24:22AM -0500, David Golden wrote:
This would be my option. Because a) I think this will be what most Abigail |
From @tonycozOn Wed, Dec 15, 2010 at 09:24:22AM -0500, David Golden wrote:
This one. But my bias is against keys etc on arrays anyway. Tony |
From @cpansproutOn Mon Dec 13 14:43:36 2010, demerphq wrote:
I am willing to do that, but I’ve been very busy lately and it looks as |
From [Unknown Contact. See original ticket]On Mon Dec 13 14:43:36 2010, demerphq wrote:
I am willing to do that, but I’ve been very busy lately and it looks as |
From @iabynOn Wed, Dec 15, 2010 at 09:24:22AM -0500, David Golden wrote:
This thread has been silent for 3 months, and we're now one day away from There seem to be two issues: a) whether to always treat $r as a *hash* ref in 'keys $r' etc b) FC identified a number of edge cases, where the thing after keys etc Now, can you (DG) and/or us (p5p) fix (a) and/or (b) before the I think I'd reluctantly vote for removal. -- |
From @xdgOn Sat, Mar 19, 2011 at 6:57 PM, Dave Mitchell <davem@iabyn.com> wrote:
We're past the freeze for "user visible changes", which (IMO) would The DWIM behavior decision is ultimately Jesse's and a number of The edge case fixes were blocking on TODO tests for them. Father C -- David |
From ambrus@math.bme.huOn Tue, Dec 14, 2010 at 12:11 AM, Zefram <zefram@fysh.org> wrote:
Agreed. Please let this be the behaviour. No implicit dereferencing On Sun, Mar 20, 2011 at 1:44 AM, David Golden <xdaveg@gmail.com> wrote:
I'd be okay with that. Ambrus |
From @obraOn Sat 19.Mar'11 at 20:44:37 -0400, David Golden wrote:
I suppose that marking it as experimental does give us the wiggle room -j
|
From @cpansproutOn Mar 20, 2011, at 4:30 PM, Jesse via RT wrote:
I’m afraid I had forgotten about the edge cases. Now that I think about it though, we have a chicken-and-egg problem. There is no problem with push, splice, etc., as the edge cases are all currently errors and can be resolved later without backward compatibility concerns. The edges cases for keys, each and values, however, entirely depend upon your decision with regard to array refs and objects.
That would be possible, but wouldn’t it be strange to put it there? What would the same ‘feature’ feature do in 5.16? I think marking that aspect of those functions as experimental in the docs (and removing the ‘or ARRAYREF’ from the =item directives in perlfunc) would be acceptable.
|
From @cpansproutOn Mon Mar 21 20:40:19 2011, sprout wrote:
Attached is a first go at a test script. Edit the JC constant to choose BTW, I noticed that ck_push is duplicating some logic from ck_fun. That |
From @cpansprout#!/usr/bin/perl # For most of these tests, I���m actually trying to make the behaviour # I���m not entirely sure about the edge cases for keys for 5a-5e. # This script as-is should not be incorporated into the perl core, but # What the tests test for are based on Jesse���s Choice: BEGIN { die "Why are you even running this?"if!JC } use Test::More; # push with various non-ref scalars # push with globs # keys with various non-ref scalars # keys with globs # lvalue keys |
From [Unknown Contact. See original ticket]On Mon Mar 21 20:40:19 2011, sprout wrote:
Attached is a first go at a test script. Edit the JC constant to choose BTW, I noticed that ck_push is duplicating some logic from ck_fun. That |
From @iabynOn Mon, Mar 21, 2011 at 08:39:42PM -0700, Father Chrysostomos wrote:
I agree. 'use feature' is inappropriate here.
Agreed. I think the docs should make clear that any use apart from Note also that traditionally we don't change such behaviours during maint I'm happy to make the doc changes if Jesse gives the nod. -- |
From @cpansproutOn Mar 30, 2011, at 7:40 AM, Dave Mitchell wrote:
For push, shift, etc., the only controversial cases are currently errors. For keys, each and values, even unblessed array refs are still controversial. So I think the easiest approach for now is to mark keys/each/values with *any* scalar as being experimental and subject to change. Attached is a diff with my recommendation as to how the docs should be changed.
|
From @cpansproutInline Patchdiff --git a/pod/perldelta.pod b/pod/perldelta.pod
index 646d1bc..8624143 100644
--- a/pod/perldelta.pod
+++ b/pod/perldelta.pod
@@ -253,6 +253,10 @@ C<delete> on an entry of C<%+> or C<%->.
=head3 Array and hash container functions accept references
+B<Warning:> For C<keys>, C<each> and C<values> this feature is considered
+experimental, as the exact behaviour may change in a future version of
+Perl.
+
All built-in functions that operate directly on array or hash
containers now also accept hard references to arrays or hashes:
diff --git a/pod/perlfunc.pod b/pod/perlfunc.pod
index c2a68a5..9ce7bea 100644
--- a/pod/perlfunc.pod
+++ b/pod/perlfunc.pod
@@ -1467,10 +1467,10 @@ convert a core file into an executable. That's why you should now invoke
it as C<CORE::dump()>, if you don't want to be warned against a possible
typo.
-=item each HASH (or HASHREF)
+=item each HASH
X<each> X<hash, iterator>
-=item each ARRAY (or ARRAYREF)
+=item each ARRAY
X<array, iterator>
When called in list context, returns a 2-element list consisting of the key
@@ -1509,8 +1509,10 @@ but in a different order:
print "$key=$value\n";
}
-When given a reference to a hash or array, the argument will be
-dereferenced automatically.
+Starting with Perl 5.14, C<each> can take a reference to a hash or array.
+The argument will be dereferenced automatically. This aspect of C<each>
+is considered highly experimental. The exact behaviour may change in a
+future version of Perl.
while (($key,$value) = each $hashref) { ... }
@@ -2641,10 +2643,10 @@ separated by the value of EXPR, and returns that new string. Example:
Beware that unlike C<split>, C<join> doesn't take a pattern as its
first argument. Compare L</split>.
-=item keys HASH (or HASHREF)
+=item keys HASH
X<keys> X<key>
-=item keys ARRAY (or ARRAYREF)
+=item keys ARRAY
Returns a list consisting of all the keys of the named hash, or the indices
of an array. (In scalar context, returns the number of keys or indices.)
@@ -2701,8 +2703,10 @@ C<keys> in this way (but you needn't worry about doing this by accident,
as trying has no effect). C<keys @array> in an lvalue context is a syntax
error.
-When given a reference to a hash or array, the argument will be
-dereferenced automatically.
+Starting with Perl 5.14, C<keys> can take a reference to a hash or array.
+The argument will be dereferenced automatically. This aspect of C<keys>
+is considered highly experimental. The exact behaviour may change in a
+future version of Perl.
for (keys $hashref) { ... }
for (keys $obj->get_arrayref) { ... }
@@ -7435,10 +7439,10 @@ files. On systems that don't support futimes(2), passing filehandles raises
an exception. Filehandles must be passed as globs or glob references to be
recognized; barewords are considered filenames.
-=item values HASH (or HASHREF)
+=item values HASH
X<values>
-=item values ARRAY (or ARRAYREF)
+=item values ARRAY
Returns a list consisting of all the values of the named hash, or the values
of an array. (In a scalar context, returns the number of values.)
@@ -7466,8 +7470,10 @@ modify the contents of the hash:
for (values %hash) { s/foo/bar/g } # modifies %hash values
for (@hash{keys %hash}) { s/foo/bar/g } # same
-When given a reference to a hash or array, the argument will be
-dereferenced automatically.
+Starting with Perl 5.14, C<values> can take a reference to a hash or array.
+The argument will be dereferenced automatically. This aspect of C<values>
+is considered highly experimental. The exact behaviour may change in a
+future version of Perl.
for (values $hashref) { ... }
for (values $obj->get_arrayref) { ... } |
From @obraAfter poring over the test scripts and various recommendations, * keys, each and values should only magically dereference unblessed * keys, each and values should behave as they did in 5.12 for blessed * For 5.14, we will mark this behavior as experimental, with an eye I'm really sorry that I've been so avoidant on this one. -Jesse |
From @obraAs happens with some regularity, I made a pronouncement that was too Let me try again: The following should magically dereference unblessed arrayrefs: The following should magically dereference unblessed hashrefs or arrayrefs: Everything else should work like it did in 5.12. Now, given that pronouncement, I _believe_ we have some bugs to fix and some -j |
From @AbigailOn Tue, Apr 12, 2011 at 06:50:03AM -0400, Jesse Vincent wrote:
No splice?
Abigail |
From @obraOn Tue, Apr 12, 2011 at 12:55:00PM +0200, Abigail wrote:
*sigh* The first version of this message had just said "keys and |
From @xdgOn Tue, Apr 12, 2011 at 7:02 AM, Jesse Vincent <jesse@fsck.com> wrote:
Splice was not made magical like push/pop/etc. -- David |
From @xdgOn Tue, Apr 12, 2011 at 7:41 AM, David Golden <xdaveg@gmail.com> wrote:
Sorry -- yes it was and it should be made to work only on unblessed Apologies for the confusion. I'm in week 3 of my sleep deprivation -- David |
From @cpansproutOn Apr 12, 2011, at 6:25 AM, David Golden via RT wrote:
Jesse: What about keys %hashref as an lvalue? David: Are you going to do this, or shall I go ahead? |
From @xdgOn Sun, Apr 17, 2011 at 8:08 PM, Father Chrysostomos <sprout@cpan.org> wrote:
Father C: I've got a 3 week old baby and family in town, so I've Regards, |
From @obraOn Sun, Apr 17, 2011 at 05:08:38PM -0700, Father Chrysostomos wrote:
On an unblessed hashref, my ideal would be for it to work as close to Thanks for the catch. -- |
From @cpansproutOn Apr 17, 2011, at 6:36 PM, David Golden wrote:
OK, I will. |
From @obrasprout's series of commits just now gets us to the place we hoped to be |
@obra - Status changed from 'open' to 'resolved' |
Migrated from rt.perl.org#80626 (status was 'resolved')
Searchable as RT80626$
The text was updated successfully, but these errors were encountered: