Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re: More Macro work...out to export a definition to next-outer level?

by ikegami (Pope)
on Sep 30, 2010 at 06:09 UTC ( #862751=note: print w/ replies, xml ) Need Help??


in reply to More Macro work...out to export a definition to next-outer level?

class_vars was being called too late to be of any use.

Putting a BEGIN block around a sub definition is useless, as a sub definition doesn't generate code to execute.

Contrary to what you said, you weren't getting a syntax error, you were getting a strict error. Quite appropriate since you asked for it.

Solution:

BEGIN { package class_vars; use strict; use warnings; sub import { shift; my $pkg = caller; for my $var (@_) { eval(" package $pkg; use vars '\$$var'; sub $var { \$$var = \$_[1] if \@_ > 1; return \$$var; } "); } } $INC{'class_vars.pm'} = __FILE__; } { package MyPackage; use strict; use warnings; use class_vars qw( one two three ); sub init_one_from_three { $one=$three-2; } sub new { my $package=shift; my $parms=$_[0]; my $this={}; foreach(keys %$parms) { no strict 'refs'; $$_=$parms->{$_}; } bless $this, $package; } } { use strict; use warnings; my $p=new MyPackage({three => 3,}); $p->two(2); $p->init_one_from_three; printf "one=%d two=%d, three=%d\n", $p->one, $p->two, $p->three; }
one=1 two=2, three=3
The following simulates putting the module in its own file:
BEGIN { ... $INC{'class_vars.pm'} = __FILE__; }

Package declarations are lexically scoped. You had lots of needless package switching.

I left in the limit that class vars must be scalars.

You call them class vars, but then you initialise them when constructing an instance, and you access them via a class instance. They're not class variables at all. They're object attributes, and you're going the wrong way about creating a singleton.

Update: Adjust the value in %INC as per reply.


Comment on Re: More Macro work...out to export a definition to next-outer level?
Select or Download Code
Re^2: More Macro work...out to export a definition to next-outer level?
by Anonymous Monk on Sep 30, 2010 at 06:27 UTC
    $INC{'class_vars.pm'} = 1;
    Please use a filename instead of 1, like
    $INC{'class_vars.pm'} = __FILE__;
Re^2: More Macro work...out to export a definition to next-outer level?
by perl-diddler (Hermit) on Sep 30, 2010 at 08:42 UTC
    Sorry, you just lost me -- you used a magic spell above my level. ;-)

    In my previous example: #!/usr/bin/perl -w #use strict; use feature ':5.10'; BEGIN { sub instance_vars { my $pck=caller; foreach(@_) { eval "sub ${pck}::$_ { my \$p = shift; \$p->{$_} = \$_[0] if \@_; \$p->{$_}; }" } } } package MyPackage; *instance_vars=\&main::package_vars; { instance_vars( qw(one two three) ); sub new { my $package=shift; my $parms=$_[0]; my $this={}; foreach(%$parms) { $this->{$_}=$parms->{$_}; } bless $this, $package; } } package main; my $p=new MyPackage({three => 3,}); $p->two(2); printf "two=%d, three=%d\n",$p->two, $p->three; </code> I didn't have any reference to use or import.

    To invoke the code, I called a sub 'instance_vars', that was in a begin block. The reason the package statements are / were in the way they are is that the macros definitions are at the top of the file in 'main'.

    The way you are doing it may be the only way to do it, but it isn't close to as simple as the case for the 'instance' vars.

    You say that the above isn't satisfactory for 'singletons'. Why not? Aren't they global variables to each package that are initialized only once on the initial passthrough when the package is first read, and then retain their value as global variables in each package (or accessible via package::var) from without the package?

    The part where you put the classname.pm in the INC var likely prevents future 'use' statements from actually trying to find the file, I'd guess, and the 'use' statement does the same as: "package::import( qw(one two three) )"? It's workable, but I don't understand why something simple like I used for instance variables doesn't work.

    If putting a BEGIN block around a sub definition is useless, then how does this 'instance' var code work? It puts a sub definition in a BEGIN block which is then called in the code below. Also, the class_vars code *works* (with strict turned off, with warnings -- i.e. the variables being set in 'MyPackage' retain their values -- they aren't local but are treated as package variables, so I don't see how you can the subs don't work

    I think you are showing me an alternate way of doing what I'm doing, but I don't think it's answering my question -- which may have no good answer, i.e. the way you are doing it may be the only way -- I don't know.

    The 'sub' in main gets declared as a global as all named subs are, so in a BEGIN block or not, I think it is having the desired effect. The problem is adding an 'our' statement that is taken as a declarator for the rest of the block that the caller is in (not just in within the eval -- which is works for, but is ended when the eval ends and goes out of scope.

      That's lame! I edited the above, even previewed it, and resubmitted it with an inserted 'code' tag (it was missing one before the code, as you can see, it already had one after the code ;-/ ). But only the above version was stored and it seems I can't update it. Oh poo! Anyway, hopefully this version will stay with the code tag intact!
      #!/usr/bin/perl -w #use strict; use feature ':5.10'; BEGIN { sub instance_vars { my $pck=caller; foreach(@_) { eval "sub ${pck}::$_ { my \$p = shift; \$p->{$_} = \$_[0] if \@_; \$p->{$_}; }" } } } package MyPackage; *instance_vars=\&main::instance_vars; { instance_vars( qw(one two three) ); sub new { my $package=shift; my $parms=$_[0]; my $this={}; foreach(%$parms) { $this->{$_}=$parms->{$_}; } bless $this, $package; } } package MyPackagetwo; { our @ISA = qw (MyPackage); } package main; my $p=new MyPackagetwo({three => 3,}); $p->two(2); printf "two=%d, three=%d\n",$p->two, $p->three;

      You say that the above isn't satisfactory for 'singletons'.

      Because you're using two screens of fragile and complicated code to replace two lines of code.

      To invoke the code, I called a sub 'instance_vars', that was in a begin block.

      No, it's not in a BEGIN block. The sub's definition is in a BEGIN block, but I already indicates how that's useless.

      Aren't they global variables to each package that are initialized only once

      No, they're initialised by the constructor, any number of times.

      and then retain their value as global variables in each package (or accessible via package::var) from without the package?

      That may be, but you access them via method calls.

      I think you are showing me an alternate way of doing what I'm doing, but I don't think it's answering my question

      I did. Like I said, you called it too late. You only call class_vars after you try to compile the code that uses them. All I did was made a change to call it earlier.

        I think there's a confusion in terms. I'm using class var to mean global to the whole class and each instance of the class. My other routine is an instance_var which declares variables for each instance. For my globals, I'm trying to use the package variables referenced by 'our', that are global to the package. AFAIK, they are globals that come into creation when the package does, and if there is code defining them in the package, with an initializer, it gets executed once when that package loads.

        There shouldn't be multiple initializations

        As far as how I access them: I call them through method calls, meaning I call them through a blessed pointer which I throw away with the shift; Then I store or/and return the global variable passed in from the 'foreach' in '$_' (e.g. one two three), namely the global package variables byte those names.

        Does this clear anything up?

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://862751]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (9)
As of 2014-07-13 19:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (251 votes), past polls