xsawyerx / guacamole

Guacamole is a parser toolkit for Standard Perl. It provides fully static BNF-based parsing capability to a reasonable subset of Perl.
https://metacpan.org/pod/Guacamole
20 stars 8 forks source link

glob vs package #3

Closed vickenty closed 4 years ago

vickenty commented 8 years ago

A method call on a string is dynamically dispatched. If a filehandle with the given name exists, call will be dispatched to it, otherwise perl will try package name. This does not depend on the method name called, just on the value of the object.

All these are affected:

my $foobar = "Foo::Bar";
$foobar->say();
Foo::Bar->say();
Foo::Bar::->say();
"Foo::Bar"->say();

Behaviour of the code is changed iff a filehandle is assigned to *Foo::Bar, either via call to open or via assignment operator:

open(*Foo::Bar, ">foo");
*Foo::Bar = $filehandle;

Funnily enough, blessing something into "Foo::Bar" undoes the effect:

use strict;
*Foo::Bar = *STDOUT;
my $foobar = "Foo::Bar";
$foobar->say("Hi");
bless {}, "Foo::Bar";
$foobar->say("Hi"); 

outputs:

Hi
Can't locate object method "say" via package "Foo::Bar" at test2.pl line 6.

It seems that this behaviour is fairly new: under 5.18.4 and 5.20.3 the output is different:

Hi
Hi

In the end, this behaviour seems to be baked pretty deep into the interpreter and unavoidable using just syntactic changes.

xsawyerx commented 8 years ago

Off the ticket I think we agreed with the syntax:

(\*STDOUT)->method()?

No?

vickenty commented 8 years ago

We agreed that (\*STDOUT)->method() makes an unambiguous reference to a file handle. But STDOUT::->method() still refers to a file handle and not a package, and there is no around that, unfortunately.

xsawyerx commented 8 years ago

I think what we end up with is (\*STDOUT)->method();:

  1. Only works on file handles.
  2. Only a run-time error.

That means that while STDOUT::->method() or binmode *STDOUT, 'UTF_8' or binmode *main::STDOUT, 'UTF-8' or even binmode *::STDOUT, 'UTF-8' will all work, by using (\*STDOUT)->method(), we assure that we know it's a file handle (or will crash at run-time).

xsawyerx commented 4 years ago

Reviewing it now, I want to break this to two different problems:

  1. Disambiguating class name from a function within a class:
Foo::Bar->new(); # Foo.pm's Bar() or Foo::Bar's new()?

This can be fixed by the rule that all user-provided subroutines must include parenthesis:

Foo::Bar->new();   # always Foo::Bar's new() - "Foo::Bar" is a literal namespace string
Foo::Bar()->new(); # always Foo's Bar() - Should "Foo" be a namespace or should "Foo::Bar()" be a literal function name?
  1. What perl understands it needs to do:

If it's a filehandle, it calls the filehandle. If not, it tries a function or a class name. In either case, who cares. We're not running it, only parsing it.

I think we can close this issue.