in reply to Re: Duplicating Pascal's with statement in Perl for anonymous data structures
in thread Duplicating Pascal's with statement in Perl for anonymous data structures

At first glance, I thought you had accomplished what I couldn't. Then I realized you're just passing a hashref, not a code block. The actual with statement in Pascal takes a code block and you can read and write variables by member name, rather than by fully-qualified name.

I've been trying to mimic that in Perl with globs and package variables, but I think it's not possible. What do you think?


Caution: Contents may have been coded under pressure.
  • Comment on Re^2: Duplicating Pascal's with statement in Perl for anonymous data structures
  • Download Code

Replies are listed 'Best First'.
Re^3: Duplicating Pascal's with statement in Perl for anonymous data structures
by ambrus (Abbot) on Mar 28, 2005 at 19:16 UTC

    I think it's either not possible or is a Bad Thing. Pascal can know what identifiers in the with body refer to record members and which ones are variables. However, a perl hash is an open structure, it can have any key, so perl would have no way to deduce which $-variables are meant to be hash elements.

      Good point to note that you can also use non-member variables within a with. But in the way I envision it working, Perl would do The Right Thing. If only it would work. Here's a quick description:
      with takes a hashref and a coderef. It goes through the hashref and creates package variables in the "With::" namespace that point to the hash elements. Then it executes the coderef in the With package space.

      Sadly, I don't think it can be done. Even in a coderef executed within a package, Perl considers the unqualified variable names to be in main (or wherever the coderef was created). And while my glob-fu is shaky, I don't think it's possible to make a symbol table refer to another hash, so that changes to package variables actually affect members of the hash.

      Here's an eval solution that turns the members into references with the same names, so the user accesses them as, e.g., $$a:

      use strict; my %hash = ( a => 1, b => 2, c => 3 ); sub with(\%&) { my ($href, $cref) = @_; my $cmd = join "\n", map sprintf('local $::%s = \\$href->{%s};', $_, $_), keys %$href; eval $cmd . '$cref->()'; warn "$@: $cmd\n" if $@; } with %hash, sub { $$a = 'changed'; print "B=$$b\n"; } ; use Data::Dumper; print Dumper(\%hash);
      I always feel dirty after using a string eval, though.

      Caution: Contents may have been coded under pressure.