Creator named like class

Discussion in 'Perl Misc' started by Anno Siegel, Jul 16, 2004.

  1. Anno Siegel

    Anno Siegel Guest

    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
     
    Anno Siegel, Jul 16, 2004
    #1
    1. Advertising

  2. 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} ;

    --
    ) ( Jaap Karssenberg || Pardus [Larus] | |0| |
    : : http://pardus-larus.student.utwente.nl/~pardus | | |0|
    ) \ / ( |0|0|0|
    ",.*'*.," Proud owner of "Perl6 Essentials" 1st edition :) wannabe
     
    Jaap Karssenberg, Jul 16, 2004
    #2
    1. Advertising

  3. Anno Siegel

    Anno Siegel Guest

    Jaap Karssenberg <> wrote in comp.lang.perl.misc:
    > 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
     
    Anno Siegel, Jul 17, 2004
    #3
  4. Jaap Karssenberg <> writes:

    > 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\\
     
    Brian McCauley, Jul 17, 2004
    #4
  5. Anno Siegel

    Anno Siegel Guest

    Brian McCauley <> wrote in comp.lang.perl.misc:
    > Jaap Karssenberg <> writes:
    >
    > > 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.


    ....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
     
    Anno Siegel, Jul 17, 2004
    #5
  6. -berlin.de (Anno Siegel) writes:

    > Brian McCauley <> wrote in comp.lang.perl.misc:
    > > [...] 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\\
     
    Brian McCauley, Jul 17, 2004
    #6
  7. Anno Siegel

    Lukas Mai Guest

    use strict; and string literals (was: Creator named like class)

    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
    --
    main(int v,char**c){c?main(atoi(c[--v]),0),
    puts(""):putchar((v/2&&main(v/2,0),48|v&1));}
     
    Lukas Mai, Jul 17, 2004
    #7
  8. Re: use strict; and string literals (was: Creator named like class)

    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
    --
    $_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
    pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
    $_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval
     
    Tassilo v. Parseval, Jul 17, 2004
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Max-Ph. Blickenstorfer

    access creator of class

    Max-Ph. Blickenstorfer, Jan 7, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    486
    Max-Ph. Blickenstorfer
    Jan 7, 2004
  2. Patrick Olurotimi Ige

    Huge security hole in .NET: Java creator

    Patrick Olurotimi Ige, Feb 7, 2005, in forum: ASP .Net
    Replies:
    4
    Views:
    365
    Kevin Spencer
    Feb 7, 2005
  3. E11
    Replies:
    1
    Views:
    4,955
    Thomas Weidenfeller
    Oct 12, 2005
  4. Henrik
    Replies:
    5
    Views:
    531
    Paul Furman
    Jan 18, 2004
  5. Patrick Kowalzick
    Replies:
    5
    Views:
    512
    Patrick Kowalzick
    Mar 14, 2006
Loading...

Share This Page