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

Wishlist: Overridable keywords #11869

Open
p5pRT opened this issue Jan 15, 2012 · 130 comments
Open

Wishlist: Overridable keywords #11869

p5pRT opened this issue Jan 15, 2012 · 130 comments

Comments

@p5pRT
Copy link

p5pRT commented Jan 15, 2012

Migrated from rt.perl.org#108286 (status was 'open')

Searchable as RT108286$

@p5pRT
Copy link
Author

p5pRT commented Jan 15, 2012

From @cpansprout

This touches on issues in tickets #84690, #94480, #96116, #105924, #105926 and #105928.

I have been thinking about this from time to time, and I think I finally have all the edge cases worked out​:

Proposal


I propose that we make �use feature "overrides"� allow all keywords to be overridden.

Infix operators like �and� will continue to be overridable only in non-infix positions. I.e., �use subs "and"; sub and () {} and and and� will continue to parse as �&and && &and�, as it currently does. Allowing overridable infix operators would be nice, but is not part of this proposal. Maybe that can come later.

The keywords do, require and glob are currently not overridable as keywords. Overrides cannot change their syntax, but only their behaviour. In other words, overrides of these keywords are actually callbacks, rather than overrides.

I propose that whether overrides of those three keywords are actual keyword overrides depend on whether the �overrides� feature is enabled in the scope where the subroutine is defined, not where it is used. For XS functions, I don�t know which way we should do it. We probably need a new XS keyword, similar to PROTOTYPE.

I also propose that we add an :iter attribute, that will allow custom subs to get the special defined() treatment that glob and readline get inside a while() condition. (while(glob "foo") is equivalent to while(defined(glob "foo")).)

All special-casing for parsing require VERSION should be removed from the tokenizer. ck_require can flag the op if it has a single unfolded numeric or vstring constant for its kidop. require VERSION should not delegate to a callback (�override�) any more.

glob overrides should no longer be passed a second argument. The only code using the undocumented second argument anywhere on CPAN is in the core and can be changed.

<> should continue to call glob and readline overrides automatically.

Reasoning


This should be in a feature feature, because otherwise the existence of a length method will cause every subsequent use of length() in the same file to produce a warning.

do, glob, and require should be overridable based on the hints where the sub is defined, not where the sub is used, because otherwise this would violate existing subs� expectations. Existing require subs expect to receive "Foo/Bar.pm" rather than "Foo​::Bar". A true override (with a * prototype) would leave it as "Foo​::Bar". Similarly for glob overrides​: an existing custom glob function might expect the automatic defined() in while(glob()).

The purpose of the :iter attribute is to avoid adding too many more hacks to fix bug #84690. It also allows true glob overrides to retain that feature.

Parsing of require VERSION is currently very screwy. It is not even consistent with itself. require also has the num/str bug, in that it tries to decide based on the type of its operand whether it will be a version number or a file name. We cannot fix that bug unless we make require VERSION a *syntactic* special case. In that case require $version would no longer work (thank goodness!). That means that require overrides would no longer be able to do CORE​::require($_[0]), unless we stop calling the override in the case of a version number. That would apply only to �callback-style� overrides; i.e., the old kind. require overrides defined under �use feature "overrides"� would be true overrides which would not go through the special parsing at all, but would be required (i.e., allowed) to implement it themselves, if at all.

My reason for putting require parsing in this ticket is that it is inextricably linked to the overrides feature. It�s hard to change one without the other.

The reason for eliminating the second argument to glob() (did you even know about it?) is that <> will continue to call glob overrides, and glob implementations that want to accept lists will still be expected to handle <>�s calling convention.


Flags​:
  category=wishlist
  severity=low


Site configuration information for perl 5.15.6​:

Configured by sprout at Sat Dec 31 10​:12​:16 PST 2011.

Summary of my perl5 (revision 5 version 15 subversion 6) configuration​:
  Local Commit​: b2635083831c8935c437465bbeb03aec8b599c01
  Ancestor​: 407287f
  Platform​:
  osname=darwin, osvers=10.5.0, archname=darwin-thread-multi-2level
  uname='darwin pint.local 10.5.0 darwin kernel version 10.5.0​: fri nov 5 23​:20​:39 pdt 2010; root​:xnu-1504.9.17~1release_i386 i386 '
  config_args='-de -Dusedevel -Duseithreads -DDEBUGGING -Dmad'
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=define, usemultiplicity=define
  useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
  use64bitint=undef, use64bitall=undef, uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='cc', ccflags ='-fno-common -DPERL_DARWIN -DDEBUGGING -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include',
  optimize='-O3 -g',
  cppflags='-fno-common -DPERL_DARWIN -DDEBUGGING -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
  ccversion='', gccversion='4.2.1 (Apple Inc. build 5664)', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
  ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
  alignbytes=8, prototype=define
  Linker and Libraries​:
  ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc', ldflags =' -fstack-protector -L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib
  libs=-ldbm -ldl -lm -lutil -lc
  perllibs=-ldl -lm -lutil -lc
  libc=, so=dylib, useshrplib=false, libperl=libperl.a
  gnulibc_version=''
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
  cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup -L/usr/local/lib -fstack-protector'

Locally applied patches​:
 


@​INC for perl 5.15.6​:
  /usr/local/lib/perl5/site_perl/5.15.6/darwin-thread-multi-2level
  /usr/local/lib/perl5/site_perl/5.15.6
  /usr/local/lib/perl5/5.15.6/darwin-thread-multi-2level
  /usr/local/lib/perl5/5.15.6
  /usr/local/lib/perl5/site_perl
  .


Environment for perl 5.15.6​:
  DYLD_LIBRARY_PATH (unset)
  HOME=/Users/sprout
  LANG=en_US.UTF-8
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/usr/bin​:/bin​:/usr/sbin​:/sbin​:/usr/local/bin​:/usr/X11/bin​:/usr/local/bin
  PERL_BADLANG (unset)
  SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Jan 16, 2012

From @sciurius

Father Chrysostomos (via RT) <perlbug-followup@​perl.org> writes​:

I propose that we make �use feature "overrides"� allow all keywords to
be overridden.

I'll bite... I think it's a good plan.

-- Johan

@p5pRT
Copy link
Author

p5pRT commented Jan 16, 2012

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jan 16, 2012

From @cpansprout

On Mon Jan 16 10​:35​:58 2012, jv wrote​:

Father Chrysostomos (via RT) <perlbug-followup@​perl.org> writes​:

I propose that we make �use feature "overrides"� allow all keywords to
be overridden.

I'll bite... I think it's a good plan.

I plan to implement it for 5.18.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jan 16, 2012

From [Unknown Contact. See original ticket]

On Mon Jan 16 10​:35​:58 2012, jv wrote​:

Father Chrysostomos (via RT) <perlbug-followup@​perl.org> writes​:

I propose that we make �use feature "overrides"� allow all keywords to
be overridden.

I'll bite... I think it's a good plan.

I plan to implement it for 5.18.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jan 24, 2012

From @rjbs

* Father Chrysostomos via RT <perlbug-comment@​perl.org> [2012-01-16T16​:28​:49]

I plan to implement it for 5.18.

I look forward to thinking more about it and poking at your work :)

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Apr 4, 2012

From @cpansprout

On Mon Jan 16 10​:35​:58 2012, jv wrote​:

Father Chrysostomos (via RT) <perlbug-followup@​perl.org> writes​:

I propose that we make �use feature "overrides"� allow all keywords to
be overridden.

I'll bite... I think it's a good plan.

But there is one thing my plans did not address​: How should elsif and
else work? If elsif is overridable like any other keyword, then what
happens in cases like this?

  use feature 'overrides';
  use subs 'else';
  sub else(&) { die }
  if ($x) { }
  else { }

Is else considered part of the if() statement, such that the presence of
if() causes else to be interpreted as the built-in keyword?

Or is else a keyword in its own right, so the override kicks in,
compiling the above as

  if ($x) { }
  &else(sub { });

?

If the former, then is there any need for else and elsif to be
considered keywords outside of their if() context?

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 4, 2012

From [Unknown Contact. See original ticket]

On Mon Jan 16 10​:35​:58 2012, jv wrote​:

Father Chrysostomos (via RT) <perlbug-followup@​perl.org> writes​:

I propose that we make �use feature "overrides"� allow all keywords to
be overridden.

I'll bite... I think it's a good plan.

But there is one thing my plans did not address​: How should elsif and
else work? If elsif is overridable like any other keyword, then what
happens in cases like this?

  use feature 'overrides';
  use subs 'else';
  sub else(&) { die }
  if ($x) { }
  else { }

Is else considered part of the if() statement, such that the presence of
if() causes else to be interpreted as the built-in keyword?

Or is else a keyword in its own right, so the override kicks in,
compiling the above as

  if ($x) { }
  &else(sub { });

?

If the former, then is there any need for else and elsif to be
considered keywords outside of their if() context?

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 4, 2012

From @sciurius

"Father Chrysostomos via RT" <perlbug-comment@​perl.org> writes​:

But there is one thing my plans did not address​: How should elsif and
else work? If elsif is overridable like any other keyword, then what
happens in cases like this?

Suggestion​: Do not allow if, else, elseif to be overridden independently
but treat them as one set of keywords.

So you either override them all, or none.

Does that make sense?

-- Johan

@p5pRT
Copy link
Author

p5pRT commented Apr 4, 2012

From j.imrie1@virginmedia.com

On 04/04/2012 19​:58, Johan Vromans wrote​:

"Father Chrysostomos via RT"<perlbug-comment@​perl.org> writes​:

But there is one thing my plans did not address​: How should elsif and
else work? If elsif is overridable like any other keyword, then what
happens in cases like this?
Suggestion​: Do not allow if, else, elseif to be overridden independently
but treat them as one set of keywords.

So you either override them all, or none.

Does that make sense?

-- Johan
Opposing suggestion​:
Allow overriding of if, else and elsif to be overridden independently
but make

CORE​::KEYWORD​::if etc. have the default semantics.

John

@p5pRT
Copy link
Author

p5pRT commented Apr 4, 2012

From @ikegami

On Sun, Jan 15, 2012 at 3​:51 PM, Father Chrysostomos <
perlbug-followup@​perl.org> wrote​:

# New Ticket Created by Father Chrysostomos
# Please include the string​: [perl #108286]
# in the subject line of all future correspondence about this issue.
# <URL​: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=108286 >

This touches on issues in tickets #84690, #94480, #96116, #105924, #105926
and #105928.

I have been thinking about this from time to time, and I think I finally
have all the edge cases worked out​:

Proposal
--------

I propose that we make �use feature "overrides"� allow all keywords to be
overridden.

What do you mean by overriding a keyword? Do you mean a Perl-accessible
version of PL_keyword_plugin (i.e. the keyword introduces your own grammar
rule)? Do you mean the ability to pass them to "use subs"?

@p5pRT
Copy link
Author

p5pRT commented Apr 4, 2012

From @ikegami

On Wed, Apr 4, 2012 at 11​:50 AM, Father Chrysostomos via RT <
perlbug-comment@​perl.org> wrote​:

But there is one thing my plans did not address​: How should elsif and
else work?

If elsif is overridable like any other keyword, then what
happens in cases like this?

use feature 'overrides';
use subs 'else';
sub else(&) { die }
if ($x) { }
else { }

The builtin "if" should expect the following to follow it (ignoring
whitespace)

"(" EXPR ")" BLOCK ( "elsif" "(" EXPR ")" BLOCK )* ( "else" BLOCK )?

None of those tokens should be overridable when parsing that rule (although
EXPR and BLOCK may use overridden tokens).

If by overriding a keyword you mean altering its syntax to something of the
user's choice, and if you want to change "else"'s syntax, override "if" and
"unless".

If by overriding a keyword you mean giving the ability to create functions
with the same name, and if you want create a sub called "else", the sub
call can be disambiguated with a leading ";", or even "&" (although the
latter disables prototypes).

- Eric

@p5pRT
Copy link
Author

p5pRT commented Apr 5, 2012

From @cpansprout

On Wed Apr 04 13​:53​:55 2012, ikegami@​adaelis.com wrote​:

On Wed, Apr 4, 2012 at 11​:50 AM, Father Chrysostomos via RT <
perlbug-comment@​perl.org> wrote​:

But there is one thing my plans did not address​: How should elsif and
else work?

If elsif is overridable like any other keyword, then what
happens in cases like this?

use feature 'overrides';
use subs 'else';
sub else(&) { die }
if ($x) { }
else { }

The builtin "if" should expect the following to follow it (ignoring
whitespace)

"(" EXPR ")" BLOCK ( "elsif" "(" EXPR ")" BLOCK )* ( "else" BLOCK )?

None of those tokens should be overridable when parsing that rule
(although
EXPR and BLOCK may use overridden tokens).

If by overriding a keyword you mean altering its syntax to something
of the
user's choice, and if you want to change "else"'s syntax, override
"if" and
"unless".

If by overriding a keyword you mean giving the ability to create functions
with the same name,

That is what I mean.

and if you want create a sub called "else", the sub
call can be disambiguated with a leading ";", or even "&" (although the
latter disables prototypes).

Your suggestion sounds good to me.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 5, 2012

From [Unknown Contact. See original ticket]

On Wed Apr 04 13​:53​:55 2012, ikegami@​adaelis.com wrote​:

On Wed, Apr 4, 2012 at 11​:50 AM, Father Chrysostomos via RT <
perlbug-comment@​perl.org> wrote​:

But there is one thing my plans did not address​: How should elsif and
else work?

If elsif is overridable like any other keyword, then what
happens in cases like this?

use feature 'overrides';
use subs 'else';
sub else(&) { die }
if ($x) { }
else { }

The builtin "if" should expect the following to follow it (ignoring
whitespace)

"(" EXPR ")" BLOCK ( "elsif" "(" EXPR ")" BLOCK )* ( "else" BLOCK )?

None of those tokens should be overridable when parsing that rule
(although
EXPR and BLOCK may use overridden tokens).

If by overriding a keyword you mean altering its syntax to something
of the
user's choice, and if you want to change "else"'s syntax, override
"if" and
"unless".

If by overriding a keyword you mean giving the ability to create functions
with the same name,

That is what I mean.

and if you want create a sub called "else", the sub
call can be disambiguated with a leading ";", or even "&" (although the
latter disables prototypes).

Your suggestion sounds good to me.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 22, 2012

From @cpansprout

On Wed Apr 04 13​:53​:55 2012, ikegami@​adaelis.com wrote​:

The builtin "if" should expect the following to follow it (ignoring
whitespace)

"(" EXPR ")" BLOCK ( "elsif" "(" EXPR ")" BLOCK )* ( "else" BLOCK )?

None of those tokens should be overridable when parsing that rule
(although
EXPR and BLOCK may use overridden tokens).

In that case, is there any reason why elsif needs to be a reserved word
outside of that context?

I�m also trying to plan ahead with regard to adding all keywords to the
CORE​:: namespace.

It should be possible in the future for the �if� keyword to be
implemented as a CV named &CORE​::if, which has its own custom parser
that eats the elsif and else keywords.

But it wonâ��t make much sense for there to be a &CORE​::elsif subroutine.
It would just be a stub that produces a syntax error when inlined.
Maybe that does make sense. Then we could always change it later.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 22, 2012

From [Unknown Contact. See original ticket]

On Wed Apr 04 13​:53​:55 2012, ikegami@​adaelis.com wrote​:

The builtin "if" should expect the following to follow it (ignoring
whitespace)

"(" EXPR ")" BLOCK ( "elsif" "(" EXPR ")" BLOCK )* ( "else" BLOCK )?

None of those tokens should be overridable when parsing that rule
(although
EXPR and BLOCK may use overridden tokens).

In that case, is there any reason why elsif needs to be a reserved word
outside of that context?

I�m also trying to plan ahead with regard to adding all keywords to the
CORE​:: namespace.

It should be possible in the future for the �if� keyword to be
implemented as a CV named &CORE​::if, which has its own custom parser
that eats the elsif and else keywords.

But it wonâ��t make much sense for there to be a &CORE​::elsif subroutine.
It would just be a stub that produces a syntax error when inlined.
Maybe that does make sense. Then we could always change it later.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 22, 2012

From @ikegami

On Sun, Apr 22, 2012 at 1​:41 AM, Father Chrysostomos via RT <
perlbug-comment@​perl.org> wrote​:

On Wed Apr 04 13​:53​:55 2012, ikegami@​adaelis.com wrote​:

The builtin "if" should expect the following to follow it (ignoring
whitespace)

"(" EXPR ")" BLOCK ( "elsif" "(" EXPR ")" BLOCK )* ( "else" BLOCK )?

None of those tokens should be overridable when parsing that rule
(although
EXPR and BLOCK may use overridden tokens).

In that case, is there any reason why elsif needs to be a reserved word
outside of that context?

I was wondering that myself when I typed the above. We allow C<< sub if { }

, so why not C<< sub elsif { } >>?

I'm not seeing the value of C<< elsif(); >> being a syntax error. The two
reasons I can come up for continuing to be a syntax error are confusion
avoidance and syntax error detection, but neither reason is valid. We
already allow C<< sub if { } >>, and C<< elsif (...) { ... } >> would still
be a syntax error if C<< elsif(...); >> isn't.

@p5pRT
Copy link
Author

p5pRT commented Apr 22, 2012

From @cpansprout

On Sun Apr 22 13​:25​:19 2012, ikegami@​adaelis.com wrote​:

On Sun, Apr 22, 2012 at 1​:41 AM, Father Chrysostomos via RT <
perlbug-comment@​perl.org> wrote​:

On Wed Apr 04 13​:53​:55 2012, ikegami@​adaelis.com wrote​:

The builtin "if" should expect the following to follow it (ignoring
whitespace)

"(" EXPR ")" BLOCK ( "elsif" "(" EXPR ")" BLOCK )* ( "else" BLOCK )?

None of those tokens should be overridable when parsing that rule
(although
EXPR and BLOCK may use overridden tokens).

In that case, is there any reason why elsif needs to be a reserved word
outside of that context?

I was wondering that myself when I typed the above. We allow C<< sub
if { }

, so why not C<< sub elsif { } >>?

I'm not seeing the value of C<< elsif(); >> being a syntax error.

Allowing C<< sub elsif { } >> and having C<< elsif(); >> be a syntax
error by default are not exclusive.

The real question is​: Without an imported override named elsif, what
should elsif(); do?

Another way of putting it​: Should there by a sub named CORE​::elsif that
produces a syntax error when inlined? Or should there be no CORE​::elsif
sub at all, elsif only being treated as a keyword after if(){} or elsif{}?

I�m leaning toward the former right now, as it avoids changing the
behaviour unnecessarily.

The two
reasons I can come up for continuing to be a syntax error are confusion
avoidance and syntax error detection, but neither reason is valid. We
already allow C<< sub if { } >>, and C<< elsif (...) { ... } >> would
still
be a syntax error if C<< elsif(...); >> isn't.

With custom call parsers, elsif(){} could be valid syntax even with a
sub named elsif :-).

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 22, 2012

From [Unknown Contact. See original ticket]

On Sun Apr 22 13​:25​:19 2012, ikegami@​adaelis.com wrote​:

On Sun, Apr 22, 2012 at 1​:41 AM, Father Chrysostomos via RT <
perlbug-comment@​perl.org> wrote​:

On Wed Apr 04 13​:53​:55 2012, ikegami@​adaelis.com wrote​:

The builtin "if" should expect the following to follow it (ignoring
whitespace)

"(" EXPR ")" BLOCK ( "elsif" "(" EXPR ")" BLOCK )* ( "else" BLOCK )?

None of those tokens should be overridable when parsing that rule
(although
EXPR and BLOCK may use overridden tokens).

In that case, is there any reason why elsif needs to be a reserved word
outside of that context?

I was wondering that myself when I typed the above. We allow C<< sub
if { }

, so why not C<< sub elsif { } >>?

I'm not seeing the value of C<< elsif(); >> being a syntax error.

Allowing C<< sub elsif { } >> and having C<< elsif(); >> be a syntax
error by default are not exclusive.

The real question is​: Without an imported override named elsif, what
should elsif(); do?

Another way of putting it​: Should there by a sub named CORE​::elsif that
produces a syntax error when inlined? Or should there be no CORE​::elsif
sub at all, elsif only being treated as a keyword after if(){} or elsif{}?

I�m leaning toward the former right now, as it avoids changing the
behaviour unnecessarily.

The two
reasons I can come up for continuing to be a syntax error are confusion
avoidance and syntax error detection, but neither reason is valid. We
already allow C<< sub if { } >>, and C<< elsif (...) { ... } >> would
still
be a syntax error if C<< elsif(...); >> isn't.

With custom call parsers, elsif(){} could be valid syntax even with a
sub named elsif :-).

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 22, 2012

From @cpansprout

On Sun Jan 15 12​:51​:08 2012, sprout wrote​:

I also propose that we add an :iter attribute, that will allow custom
subs to get the special defined() treatment that glob and readline
get inside a while() condition. (while(glob "foo") is equivalent
to while(defined(glob "foo")).)

Actually, it�s equivalent to while(defined($_ = glob "foo")).

Interestingly, while($x=<foo>) did not get the special treatment until
commit 4b161ae, which I think was somewhere on the 5.004 maint branch.

Commit 4b161ae also made while($x=each %foo) get wrapped in
defined(), but did not affect while(each %foo), which gets neither
defined() nor $_=.

Was $_= omitted to avoid backward-compatibility problems, or was it an
oversight? Was it simply an oversight that defined() was omitted in
that case?

The reason I ask is that it would be nice if we could make this all
consistent, but there may be good reasons why we cannot.

I also need to know how this will affect my :iter proposal. Based on
the precedent set by �each�, while($x=itersub) should become
while(defined($x=itersub)). But what should happen for while(itersub)?
Should it stay as it is (like each)? Should it become
while(defined($_=itersub)) like readline? Or should we take a middle
ground, and make it while(defined(itersub))?

Also, as long as �each� follows its own rules, how is one to override it
with another iterator function, while preserving exactly the same syntax?

Maybe in the end we need to let the iter sub itself decide, and while()
could call it with a special param, or a package variable (like
$AUTOLOAD), or *somehow* signal it to tell it that it is in a while().

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 22, 2012

From [Unknown Contact. See original ticket]

On Sun Jan 15 12​:51​:08 2012, sprout wrote​:

I also propose that we add an :iter attribute, that will allow custom
subs to get the special defined() treatment that glob and readline
get inside a while() condition. (while(glob "foo") is equivalent
to while(defined(glob "foo")).)

Actually, it�s equivalent to while(defined($_ = glob "foo")).

Interestingly, while($x=<foo>) did not get the special treatment until
commit 4b161ae, which I think was somewhere on the 5.004 maint branch.

Commit 4b161ae also made while($x=each %foo) get wrapped in
defined(), but did not affect while(each %foo), which gets neither
defined() nor $_=.

Was $_= omitted to avoid backward-compatibility problems, or was it an
oversight? Was it simply an oversight that defined() was omitted in
that case?

The reason I ask is that it would be nice if we could make this all
consistent, but there may be good reasons why we cannot.

I also need to know how this will affect my :iter proposal. Based on
the precedent set by �each�, while($x=itersub) should become
while(defined($x=itersub)). But what should happen for while(itersub)?
Should it stay as it is (like each)? Should it become
while(defined($_=itersub)) like readline? Or should we take a middle
ground, and make it while(defined(itersub))?

Also, as long as �each� follows its own rules, how is one to override it
with another iterator function, while preserving exactly the same syntax?

Maybe in the end we need to let the iter sub itself decide, and while()
could call it with a special param, or a package variable (like
$AUTOLOAD), or *somehow* signal it to tell it that it is in a while().

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2012

From @ikegami

On Sun, Apr 22, 2012 at 4​:56 PM, Father Chrysostomos via RT <
perlbug-comment@​perl.org> wrote​:

Another way of putting it​: Should there by a sub named CORE​::elsif that
produces a syntax error when inlined? Or should there be no CORE​::elsif
sub at all, elsif only being treated as a keyword after if(){} or elsif{}?

I�m leaning toward the former right now, as it avoids changing the
behaviour unnecessarily.

Would you recommend this behaviour to someone else? Say someone introduces
a C<< with ... in ... >> statement. Should they override C<< in >> so that
C<< in(); >> is a syntax error?

It's going to be fun telling people that Perl goes out of its way to make
C<< elsif(); >> a syntax error just so users can ask Perl not to make it a
syntax error.

- Eric

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2012

From @ap

* Father Chrysostomos via RT <perlbug-comment@​perl.org> [2012-04-22 23​:45]​:

I also need to know how this will affect my :iter proposal. Based on
the precedent set by �each�, while($x=itersub) should become
while(defined($x=itersub)).

Should it?

There is a bit of a problem there, isn�t it? The protocol with undef
obviously makes sense for `each` as a hash key can never be undef. But
when iterating arbitrarily (e.g. converting an array to an iter), undef
becomes a valid value, no?

So you cannot use it to abort iteration� unless you contrive something
contorted like returning a scalarref to the real value on every
successful iteration (thus turning undef in the data into \undef which
is true) and then an undef once you are done.

But what should happen for while(itersub)? Should it stay as it is
(like each)? Should it become while(defined($_=itersub)) like
readline? Or should we take a middle ground, and make it
while(defined(itersub))?

I would tend to go with adding the $_ assignment by default, including
adding it to `while(each %foo)` retroactively, if a scan of the CPAN
shows this to be viable without breaking huge swathes of code. It seems
the Perlish approach to take.

But, extending its coverage to arbitrary user-defined function concerns
me to some extent. As long as only `each`, `glob`, and `readline` get
this treatment, it is predictable what code will do. But if potentially
any sub could get it, then looking at

  while (foo $bar, $baz) { ... }

without knowing the definition of `foo` will not tell whether this code
will molest $_.

Also, as long as �each� follows its own rules, how is one to override
it with another iterator function, while preserving exactly the same
syntax?

Simple, you have to ensure that your overridden `each` has the exact
same semantics i.e. it can never return undef as part of the data. I see
no problem here.

Maybe in the end we need to let the iter sub itself decide, and while()
could call it with a special param, or a package variable (like
$AUTOLOAD), or *somehow* signal it to tell it that it is in a while().

Please let�s not. I like this least of all options.

Regards,
--
Aristotle Pagaltzis // <http​://plasmasturm.org/>

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2012

From @ap

* Aristotle Pagaltzis <pagaltzis@​gmx.de> [2012-04-23 12​:01]​:

The protocol with undef obviously makes sense for `each` as a hash key
can never be undef. But when iterating arbitrarily (e.g. converting an
array to an iter), undef becomes a valid value, no?

So you cannot use it to abort iteration� unless you contrive something
contorted like returning a scalarref to the real value on every
successful iteration (thus turning undef in the data into \undef which
is true) and then an undef once you are done.

Hmm. Now I am wondering how contrived that really is. I wonder if this
could be baked into the protocol, i.e. an :iter function returning any
value other than undef or a reference would throw an exception.

Then unpacking a scalarref into $_ could be baked right into the `while`
magic (returning other types of reference would be allowed but they
would, obviously, not be automatically deref�d) and you could write
Perlishly concise iterating loops at the price of a single backslash in
your iterator functions.

Warning​: highly experimental. I am a long way from thinking through all
the implications, the automatic deref in particular may turn out to be
a terrible idea in practice.

But if the pieces come together then I would be eager to prototype this
somewhere to see how well it holds up.

If we could get a solid, supported iteration mechanism right into core
that would *rock*. E.g. I remember the struggles PSGI went through for
lack of in-core iterators.

Regards,
--
Aristotle Pagaltzis // <http​://plasmasturm.org/>

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2012

From @nwc10

On Sun, Apr 22, 2012 at 02​:43​:25PM -0700, Father Chrysostomos via RT wrote​:

On Sun Jan 15 12​:51​:08 2012, sprout wrote​:

I also propose that we add an :iter attribute, that will allow custom
subs to get the special defined() treatment that glob and readline
get inside a while() condition. (while(glob "foo") is equivalent
to while(defined(glob "foo")).)

Actually, it's equivalent to while(defined($_ = glob "foo")).

Interestingly, while($x=<foo>) did not get the special treatment until
commit 4b161ae, which I think was somewhere on the 5.004 maint branch.

Commit 4b161ae also made while($x=each %foo) get wrapped in
defined(), but did not affect while(each %foo), which gets neither
defined() nor $_=.

Was $_= omitted to avoid backward-compatibility problems, or was it an
oversight? Was it simply an oversight that defined() was omitted in
that case?

I think that $_ = being ommitted on while(each %foo) is not an oversight
at that time.

That commit you quote gets me back to this message from Larry​:

  As usual, when there are long arguments, there are good arguments for both
  sides (mixed in with the chaff). In this case, let's make
 
  while ($x = <whatever>)
 
  equivalent to
 
  while (defined($x = <whatever>))
 
  (But nothing more complicated than an assignment should assume defined().)

http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-04/msg00133.html

Nick Ing-Simmons asks for a clarification​:

  Thanks Larry - that is what the patch I posted does.
 
  But it also does the same for C<readdir>, C<each> and C<glob> -
  i.e. the same cases that solicit the warning in 5.004 is extending
  the defined insertion to those cases desirable?
  (glob and readdir seem to make sense, I am less sure about each).

http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-04/msg00182.html

(it's clarified in a later message that Nick I-S hadn't realised that each
in *scalar* context returns the keys, so it's an analogous iterator which
can't return undef for any entry)

In turn, the "RULING" dates back to this thread/request​:

http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-03/msg01630.html

which also generates a massive thread, of which this message is probably
most insightful​:

  Pray tell how you can tell that the code is broken without comments in the
  code explaining what they expected it to do. while ($x = <>) is legal
  code and works as documented. It does not use the idiom of while (<>).
 
  You can't just say "this code is broken" about while ($x = <>) *in all
  cases* without more context to indicate the expected behaviour.

http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-03/msg01966.html

in turn that seems to be a reaction to these warnings added in 5.004

$ ./perl -lwe 'while ($a = each %a) {}'
Value of each() operator can be "0"; test with defined() at -e line 1.

[strictly as far as git has it, most this commit​:

commit a600677
Author​: Perl 5 Porters <perl5-porters@​africa.nicoh.com>
Date​: Wed Jan 1 08​:59​:00 1997 +1200

  [inseparable changes from patch from perl5.003_17 to perl5.003_18]
 
  CORE LANGUAGE CHANGES
 
...

  Subject​: Warn on '{if,while} ($x = X)' where X is glob, readdir, or <FH>
  From​: Chip Salzenberg <chip@​atlantic.net>
  Files​: op.c pod/perldiag.pod

...

as determined by

.../bisect.pl --end perl-5.004 -lwe 'BEGIN {$SIG{__WARN__} = sub {++$b}}; while ($a = <>) {++$a}; exit $b' </dev/null

and the each warning in this commit​:

commit 68dc074
Author​: Perl 5 Porters <perl5-porters@​africa.nicoh.com>
Date​: Sun Mar 9 11​:57​:19 1997 +1200
  [inseparable changes from match from perl-5.003_93 to perl-5.003_94]

...

  Subject​: Warn on C<while ($x = each %y) {}>
  From​: Chip Salzenberg <chip@​perl.com>
  Files​: op.c pod/perldiag.pod

as determined by

.../bisect.pl --end perl-5.004 -lwe 'BEGIN {$SIG{__WARN__} = sub {++$b}}; while ($a = each %a) {}; exit $b'

]

The rational for the former commit is detailed in the thread starting here​:

http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/9612/msg02125.html

the latter in these messages

http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1997-03/msg01263.html
http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1997-03/msg01302.html

The intent of the changes appears to be to retain the 5.003 and earlier
behaviour on what gets assigned for each construction, but change the loop
behaviour to terminate on undefined rather than simply falsehood for the
common simple cases​:

  while (OP ...)

and

  while ($var = OP ...)

The mail archives from 1997 are fascinating. Lots of messages. Lots of
design discussions, not always helpful. And some of the same unanswered
questions as today.

Nicholas Clark

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2012

From dcmertens.perl@gmail.com

Can someone point me to the discussion where it was decided that overriding
if() was a good idea? It seems to have sprung out of nowhere in this
discussion. I skimmed through the related tickets but only saw discussion
of glob(). Did I miss it?

Thanks!
David

--
"Debugging is twice as hard as writing the code in the first place.
  Therefore, if you write the code as cleverly as possible, you are,
  by definition, not smart enough to debug it." -- Brian Kernighan

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2012

From @cpansprout

On Mon Apr 23 14​:20​:09 2012, dcmertens.perl@​gmail.com wrote​:

Can someone point me to the discussion where it was decided that
overriding
if() was a good idea? It seems to have sprung out of nowhere in this
discussion. I skimmed through the related tickets but only saw discussion
of glob(). Did I miss it?

Overriding if() and being *able* to override if() are two different things.

Anyone who overrides if() is probably asking for trouble.

But it would be nice to override length() and vec(). Where do we draw
the line? Or, rather, why do we need to draw a line? Instead of
debating over every keyword about whether it should be overridable,
let�s just make them all overridable, allowing smarter people to do
things we haven�t thought of.

I only brought up if() in particular because it can have elsif attached
to it, and we need to figure out how things are going to fit together.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2012

From @cpansprout

On Mon Apr 23 14​:03​:27 2012, nicholas wrote​:

The intent of the changes appears to be to retain the 5.003 and
earlier
behaviour on what gets assigned for each construction, but change the
loop
behaviour to terminate on undefined rather than simply falsehood for
the
common simple cases​:

while \(OP \.\.\.\)

and

while \($var = OP \.\.\.\)

Except that while($var = each %h) implies defined(), but while(each %h)
does not. So something got screwed up. :-)

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2012

From @cpansprout

Χ�ι��ὸ� �νέ��η!

On Mon Apr 23 03​:03​:36 2012, aristotle wrote​:

* Aristotle Pagaltzis <pagaltzis@​gmx.de> [2012-04-23 12​:01]​:

The protocol with undef obviously makes sense for `each` as a hash key
can never be undef. But when iterating arbitrarily (e.g. converting an
array to an iter), undef becomes a valid value, no?

So you cannot use it to abort iteration� unless you contrive something
contorted like returning a scalarref to the real value on every
successful iteration (thus turning undef in the data into \undef which
is true) and then an undef once you are done.

Hmm. Now I am wondering how contrived that really is. I wonder if this
could be baked into the protocol, i.e. an :iter function returning any
value other than undef or a reference would throw an exception.

Then unpacking a scalarref into $_ could be baked right into the `while`
magic (returning other types of reference would be allowed but they
would, obviously, not be automatically deref�d) and you could write
Perlishly concise iterating loops at the price of a single backslash in
your iterator functions.

Warning​: highly experimental. I am a long way from thinking through all
the implications, the automatic deref in particular may turn out to be
a terrible idea in practice.

This reference interface would make the sub practically unusable outside
of a while loop.

But if the pieces come together then I would be eager to prototype this
somewhere to see how well it holds up.

I�ve already been thinking about that. This would require hooking
PL_check or something to intercept how while loops are compiled. And
then, to work with closures, we would have to associate the attribute
with the address of the op tree. I can already see how that could be
accomplished, without memory leaks, using tied field hashes.

If we could get a solid, supported iteration mechanism right into core
that would *rock*.

But we may end up with too many variations that are all equally good,
but designed for different circumstances. Maybe in the end the core
docs could recommend Sub​::Iter (or whatever name it gets), they way they
do Unicode​::Casing.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2012

From @cpansprout

On Mon Apr 23 15​:19​:09 2012, sprout wrote​:

I�ve already been thinking about that. This would require hooking
PL_check or something to intercept how while loops are compiled. And
then, to work with closures, we would have to associate the attribute
with the address of the op tree. I can already see how that could be
accomplished, without memory leaks, using tied field hashes.

In fact, in the process of thinking about this and considering where the
attribute could be stored, I�ve noticed that cv_clone doesn�t copy
magic, which means that call checkers added in attribute handlers won�t
apply to closures cloned therefrom. I think this is clearly a bug. But
(and this question is aimed mostly at Zefram) would copying the magic be
the best solution? Is there a standard way of copying magic already
that cv_clone can use?

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented May 15, 2012

From @doy

On Tue, May 15, 2012 at 05​:59​:22PM -0400, Eric Brine wrote​:

On Tue, May 15, 2012 at 4​:55 PM, Jesse Luehrs <doy@​tozt.net> wrote​:

Okay, now I'm confused. What are you actually asking? Are you referring
to some potential future try/catch keyword that may be added to the
language in the future?

No. Some try/catch keyword that can be added by anyone, today or even
yesterday.

Okay, this is where I was confused then.

If you are, my position is that all of the
arguments I've been making about 'else' apply equally well to 'catch'

and they should be treated the same (i.e., not overridable via the

keyword plugin mechanism).

Well, that's what I thought you meant, but it makes no sense. Since I could
have used any word instead of catch, it applies to every word. It makes no
sense to prevent all keywords from being overridden by the keyword plugin.

I believe the keyword plugin should not override "else" **immediately after
an if/elsif block**. More generally, I believe the keyword plugin should
not be called anywhere but where an expression is expected.

FC​:
I'm ok with making C<else> and C<continue> reserved words to avoid the
ambiguous message. Whoever might write try-catch can make C<catch> a
reserved word too if they so desire, so consistency is still possible.

Yes, I agree with all this (including making 'else' and 'continue'
reserved words).

-doy

@p5pRT
Copy link
Author

p5pRT commented May 15, 2012

From @doy

On Tue, May 15, 2012 at 05​:29​:43PM -0500, Jesse Luehrs wrote​:

On Tue, May 15, 2012 at 05​:59​:22PM -0400, Eric Brine wrote​:

On Tue, May 15, 2012 at 4​:55 PM, Jesse Luehrs <doy@​tozt.net> wrote​:

Okay, now I'm confused. What are you actually asking? Are you referring
to some potential future try/catch keyword that may be added to the
language in the future?

No. Some try/catch keyword that can be added by anyone, today or even
yesterday.

Okay, this is where I was confused then.

If you are, my position is that all of the
arguments I've been making about 'else' apply equally well to 'catch'

and they should be treated the same (i.e., not overridable via the

keyword plugin mechanism).

Well, that's what I thought you meant, but it makes no sense. Since I could
have used any word instead of catch, it applies to every word. It makes no
sense to prevent all keywords from being overridden by the keyword plugin.

I believe the keyword plugin should not override "else" **immediately after
an if/elsif block**. More generally, I believe the keyword plugin should
not be called anywhere but where an expression is expected.

FC​:
I'm ok with making C<else> and C<continue> reserved words to avoid the
ambiguous message. Whoever might write try-catch can make C<catch> a
reserved word too if they so desire, so consistency is still possible.

Yes, I agree with all this (including making 'else' and 'continue'
reserved words).

Actually, I'm less sure about 'continue', considering it's use as a flow
control operator within given/when. Not entirely sure what should be
done about that case (reusing keywords for radically different things
makes parsing pretty annoying).

-doy

@p5pRT
Copy link
Author

p5pRT commented May 16, 2012

From @cpansprout

On Tue May 15 15​:34​:13 2012, doy@​tozt.net wrote​:

On Tue, May 15, 2012 at 05​:29​:43PM -0500, Jesse Luehrs wrote​:

On Tue, May 15, 2012 at 05​:59​:22PM -0400, Eric Brine wrote​:

On Tue, May 15, 2012 at 4​:55 PM, Jesse Luehrs <doy@​tozt.net>
wrote​:

Okay, now I'm confused. What are you actually asking? Are you
referring
to some potential future try/catch keyword that may be added to
the
language in the future?

No. Some try/catch keyword that can be added by anyone, today or
even
yesterday.

Okay, this is where I was confused then.

If you are, my position is that all of the
arguments I've been making about 'else' apply equally well to
'catch'

and they should be treated the same (i.e., not overridable via the

keyword plugin mechanism).

Well, that's what I thought you meant, but it makes no sense.
Since I could
have used any word instead of catch, it applies to every word. It
makes no
sense to prevent all keywords from being overridden by the keyword
plugin.

I believe the keyword plugin should not override "else"
**immediately after
an if/elsif block**. More generally, I believe the keyword plugin
should
not be called anywhere but where an expression is expected.

Well how about my commit ae8d051 on the sprout/overridesδ branch? Is
that the right approach?

FC​:
I'm ok with making C<else> and C<continue> reserved words to avoid
the
ambiguous message. Whoever might write try-catch can make C<catch>
a
reserved word too if they so desire, so consistency is still
possible.

Yes, I agree with all this (including making 'else' and 'continue'
reserved words).

Actually, I'm less sure about 'continue', considering it's use as a
flow
control operator within given/when. Not entirely sure what should be
done about that case (reusing keywords for radically different things
makes parsing pretty annoying).

Iâ��ve just discovered that this goes all the way back to perl 5.000​:

$ perl5.6.2 -e 'use subs "continue"; sub continue { warn "@​_" } while(1)
{ last } continue {}'
HASH(0x80015c) at -e line 1.

I think that should stop working, but I just wanted to check.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented May 17, 2012

From @ap

* Father Chrysostomos via RT <perlbug-followup@​perl.org> [2012-04-26 05​:50]​:

On Wed Apr 25 04​:30​:22 2012, aristotle wrote​:

* Father Chrysostomos via RT <perlbug-followup@​perl.org> [2012-04-24 00​:20]​:

Χ�ι��ὸ� �νέ��η!

�ληθῶ� �νέ��η.

Σ�γν�μη. �εγάλ��α εκ��� �λλάδα� �ε μη ο�θ�δοξη οικογένεια και �ολλέ�
�α�αδ��ει� δεν έζη�α, ο���ε και δεν θ�μήθηκα ��ι α��� είναι ε��ή και
αν�ε��ή.

--
Î�Ï�ιÏ�Ï�οÏ�έληÏ� ΠαγκαλÏ�ζήÏ� // <http​://plasmasturm.org/>

@p5pRT
Copy link
Author

p5pRT commented May 17, 2012

From @cpansprout

On Wed May 16 17​:24​:55 2012, aristotle wrote​:

* Father Chrysostomos via RT <perlbug-followup@​perl.org> [2012-04-26
05​:50]​:

On Wed Apr 25 04​:30​:22 2012, aristotle wrote​:

* Father Chrysostomos via RT <perlbug-followup@​perl.org> [2012-04-
24 00​:20]​:

Χ�ι��ὸ� �νέ��η!

�ληθῶ� �νέ��η.

Σ�γν�μη. �εγάλ��α εκ��� �λλάδα� �ε μη ο�θ�δοξη οικογένεια και �ολλέ�
�α�αδ��ει� δεν έζη�α, ο���ε και δεν θ�μήθηκα ��ι α��� είναι ε��ή και
αν�ε��ή.

�α�άλαβα. �ὲ ��γ���ε��ε.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented May 17, 2012

From @cpansprout

On Sun Jan 15 12​:51​:08 2012, sprout wrote​:

do, glob, and require should be overridable based on the hints where
the sub is defined, not where the sub is used, because otherwise
this would violate existing subs� expectations. Existing require
subs expect to receive "Foo/Bar.pm" rather than "Foo​::Bar". A true
override (with a * prototype) would leave it as "Foo​::Bar".
Similarly for glob overrides​: an existing custom glob function
might expect the automatic defined() in while(glob()).

perlsub has this to say about doâ��s prototype​:

The built-ins C<do>, C<require> and C<glob> can also be overridden, but due
to special magic, their original syntax is preserved, and you don't have
to define a prototype for their replacements. (You can't override the
C<do BLOCK> syntax, though).

What happens in reality is different​:

$ perl -le 'do("foo","bar")'
Too many arguments for do "file" at -e line 1, at EOF
Execution of -e aborted due to compilation errors.

$ perl -le 'use subs "do"; sub do {warn @​_}; do("foo","bar")'
foobar at -e line 1.

So it actually does take a list with no prototype.

With a scalar prototype, I get this​:

$ perl -le 'use subs "do"; sub do($) {warn @​_}; do("foo","bar")'
bar at -e line 1.

So the entire argument list is being treated as one of the arguments and
put in scalar context, resulting in this oddity​:

$ perl -le 'use subs "do"; sub do($$) {warn @​_}; do("foo","bar")'
Not enough arguments for main​::do at -e line 1, at EOF
Execution of -e aborted due to compilation errors.

And this​:

$ perl -le 'use subs "do"; sub do($@​) {warn @​_}; do("foo","bar")'
bar at -e line 1.

So the only cases that are not buggy are no prototype (or @​_), and ($)
called with one argument.

Hence, should I make it so that the prototype simply does apply properly
in all cases (except do{}), since that is what the only non-buggy cases
are doing? perlsub would have to be updated accordingly, but what it
has right now is not true.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented May 17, 2012

From @cpansprout

On Sun Jan 15 12​:51​:08 2012, sprout wrote​:

Proposal
--------

...

The keywords do, require and glob are currently not overridable as
keywords. Overrides cannot change their syntax, but only their
behaviour. In other words, overrides of these keywords are
actually callbacks, rather than overrides.

I propose that whether overrides of those three keywords are actual
keyword overrides depend on whether the �overrides� feature is
enabled in the scope where the subroutine is defined, not where it
is used. For XS functions, I don�t know which way we should do it.
We probably need a new XS keyword, similar to PROTOTYPE.

...

Reasoning
---------

...

do, glob, and require should be overridable based on the hints where
the sub is defined, not where the sub is used, because otherwise
this would violate existing subs� expectations. Existing require
subs expect to receive "Foo/Bar.pm" rather than "Foo​::Bar". A true
override (with a * prototype) would leave it as "Foo​::Bar".
Similarly for glob overrides​: an existing custom glob function
might expect the automatic defined() in while(glob()).

I�ve just realised that a �do� override won�t have this problem, as the
current override system never causes a �do� override to have any special
treatment other than being ignored when there is a block.

Only new code can have �use feature "overrides"�, so, if it imports a
�do� from elsewhere, then do-BLOCK will simply do the wrong thing. But
that could only affect *new* code. So it�s not necessary for �do� to be
treated specially like �require� and �glob�.

In fact, if �do� could go one way or the other, then so could any of the
other keywords that are currently not overridable. So we probably don�t
need any special-casing here at all. We could simply base the
overridability on whether the subroutine itself was declared in an
override scope, for all keywords that are not currently overridable.

We still have a problem with XSUBs, though. So, should this actually be
a sub attribute?

I would prefer not to have a sub attribute, because eventually, when all
code has �use 5.18� or higher, no one should have to think about it;
overrides should just use one mechanism, without the need for :override
for some names.

Should we assume that XS overrides for glob and require were declared
under �use feature "overrides"�. I think that is the best solution, as
nothing on CPAN as far as I can tell declares an XS glob or require
function. But I am not the most adept at searching CPAN.

BTW, I have implemented my original suggestion, which can be found on
the sprout/overridesε branch. (It doesn�t yet deal with XS require/glob
overrides; and it contains a bad attempt at fixing the �do� prototype
bug I brought up recently.)

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented May 20, 2012

From zefram@fysh.org

Eric Brine wrote​:

PS - Something to test​: What happens if one overrides C<elsif> using the
keyword plugin? Does it break C<if>?

I think the best way to do this (in the long run) is that the code to
parse the "if" syntax (which is magically attached to &if), when it sees
an identifier in a place that might be an "else" or "elsif", uses the
normal sub name lookup mechanism to decide what it means. Having resolved
the identifier to a sub ref, it checks whether this matches the &else or
&elsif that it knows about, and acts accordingly. &elsif is, of course,
a dummy sub, with parser magic that will just signal an error, because
"elsif" isn't allowed to be used on its own. The result is that you can
change the spelling of "elsif" by doing things like "*orif = \&elsif".
A user-added "if"-alike can use exactly the same mechanism, using either
the standard &elsif or its own dummy subs.

-zefram

@p5pRT
Copy link
Author

p5pRT commented May 20, 2012

From zefram@fysh.org

Eric Brine wrote​:

What is it we're suppose to use instead? Devel​::Declare?

The intention is to migrate Devel​::CallParser into the core. I'm actually
in the middle of that, on hold due to the freeze for 5.16. I got the
mechanism working in the core, but then discovered that one of the
standard procedural argument parsers doesn't actually match the core
yacc parser. So want to fix that before putting it into blead. Once D​:CP
is in the core, the PL_keyword_plugin will be obsolete and can be removed.

Generally, the paradigm I'm aiming for is to merge the keyword namespace
with the subroutine namespace, and have special parsing and compilation
behaviour implemented as magic attached to (possibly dummy) subroutines.
What sprout is addressing in this thread is the issue of making
existing builtins play relatively nicely with subroutine definitions.
That's an issue because currently builtins are a separate namespace
from subroutines, looked up in different ways. The aim is to make
user-supplied keywords as interchangeable with builtins as possible.

The PL_keyword_plugin mechanism, to the extent that it supplies any
namespace behaviour at all, goes with that older concept of keywords
being a different class of entity from subroutines. That turns out to be
awfully messy, because it requires the building of a separate mechanism
to manage the keyword namespace, where previously that wasn't an issue
because the keyword set was immutable. That's the motivation for reusing
the namespace mechanism that we've already got.

I've been putting off reading this thread for ages, sorry. Originally I
only read the first couple of messages, and then decided I needed to cool
off and then read it again to be sure of comprehending it correctly.
Initial thought is that I want us to explore multiple options for how
to make the namespaces work together. Sprout seems to have picked one
(very simple) way that they could work, and then bent everything else
to fit around it. I've got other ideas that may avoid the need for an
explicit feature flag.

-zefram

@p5pRT
Copy link
Author

p5pRT commented May 20, 2012

From zefram@fysh.org

Father Chrysostomos via RT wrote​:

If require is always a keyword

I am troubled by the implications of this sort of condition. What does
it mean to be a keyword? What is the alternative to it being a keyword?
I'm aiming for a system where the things that have historically
been builtin keywords are processed as mere names of subroutines,
and there's no strong distinction between keyword-like entities and
compile-time-resolved subroutines. If you end up needing to make such
a distinction then something's gone wrong.

So, which behaviour should \&CORE​::require have? It should probably be
the same as CORE​::require. And require???s fixed prototype should be
treated as a special case.

If you have a sub ref \&CORE​::require, it must behave as a pure subroutine
at runtime. If you call through the ref, you are calling a sub, and
there is no opportunity for its prototype or other compile-time magic
to affect the call. By contrast, if you refer to it without sigil, in a
compile-time-resolvable manner, then its prototype and other magic should
take full effect at compile time, regardless of exactly what name you
used to refer to it. In the case of require, the special interpretation
of barewords is part of that compile-time magic.

I was trying to come up with a model that would encompass all special
cases, such that there wouldn't be any special cases any more (they all
being CV-specific parsing rules), but I have failed in this particular case.

Where exactly does the problem arise? I see no categorical problem with
doing this for require.

-zefram

@p5pRT
Copy link
Author

p5pRT commented May 20, 2012

From zefram@fysh.org

Father Chrysostomos via RT wrote​:

On Mon May 14 14​:38​:10 2012, sprout wrote​:

Devel​::CallParser is the other option. It can return ops.

Correction​: the ops returned are treated as an argument list, so it is
in the same category as Devel​::Declare.

No, they're different. A Devel​::Declare parser doesn't get to return
ops at all, it only gets to rewrite the next part of the source, which
will then be parsed as an argument list. A Devel​::CallParser parser
returns ops that are used as the argument list. A PL_keyword_plugin
parser returns ops that are used as a complete expression.

Replacing the entersub op with something else is what
cv_set_call_checker is for.

Yes. It is very much intended that many subs with a D​:CP parser will
also have D​:CC magic to replace the entersub op. So D​:CP does not
effectively lack that part of the power of PL_keyword_plugin.

-zefram

@p5pRT
Copy link
Author

p5pRT commented May 20, 2012

From @cpansprout

On Sun May 20 04​:41​:46 2012, zefram@​fysh.org wrote​:

Eric Brine wrote​:

PS - Something to test​: What happens if one overrides C<elsif> using the
keyword plugin? Does it break C<if>?

I think the best way to do this (in the long run) is that the code to
parse the "if" syntax (which is magically attached to &if), when it sees
an identifier in a place that might be an "else" or "elsif", uses the
normal sub name lookup mechanism to decide what it means. Having resolved
the identifier to a sub ref, it checks whether this matches the &else or
&elsif that it knows about, and acts accordingly. &elsif is, of course,
a dummy sub, with parser magic that will just signal an error, because
"elsif" isn't allowed to be used on its own. The result is that you can
change the spelling of "elsif" by doing things like "*orif = \&elsif".
A user-added "if"-alike can use exactly the same mechanism, using either
the standard &elsif or its own dummy subs.

That�s a nice solution that solves all the problems I brought up..

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented May 20, 2012

From @cpansprout

On Sun May 20 04​:59​:39 2012, zefram@​fysh.org wrote​:

Eric Brine wrote​:

What is it we're suppose to use instead? Devel​::Declare?

The intention is to migrate Devel​::CallParser into the core. I'm actually
in the middle of that, on hold due to the freeze for 5.16. I got the
mechanism working in the core, but then discovered that one of the
standard procedural argument parsers doesn't actually match the core
yacc parser. So want to fix that before putting it into blead. Once D​:CP
is in the core, the PL_keyword_plugin will be obsolete and can be removed.

And then I can finish adding subs to the CORE​:: namespace.

Generally, the paradigm I'm aiming for is to merge the keyword namespace
with the subroutine namespace, and have special parsing and compilation
behaviour implemented as magic attached to (possibly dummy) subroutines.
What sprout is addressing in this thread is the issue of making
existing builtins play relatively nicely with subroutine definitions.
That's an issue because currently builtins are a separate namespace
from subroutines, looked up in different ways. The aim is to make
user-supplied keywords as interchangeable with builtins as possible.

The PL_keyword_plugin mechanism, to the extent that it supplies any
namespace behaviour at all, goes with that older concept of keywords
being a different class of entity from subroutines. That turns out to be
awfully messy, because it requires the building of a separate mechanism
to manage the keyword namespace, where previously that wasn't an issue
because the keyword set was immutable. That's the motivation for reusing
the namespace mechanism that we've already got.

I've been putting off reading this thread for ages, sorry. Originally I
only read the first couple of messages, and then decided I needed to cool
off and then read it again to be sure of comprehending it correctly.
Initial thought is that I want us to explore multiple options for how
to make the namespaces work together. Sprout seems to have picked one
(very simple) way that they could work, and then bent everything else
to fit around it. I've got other ideas that may avoid the need for an
explicit feature flag.

I�d love to hear them. What I�ve come up with does have a few rough
edges that I�ve been trying to iron out. And �use feature� doesn�t
really fit into the scheme yet.

I�m not so certain we can eliminate the keyword category altogether.
Many constructs parse differently depending on whether a word is a
keyword. Three examples​:

� Even in the presence of a sub �foo�, a package �Foo� will cause �foo
Foo� to be parsed as a method call. Not so with �chr Foo�.
â�¢ foo'bar'x3 is equivalent to foo​::bar​::x3. print'bar'x3 is equivalent
to print 'barbarbar';
� �require foo� implicitly quotes foo (adding .pm as well). �require
time� is a version check guaranteed to fail.

One idea I�ve had, which I don�t like very much, is to create a pragma
that controls the current set of keywords, which keywords delegate to
the CORE​:: namespace by default. Any keywords in the â��current setâ�� are
treated specially by the parser.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented May 20, 2012

From @cpansprout

On Sun May 20 05​:09​:10 2012, zefram@​fysh.org wrote​:

Father Chrysostomos via RT wrote​:

If require is always a keyword

I am troubled by the implications of this sort of condition. What
does
it mean to be a keyword?

To use the built-in parser for that keyword.

What is the alternative to it being a
keyword?

Being overridden, including the parsing.

In the current implementation, require is not overridable, at least
according to my definition, despite (and because of) what perlsub says.
The prototype cannot be overridden, so what we have is basically a core
function that can be *hooked*, but not overridden, via �use subs�. The
�override� is actually a callback function.

(The fact that an �overridden� require is compiled to an entersub op is
besides the point. The sub�s call checker doesn�t get to control
things. Actually, it�s very buggy.)

There is currently an ugly parser hack that makes �require� and
â��CORE​::requireâ�� behave differently, in that the latter bypasses callbacks.

So we have a single core function that behaves differently depending on
whether it is prefixed with its namespace.

I'm aiming for a system where the things that have historically
been builtin keywords are processed as mere names of subroutines,
and there's no strong distinction between keyword-like entities and
compile-time-resolved subroutines. If you end up needing to make such
a distinction then something's gone wrong.

So, which behaviour should \&CORE​::require have? It should probably
be
the same as CORE​::require. And require???s fixed prototype should be
treated as a special case.

If you have a sub ref \&CORE​::require, it must behave as a pure
subroutine
at runtime. If you call through the ref, you are calling a sub, and
there is no opportunity for its prototype or other compile-time magic
to affect the call. By contrast, if you refer to it without sigil, in
a
compile-time-resolvable manner, then its prototype and other magic
should
take full effect at compile time, regardless of exactly what name you
used to refer to it.

I was using \& to refer to it, in an attempt to clarify that I was
referring to the actual CV, not the current â��CORE​::â�� parser hack, nor
the keyword as parsed by Perl_keyword.

What I was trying to ask was​: Should an inlined CORE​::require CV
respect callbacks, the way the built-in function does?

In the case of require, the special
interpretation
of barewords is part of that compile-time magic.

I was trying to come up with a model that would encompass all special
cases, such that there wouldn't be any special cases any more (they
all
being CV-specific parsing rules), but I have failed in this
particular case.

Where exactly does the problem arise? I see no categorical problem
with
doing this for require.

As I mentioned above, it�s all about the discrepancy between �require�
and â��CORE​::requireâ��.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented May 20, 2012

From zefram@fysh.org

Father Chrysostomos via RT wrote​:

On Sun May 20 05​:09​:10 2012, zefram@​fysh.org wrote​:

What does it mean to be a keyword?

To use the built-in parser for that keyword.

This shouldn't be distinguishable from using an appropriate custom parser
that a user can attach to an arbitrary sub. Going to need more detail
if you're maintaining a distinction here.

There is currently an ugly parser hack that makes "require" and
"CORE​::require" behave differently, in that the latter bypasses callbacks.

I think here you're talking about the difference that arises if a
sub CORE​::GLOBAL​::require is defined. This is not a problem to my
model. It's only a problem if you mistakenly suppose that require and
CORE​::require must be the same thing, which, for exactly this reason,
they're patently not.

As it is, "CORE​::require", used without sigil, always refers to the
baseline builtin behaviour. Its behaviour is not affected by any
CORE​::GLOBAL​::require. &CORE​::require should exhibit the same behaviour.
So your later clearer question​:

What I was trying to ask was​: Should an inlined CORE​::require CV
respect callbacks, the way the built-in function does?

(supposing that by "callbacks" you're referring to the CORE​::GLOBAL​::
mechanism) has a very simple answer​: no, &CORE​::require should not obey
CORE​::GLOBAL​::require.

This also immediately leads us to the blindingly obvious realisation
that unqualified "require" by default *does not* refer to CORE​::require.
It refers to something else whose behaviour is derived from CORE​::require
and CORE​::GLOBAL​::require, and in particular has compile-time magic that
looks at whether a CORE​::GLOBAL​::require has been defined. This something
else doesn't currently have a name. I've been privately thinking of it
as CORE​::DEFAULT​::require for some months, but I'm totally flexible on
what name we use to reify it. Anyway, the point is we *should* reify it,
we should explicitly distinguish between it and CORE​::require, and we
should not get confused about having multiple entities with "require"
in their name.

Same goes for everything that's currently subject to CORE​::GLOBAL​::.

Is this the problem you were referring to? If you meant something else,
please explain further.

-zefram

@p5pRT
Copy link
Author

p5pRT commented May 21, 2012

From @cpansprout

On Sun May 20 15​:11​:05 2012, zefram@​fysh.org wrote​:

Father Chrysostomos via RT wrote​:

On Sun May 20 05​:09​:10 2012, zefram@​fysh.org wrote​:

What does it mean to be a keyword?

To use the built-in parser for that keyword.

This shouldn't be distinguishable from using an appropriate custom parser
that a user can attach to an arbitrary sub. Going to need more detail
if you're maintaining a distinction here.

There is currently an ugly parser hack that makes "require" and
"CORE​::require" behave differently, in that the latter bypasses
callbacks.

I think here you're talking about the difference that arises if a
sub CORE​::GLOBAL​::require is defined. This is not a problem to my
model. It's only a problem if you mistakenly suppose that require and
CORE​::require must be the same thing, which, for exactly this reason,
they're patently not.

As it is, "CORE​::require", used without sigil, always refers to the
baseline builtin behaviour. Its behaviour is not affected by any
CORE​::GLOBAL​::require. &CORE​::require should exhibit the same behaviour.
So your later clearer question​:

What I was trying to ask was​: Should an inlined CORE​::require CV
respect callbacks, the way the built-in function does?

(supposing that by "callbacks" you're referring to the CORE​::GLOBAL​::
mechanism)

I�m referring to that and �use subs�, as used by require, glob, do, qx
and the diamond operator.

has a very simple answer​: no, &CORE​::require should not obey
CORE​::GLOBAL​::require.

This also immediately leads us to the blindingly obvious realisation
that unqualified "require" by default *does not* refer to CORE​::require.
It refers to something else whose behaviour is derived from CORE​::require
and CORE​::GLOBAL​::require, and in particular has compile-time magic that
looks at whether a CORE​::GLOBAL​::require has been defined. This something
else doesn't currently have a name. I've been privately thinking of it
as CORE​::DEFAULT​::require for some months, but I'm totally flexible on
what name we use to reify it. Anyway, the point is we *should* reify it,
we should explicitly distinguish between it and CORE​::require, and we
should not get confused about having multiple entities with "require"
in their name.

Even if we don�t reify it (and I don�t see the practical application of
its reification, though I am not suggesting it is not a good idea), at
least you have given me a way to explain myself.

Same goes for everything that's currently subject to CORE​::GLOBAL​::.

Is this the problem you were referring to? If you meant something else,
please explain further.

I presume you mean that the parser invokes CORE​::DEFAULT​::* to decide
how to handle a word like �require�.

For most built-in functions, CORE​::DEFAULT​::foo simply delegates to an
override (use subs or CORE​::GLOBAL​::) or to CORE​::foo.

CORE​::DEFAULT​::require delegates to CORE​::require in the absence of an
override. But when there is an override it does its own parsing,
bypassing the override�s call checker.

CORE​::DEFAULT​::qx delegates to CORE​::qx. And then CORE​::qx invokes a
readpipe override, bypassing its call checker.

$ ./perl -Ilib -e 'use subs "readpipe"; sub readpipe{warn "called"}
CORE​::qx//'
called at -e line 1.

It used to be that CORE​::glob would invoke CORE​::GLOBAL​::glob, but I
�fixed� that in 5.16. I�m not sure whether the current situation is
much better, but at least it DWIMs. I effectively moved the invocation
of CORE​::GLOBAL​::glob from CORE​::glob, where it was before, to
CORE​::DEFAULT​::glob.

So we have things in CORE​:: that look at CORE​::GLOBAL. Thatâ��s why I came
up with the word �callback� to describe this oddity. Hence, the
CORE​::DEFAULT idea never occurred to me.

That�s the discrepancy I was trying to describe. We really have quite a
collection of different behaviours here with regard to CORE​::GLOBAL.

(In all those cases where I have talked about bypassing the call checker
of an override, it is not actually bypassed, resulting in very strange
bugs, such as �too many arguments� and �not enough arguments� errors
from the same functional call.)

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented May 21, 2012

From zefram@fysh.org

Father Chrysostomos via RT wrote​:

Even if we don't reify it (and I don't see the practical application of
its reification,

Obvious practical application is to be able to get the default behaviour
under a different name. "*demand = \&CORE​::DEFAULT​::require".

I presume you mean that the parser invokes CORE​::DEFAULT​::* to decide
how to handle a word like "require".

Yes.

CORE​::DEFAULT​::require delegates to CORE​::require in the absence of an
override. But when there is an override it does its own parsing,
bypassing the override's call checker.

Right, the complication is that it isn't a *complete* delegation to
CORE​::GLOBAL​::require.

That's the discrepancy I was trying to describe. We really have quite a
collection of different behaviours here with regard to CORE​::GLOBAL.

Yes, and we must maintain all, or at least most, of those oddities.
We certainly can't start requiring CORE​::GLOBAL​::require overrides to
supply their own parser magic. The core-supplied CORE​::require and
CORE​::DEFAULT​::require, however, must both have the parser magic built in.

(In all those cases where I have talked about bypassing the call checker
of an override, it is not actually bypassed, resulting in very strange
bugs, such as "too many arguments" and "not enough arguments" errors
from the same functional call.)

This behaviour is up for negotiation. I think it makes most sense
that the override's check-time magic *does* apply to a call generated
through the override mechanism. The override function should have the
opportunity to inline itself.

-zefram

@p5pRT
Copy link
Author

p5pRT commented May 21, 2012

From zefram@fysh.org

Father Chrysostomos via RT wrote​:

I'd love to hear them. What I've come up with does have a few rough
edges that I've been trying to iron out.

My basic concept is that the keyword-style name lookup searches through
a path-like sequence of namespaces (~= packages). By default you get
lookup in CORE​::DEFAULT followed by standard sub name lookup. To override
a core keyword you should be able to stick some other namespace on the
front of the path, which provides the override.

Where we currently have feature flags that make additional keywords
available, such as feature "switch", the "use feature" directive needs
to add another package into the search path. For example, "given" and
"when" *won't* be in CORE​::DEFAULT, they'll be in CORE​::SWITCH.

You'd be able to completely replace the default set of keywords by
setting up a custom package and putting that into the path *in place of*
CORE​::DEFAULT. So, for example, you can have "if" unbound, rather than
merely overridden. For the ultimate purist position, you import specific
CVs from CORE​::DEFAULT into your current package (or lexical namespace)
and then *remove* CORE​::DEFAULT from the path. You can operate with
a completely empty path as long as you've got the essential facilities
available through standard sub lookup.

Your "overrides" feature roughly corresponds to putting CORE​::DEFAULT
*after* standard sub lookup in the search path. Not sure whether it's
useful to support that, in the absence of backcompat requirement.

* foo'bar'x3 is equivalent to foo​::bar​::x3. print'bar'x3 is equivalent
to print 'barbarbar';

Ooh, interesting difference. This is quite similar to hov "s​:" is treated
as the start of a substitution expression, whereas "x​:" is a label.
I think this sort of special parsing behaviour ought to be a flag tied
to the CV for the keyword-like operator. Probably in the mg_private
field of the call-parser magic.

* "require foo" implicitly quotes foo (adding .pm as well). "require
time" is a version check guaranteed to fail.

Yow. We might want to remove that one.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Jun 1, 2012

From @rjbs

* Nicholas Clark <nick@​ccl4.org> [2012-04-24T03​:39​:11]

On Mon, Apr 23, 2012 at 03​:13​:39PM -0700, Father Chrysostomos via RT wrote​:

On Mon Apr 23 14​:03​:27 2012, nicholas wrote​:

The intent of the changes appears to be to retain the 5.003 and earlier
behaviour on what gets assigned for each construction, but change the
loop behaviour to terminate on undefined rather than simply falsehood for
the common simple cases​:

while \(OP \.\.\.\)

and

while \($var = OP \.\.\.\)

Except that while($var = each %h) implies defined(), but while(each %h)
does not. So something got screwed up. :-)

Yes. I *thought* that question was about while(each %h) [not] assigning to
$_, but I missed the [not] using defined.

Pretty sure that the intent was that the intent at the time was to change it
to use defined. And I'd guess that it was missed because it's not the same
opcode structure.

So that's a bug?

That is a bug.

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Jun 1, 2012

From @rjbs

* Ricardo Signes <perl.p5p@​rjbs.manxome.org> [2012-05-31T22​:38​:28]

So that's a bug?

That is a bug.

Well, *was* a bug. :)

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

From @cpansprout

On Mon May 21 05​:00​:56 2012, zefram@​fysh.org wrote​:

Father Chrysostomos via RT wrote​:

I'd love to hear them. What I've come up with does have a few rough
edges that I've been trying to iron out.

My basic concept is that the keyword-style name lookup searches through
a path-like sequence of namespaces (~= packages). By default you get
lookup in CORE​::DEFAULT followed by standard sub name lookup. To override
a core keyword you should be able to stick some other namespace on the
front of the path, which provides the override.

Where we currently have feature flags that make additional keywords
available, such as feature "switch", the "use feature" directive needs
to add another package into the search path. For example, "given" and
"when" *won't* be in CORE​::DEFAULT, they'll be in CORE​::SWITCH.

You'd be able to completely replace the default set of keywords by
setting up a custom package and putting that into the path *in place of*
CORE​::DEFAULT. So, for example, you can have "if" unbound, rather than
merely overridden. For the ultimate purist position, you import specific
CVs from CORE​::DEFAULT into your current package (or lexical namespace)
and then *remove* CORE​::DEFAULT from the path. You can operate with
a completely empty path as long as you've got the essential facilities
available through standard sub lookup.

How exactly would that work in practice? A pragma? �use keywords
"CORE​::DEFAULT", __PACKAGE__â��?

And where would lexical subs fit into that scheme? Should CORE​::glob
fallback to a lexical glob, the way it falls back to a package sub (I
hope not)?

Your "overrides" feature roughly corresponds to putting CORE​::DEFAULT
*after* standard sub lookup in the search path. Not sure whether it's
useful to support that, in the absence of backcompat requirement.

* foo'bar'x3 is equivalent to foo​::bar​::x3. print'bar'x3 is equivalent
to print 'barbarbar';

Ooh, interesting difference. This is quite similar to hov "s​:" is treated
as the start of a substitution expression, whereas "x​:" is a label.
I think this sort of special parsing behaviour ought to be a flag tied
to the CV for the keyword-like operator. Probably in the mg_private
field of the call-parser magic.

What would the public API for that be? CvKEYWORD_on?

* "require foo" implicitly quotes foo (adding .pm as well). "require
time" is a version check guaranteed to fail.

Yow. We might want to remove that one.

But we mustn�t break �require if ...�.

On the other hand, I think require VERSION should be a *syntactic*, not
run-time, special case.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

From [Unknown Contact. See original ticket]

On Mon May 21 05​:00​:56 2012, zefram@​fysh.org wrote​:

Father Chrysostomos via RT wrote​:

I'd love to hear them. What I've come up with does have a few rough
edges that I've been trying to iron out.

My basic concept is that the keyword-style name lookup searches through
a path-like sequence of namespaces (~= packages). By default you get
lookup in CORE​::DEFAULT followed by standard sub name lookup. To override
a core keyword you should be able to stick some other namespace on the
front of the path, which provides the override.

Where we currently have feature flags that make additional keywords
available, such as feature "switch", the "use feature" directive needs
to add another package into the search path. For example, "given" and
"when" *won't* be in CORE​::DEFAULT, they'll be in CORE​::SWITCH.

You'd be able to completely replace the default set of keywords by
setting up a custom package and putting that into the path *in place of*
CORE​::DEFAULT. So, for example, you can have "if" unbound, rather than
merely overridden. For the ultimate purist position, you import specific
CVs from CORE​::DEFAULT into your current package (or lexical namespace)
and then *remove* CORE​::DEFAULT from the path. You can operate with
a completely empty path as long as you've got the essential facilities
available through standard sub lookup.

How exactly would that work in practice? A pragma? �use keywords
"CORE​::DEFAULT", __PACKAGE__â��?

And where would lexical subs fit into that scheme? Should CORE​::glob
fallback to a lexical glob, the way it falls back to a package sub (I
hope not)?

Your "overrides" feature roughly corresponds to putting CORE​::DEFAULT
*after* standard sub lookup in the search path. Not sure whether it's
useful to support that, in the absence of backcompat requirement.

* foo'bar'x3 is equivalent to foo​::bar​::x3. print'bar'x3 is equivalent
to print 'barbarbar';

Ooh, interesting difference. This is quite similar to hov "s​:" is treated
as the start of a substitution expression, whereas "x​:" is a label.
I think this sort of special parsing behaviour ought to be a flag tied
to the CV for the keyword-like operator. Probably in the mg_private
field of the call-parser magic.

What would the public API for that be? CvKEYWORD_on?

* "require foo" implicitly quotes foo (adding .pm as well). "require
time" is a version check guaranteed to fail.

Yow. We might want to remove that one.

But we mustn�t break �require if ...�.

On the other hand, I think require VERSION should be a *syntactic*, not
run-time, special case.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jul 5, 2012

From @cpansprout

On Wed Jul 04 14​:24​:15 2012, sprout wrote​:

On Mon May 21 05​:00​:56 2012, zefram@​fysh.org wrote​:

Father Chrysostomos via RT wrote​:

I'd love to hear them. What I've come up with does have a few rough
edges that I've been trying to iron out.

My basic concept is that the keyword-style name lookup searches through
a path-like sequence of namespaces (~= packages). By default you get
lookup in CORE​::DEFAULT followed by standard sub name lookup. To
override
a core keyword you should be able to stick some other namespace on the
front of the path, which provides the override.

Where we currently have feature flags that make additional keywords
available, such as feature "switch", the "use feature" directive needs
to add another package into the search path. For example, "given" and
"when" *won't* be in CORE​::DEFAULT, they'll be in CORE​::SWITCH.

You'd be able to completely replace the default set of keywords by
setting up a custom package and putting that into the path *in place of*
CORE​::DEFAULT. So, for example, you can have "if" unbound, rather than
merely overridden. For the ultimate purist position, you import
specific
CVs from CORE​::DEFAULT into your current package (or lexical namespace)
and then *remove* CORE​::DEFAULT from the path. You can operate with
a completely empty path as long as you've got the essential facilities
available through standard sub lookup.

How exactly would that work in practice? A pragma? �use keywords
"CORE​::DEFAULT", __PACKAGE__â��?

And where would lexical subs fit into that scheme? Should CORE​::glob
fallback to a lexical glob, the way it falls back to a package sub (I
hope not)?

I am leaning toward letting lexical subs override anything and be
completely separate from the keyword namespaces, just as my $AUTOLOAD
shadows the package variable and never participates in autoloading.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jul 5, 2012

From [Unknown Contact. See original ticket]

On Wed Jul 04 14​:24​:15 2012, sprout wrote​:

On Mon May 21 05​:00​:56 2012, zefram@​fysh.org wrote​:

Father Chrysostomos via RT wrote​:

I'd love to hear them. What I've come up with does have a few rough
edges that I've been trying to iron out.

My basic concept is that the keyword-style name lookup searches through
a path-like sequence of namespaces (~= packages). By default you get
lookup in CORE​::DEFAULT followed by standard sub name lookup. To
override
a core keyword you should be able to stick some other namespace on the
front of the path, which provides the override.

Where we currently have feature flags that make additional keywords
available, such as feature "switch", the "use feature" directive needs
to add another package into the search path. For example, "given" and
"when" *won't* be in CORE​::DEFAULT, they'll be in CORE​::SWITCH.

You'd be able to completely replace the default set of keywords by
setting up a custom package and putting that into the path *in place of*
CORE​::DEFAULT. So, for example, you can have "if" unbound, rather than
merely overridden. For the ultimate purist position, you import
specific
CVs from CORE​::DEFAULT into your current package (or lexical namespace)
and then *remove* CORE​::DEFAULT from the path. You can operate with
a completely empty path as long as you've got the essential facilities
available through standard sub lookup.

How exactly would that work in practice? A pragma? �use keywords
"CORE​::DEFAULT", __PACKAGE__â��?

And where would lexical subs fit into that scheme? Should CORE​::glob
fallback to a lexical glob, the way it falls back to a package sub (I
hope not)?

I am leaning toward letting lexical subs override anything and be
completely separate from the keyword namespaces, just as my $AUTOLOAD
shadows the package variable and never participates in autoloading.

--

Father Chrysostomos

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants