Creator named like class

A

Anno Siegel

It is possible to use the name of a class also as the name of a subroutine,
which may create objects of that class. To fix the ideas, assume a class

package Race::Horse;

sub new {
my $class = shift;
bless {
name => shift,
# ...
}, $class;
}

# more methods...

It is now possible to define

sub Race::Horse {
Race::Horse->new( @_);
}

Instead of the always slightly cumbersome

my $horse = Race::Horse->new( 'Stewball');

we can now say

my $horse = Race::Horse( 'Stewball');

I find this creator intuitive, and I'm thinking of equipping two or
three CPAN modules of mine that way.

Of course, there are problems. Aren't there always?

First off, it's thin ice that it works at all (if you know what I mean).
In sub Race::Hose, "Race::Horse->new..." is ambiguous syntax. What is
left of the arrow can be any expression, so Perl would be in its rights
to read it as "Race::Horse()->new..." and plunge into deep recursion.
It Does What I Mean, but I don't think the feature is documented.
I don't think it is likely to go away. That would break old code.

Another problem is name space violation. Race::Horse defines a sub
in package Race, where it has no business defining things. Of course,
there is no rule that explicitly forbids it, but it might be considered
poor (even rude) style. Actual collisions are improbable, however.
If package Race contains subs, their names are likely to be lower case.

A favorable point is that the additional creator doesn't interfere with
the traditional ->new (or any other creator that might be used). One
can replace the other anywhere, and no-one is forced to use the new
style.

Anno
 
J

Jaap Karssenberg

On 16 Jul 2004 16:57:21 GMT Anno Siegel wrote:
: First off, it's thin ice that it works at all (if you know what I
: mean). In sub Race::Hose, "Race::Horse->new..." is ambiguous syntax.
: What is left of the arrow can be any expression, so Perl would be in
: its rights to read it as "Race::Horse()->new..." and plunge into deep
: recursion. It Does What I Mean, but I don't think the feature is
: documented. I don't think it is likely to go away. That would break
: old code.

I think you can be pretty sure that in the "Race::Horse->new" syntax
"Race::Horse" is considered a class name in any current and future
version of perl5. It is not documented explicitly AFAIK but it is used
as in example code in several perl manpages.

: Another problem is name space violation. Race::Horse defines a sub
: in package Race, where it has no business defining things. Of course,
: there is no rule that explicitly forbids it, but it might be
: considered poor (even rude) style. Actual collisions are improbable,
: however. If package Race contains subs, their names are likely to be
: lower case.

For this reason I would advise against using this construct in modules
that are intended for CPAN. At the very least check the existence of the
sub before defining you own. But thats no real insurance.

*Race::Horse = sub { # define constructor if sub doesn't allready exist
... code ...
} unless *Race::Horse{CODE} ;
 
A

Anno Siegel

Jaap Karssenberg said:
On 16 Jul 2004 16:57:21 GMT Anno Siegel wrote:
: First off, it's thin ice that it works at all (if you know what I
: mean). In sub Race::Hose, "Race::Horse->new..." is ambiguous syntax.
: What is left of the arrow can be any expression, so Perl would be in
: its rights to read it as "Race::Horse()->new..." and plunge into deep
: recursion. It Does What I Mean, but I don't think the feature is
: documented. I don't think it is likely to go away. That would break
: old code.

I think you can be pretty sure that in the "Race::Horse->new" syntax
"Race::Horse" is considered a class name in any current and future
version of perl5. It is not documented explicitly AFAIK but it is used
as in example code in several perl manpages.

It is also not true, if, at compile-time, Race::Horse is defined as
a sub. Example:

package Race::Horse;
sub new { bless {}, shift }

package Mickey::Mouse;
sub new { bless {}, shift }

my $x = Race::Horse->new; # swap
sub Race::Horse { 'Mickey::Mouse' } # swap

print ref $x, "\n";

This prints "Race::Horse", so the bare Race::Horse has been parsed as
Race::Horse a class name, as you say. But swap the indicated lines,
and it prints "Mickey::Mouse", so now it has been parsed as Race::Horse().

So the sub takes precedence, if defined at compile time. In

sub Race::Horse { Race::Horse->new( @_) }

the sub Race::Horse comes uncomfortably close to being defined at
compile time. Other ways of using a sub name inside a sub do result
in recursion, and that's the point I'm slightly worried about.
: Another problem is name space violation. Race::Horse defines a sub
: in package Race, where it has no business defining things. Of course,
: there is no rule that explicitly forbids it, but it might be
: considered poor (even rude) style. Actual collisions are improbable,
: however. If package Race contains subs, their names are likely to be
: lower case.

For this reason I would advise against using this construct in modules
that are intended for CPAN. At the very least check the existence of the
sub before defining you own. But thats no real insurance.

*Race::Horse = sub { # define constructor if sub doesn't allready exist
... code ...
} unless *Race::Horse{CODE} ;

Ohh... much too clever for its own good, I think :) It has quite some
surprise potential. If needed, I'd add a use-time option to switch it
off explicitly.

On the other hand, there is an ill-defined, but distinct, notion of
public and private name space on CPAN. As long as I'm in "my" name
space, I'll feel free to define what I please. Then again, I *am*
thinking of things like Music::Wurlitzer, where Music is an established
piece of public name space. I guess it should be optional in such
cases.

Anno
 
B

Brian McCauley

Jaap Karssenberg said:
On 16 Jul 2004 16:57:21 GMT Anno Siegel wrote:
: Another problem is name space violation. Race::Horse defines a sub
: in package Race, where it has no business defining things. Of course,
: there is no rule that explicitly forbids it, but it might be
: considered poor (even rude) style. Actual collisions are improbable,
: however. If package Race contains subs, their names are likely to be
: lower case.

For this reason I would advise against using this construct in modules
that are intended for CPAN.

But the glob that coresponds to the Race::Horse package if not
*Race::Horse but *Race::Horse::. Hence, logically, if you want a
subroutine with the same name as the package this is &Race::Horse::
not &Race::Horse. This way there is no namespace polution. On the
other hand I prefer the model where constructors are classs methods in
the first place.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
A

Anno Siegel

Brian McCauley said:
But the glob that coresponds to the Race::Horse package if not
*Race::Horse but *Race::Horse::. Hence, logically, if you want a
subroutine with the same name as the package this is &Race::Horse::
not &Race::Horse. This way there is no namespace polution.

....but also no way of calling the sub. Or is there?
On the
other hand I prefer the model where constructors are classs methods in
the first place.

I'm afraid the whole plan is what we call a "Schnapsidee" in German
(though no booze was involved in bringing it up). I overlooked the
simple fact that after defining "sub Race::Horse" the class name
Race::Horse cannot be used as a barewword anymore. That means that
any class method in Race::Horse, including ->new, must now be called
through a string literal:

my $x = 'Race::Horse'->new( ...);

That's not a price I want to pay for a mere esthetical improvement.
I'd say sorry for bringing it up, but the discussion has helped me
realize the idea isn't worth much, so I won't.

Anno
 
B

Brian McCauley

Brian McCauley said:
[...] logically, if you want a
subroutine with the same name as the package this is &Race::Horse::
not &Race::Horse. This way there is no namespace polution.

...but also no way of calling the sub. Or is there?

Actually you can say 'Race::Horse::'->().

You can even do this under strict, although arguably you shouldn't be
able to. Strict refs doesn't seem to apply to symrefs that are
resolved (or optomised away) at compile time but this is no something
I'd want to rely on.
I'm afraid the whole plan is what we call a "Schnapsidee" in German
(though no booze was involved in bringing it up).
I'd say sorry for bringing it up, but the discussion has helped me
realize the idea isn't worth much, so I won't.

Still, it was fun wasn't it? :)

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
L

Lukas Mai

Brian McCauley schrob:
[...]
Actually you can say 'Race::Horse::'->().
You can even do this under strict, although arguably you shouldn't be
able to. Strict refs doesn't seem to apply to symrefs that are
resolved (or optomised away) at compile time but this is no something
I'd want to rely on.

It gets weirder:

$ perl -Mstrict -e '"foo"->{bar} = 42'
Global symbol "%foo" requires explicit package name at -e line 1.

$ perl -Mstrict -e 'our %foo; "foo"->{bar} = 42'
Variable "%foo" is not imported at -e line 1.
Global symbol "%foo" requires explicit package name at -e line 1.

What?

$ perl -Mstrict -le '"::foo"->{bar} = 42; print "::foo"->{bar}'
42

$ perl -MO=Deparse -Mstrict -e '"::foo"->{bar} = 42;\
print "::foo"->{bar}'
use strict 'refs';
$foo{'bar'} = 42;
print $foo{'bar'};
-e syntax OK

$ perl -Mstrict -e '${"::foo"}{bar} = 42;'
Can't use string ("::foo") as a HASH ref while "strict refs" in use at
-e line 1.

I don't understand what's going on here. Apparently string literals are
exempt from use strict "refs", but only when using -> to dereference
them. And use strict "vars" doesn't let me declare them with our(), but
an explicit package name works.

Confused, Lukas
 
T

Tassilo v. Parseval

Also sprach Lukas Mai:
Brian McCauley schrob:
[...]
Actually you can say 'Race::Horse::'->().
You can even do this under strict, although arguably you shouldn't be
able to. Strict refs doesn't seem to apply to symrefs that are
resolved (or optomised away) at compile time but this is no something
I'd want to rely on.

It gets weirder:

$ perl -Mstrict -e '"foo"->{bar} = 42'
Global symbol "%foo" requires explicit package name at -e line 1.

It looks as though perl treats

"foo"->{bar}

as

*foo->{bar}

which follows the ordinary logic of accessing the HASH slot of a
typeglob in a similar way to doing

*foo = \%hash;
$ perl -Mstrict -e 'our %foo; "foo"->{bar} = 42'
Variable "%foo" is not imported at -e line 1.
Global symbol "%foo" requires explicit package name at -e line 1.

What?

This I don't understand either. There seems to be a minor but important
difference in the optree of the above two:

our %foo; "foo"->{bar}

gives:

...
SVOP (0x8149470) gv GV (0x82161a4) *<none>::foo
^^^^^^^^^^^^ !!

compared to

our %foo; *foo->{bar};

# or

our %foo; "::foo"->{bar};

resulting in

...
SVOP (0x8149468) gv GV (0x8148098) *foo
^^^^
$ perl -Mstrict -le '"::foo"->{bar} = 42; print "::foo"->{bar}'
42

$ perl -MO=Deparse -Mstrict -e '"::foo"->{bar} = 42;\
print "::foo"->{bar}'
use strict 'refs';
$foo{'bar'} = 42;
print $foo{'bar'};
-e syntax OK

$ perl -Mstrict -e '${"::foo"}{bar} = 42;'
Can't use string ("::foo") as a HASH ref while "strict refs" in use at
-e line 1.

I don't understand what's going on here. Apparently string literals are
exempt from use strict "refs", but only when using -> to dereference
them. And use strict "vars" doesn't let me declare them with our(), but
an explicit package name works.

It looks as though perl can be confused enough to get the package of a
global variable wrong. A cursory scan through the source suggests that
thus bug occurs somewhere in Perl_gv_fetchpv which doesn't try hard
enough to figure out the namespace of a global under certain rare
circumstances.

Tassilo
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top