qadwjoh has asked for the wisdom of the Perl Monks concerning the following question:

Is there any way to set up a variable like this
my $var; my $date; ... $var = "date $date"; ... $date = localtime; ... print $var;
where $date isn't set until after $var is set but before it's actually called?

A

Replies are listed 'Best First'.
Re: Evaluating variables when called
by Limbic~Region (Chancellor) on Mar 09, 2004 at 18:15 UTC
    qadwjoh,
    The answer(s) are yes. One use eval string which is typically frowned upon. The second would require you to tie a scalar. The 3rd option would be to use Interpolation and change your $var to a sub routine. The only reason for Interpolation is so that you can use it in a double quoted string.

    None of these answers does it exactly the way you want. Take a look:

    # Option 1 my $date = 'scalar localtime()'; print eval $date; # Option 2 package Current_Date_Stamp; sub TIESCALAR { bless {}, $_[0] } sub STORE { return 1 } sub FETCH { return scalar localtime() } package main; tie my $date, "Current_Date_Stamp"; print "The current date is $date\n"; # Option 3 use Interpolation date => sub {localtime()}; print "Today's date is $date{now}";
    Cheers - L~R
Re: Evaluating variables when called
by broquaint (Abbot) on Mar 09, 2004 at 18:18 UTC
    Since perl doesn't have lazy data natively this can get a little tricky and rather messy if dealing with lexicals, however ...
    my $var = q[date $date]; my $date = localtime; print eval qq["$var"]' __output__ date Tue Mar 9 18:11:43 2004
    But it's usually best to leave this sort of thing up to Interpolation or perhaps one of the templating modules.
    HTH

    _________
    broquaint

Re: Evaluating variables when called
by dragonchild (Archbishop) on Mar 09, 2004 at 18:17 UTC
    Yes, you can evaluate expressions whenever you want. For example, your snippet could be rewritten as:
    my $evaluatable = '$date'; my $date = localtime; my $var = eval "$evaluatable"; print "'$var'\n";

    I wouldn't recommend doing this, but it is feasible.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Evaluating variables when called
by Juerd (Abbot) on Mar 09, 2004 at 18:33 UTC

    Another way of interpolating simple scalars afterwards is s///ee:

    my $var; my $date; $var = 'date $date'; # single quotes! $date = localtime; $var =~ s/\$(\w+)/$$1/gee; print $var;

    Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

Re: Evaluating variables when called
by NetWallah (Canon) on Mar 09, 2004 at 18:55 UTC
    Another way, without modules, Tie, regex, or eval:
    my $date; my $v= sub{return qq(date $date)}; $date = localtime; print &$v; --output-- date Tue Mar 9 10:52:34 2004
Re: Evaluating variables when called
by Fletch (Bishop) on Mar 09, 2004 at 18:10 UTC

    Not exactly. Interpolation is really just syntactic sugar for concatenation (i.e. your first line is really just my $var = "date " . $date; underneath). Not to say that you couldn't do something similar with a tied variable (but then you'd need to use single quotes to protect from interpolation, and there'd possibly be issues of scoping).

Re: Evaluating variables when called
by Stevie-O (Friar) on Mar 09, 2004 at 23:44 UTC
    I actually wrote a module that handles this once; feel free to use its code:
    # DynInterp.pm package DynInterp; use overload '""' => 'stringify'; sub new { my $class = shift; bless [@_], $class; } sub stringify { my $this = shift; return join('', map { ref($_)eq'SCALAR'?$$_:ref($_)eq'ARRAY'?"@{$_ +}":$_ } @$this); } 1;
    And here is an example file with which to use it:
    # --------------------- # dyninterp.pl #!/usr/bin/perl -l use DynInterp; $x = new DynInterp('the value of $y is ', \$y, '.'); $z = new DynInterp('the value of $y is ', \@y, '.'); $y=5; print $x; $y=8; print $x; @y = qw(a b c d); print $z; $"=','; print $z; $"='.'; print $z;
    In your particular case you would do
    $var = new DynInterp('date ', \$date); $date = localtime; print $var;
    --Stevie-O
    $"=$,,$_=q>|\p4<6 8p<M/_|<('=> .q>.<4-KI<l|2$<6%s!<qn#F<>;$, .=pack'N*',"@{[unpack'C*',$_] }"for split/</;$_=$,,y[A-Z a-z] {}cd;print lc