in reply to Eval and $@% ...

Go back to the if-elsif-else! Stringy eval should be a last resort!

Besides, treating all of the references the same doesn't make much sense. Sure, I can see wanting to allow both @array and [list], but if you end up wanting to support refs to hashes, then it is unlikely that what you'll want to return is %$href (more likely you'll want to return just the keys or just the values, or have the hash keys have meanings...). And what possible value is there to allow \$value instead of just $value?? Or for letting the user pass in a code reference rather than forcing them to be the one to dereference it?

Sure, I've written functions where if one of the arguments is a code ref, I take special action. But that special action is never to just call the code in order to get the list. That would be a waste!

Even for the list vs. ref-to-array cases, I'd usually end up going the other direction: turning the list into an array ref! The whole point of allowing someone to pass in a reference to a list is usually that the list might be quite long and you don't want to have to copy that big list of values just to pass them to some subroutine. But your code just causes lots of extra copying to happen so just don't support refs to anything if that is all you are going to do with them!

(:

        - tye (but my friends call me "Tye")

Replies are listed 'Best First'.
Re: (tye)Re: Eval and $@% ...
by dragonchild (Archbishop) on Jun 19, 2001 at 18:04 UTC
    The point to this exercise is to have a function that allows a user to pass in either listrefs or lists to a given function foo(). foo() would then call a function called coerce_args(), passing in what type foo() is expecting (ARRAY, HASH, etc) and @_. coerce_args() would then return back the correct form, if possible.

    I agree that it sounds like there are much better ways of accomplishing this, namely to require the user of foo() to pass in either a hash or hashref. But, once I started down this path, I wanted to finish it in the best Perl-ish fashion.

    Why not use stringy eval? If not stringy eval, then could I use block eval? I'm probably not going to implement something like this (cause I'm going to take your advice, tye, and convert the lists to listrefs), but now I want to find out if what I'm trying is possible and, if not, why not.

      So you want something like this to work:

      my %mapping = ( ARRAY => '@', HASH => '%', SCALAR => '$', GLOB => '*', REF => '$', CODE => '&' ); return eval $mapping{$type}.'{$_[0]}';
      Note that your old code used eval "$mapping{$type}{$_[0]}" which ends up trying to run code like "$SCALAR(0xbadf00)", which doesn't do much good.

      My code above expands out to:

      return @{$_[0]} if $type eq "ARRAY"; return %{$_[0]} if $type eq "HASH"; return ${$_[0]} if $type eq "SCALAR"; return *{$_[0]} if $type eq "GLOB"; return ${$_[0]} if $type eq "REF"; return &{$_[0]} if $type eq "CODE";
      but a more correct version of this useless code would be:
      my( $ref )= @_; $ref= $$ref while UNIVERSAL::isa($ref,"REF"); return @$ref if UNIVERSAL::isa($ref,"ARRAY"); return %$ref if UNIVERSAL::isa($ref,"HASH"); return $$ref if UNIVERSAL::isa($ref,"SCALAR"); return &$ref() if UNIVERSAL::isa($ref,"CODE"); return $$ref,@$ref,%$ref if UNIVERSAL::isa($ref,"GLOB");
      Now if you really want to try to use stringy eval for this, feel free. It seems like a waste to me. And, no, block eval would do you no good in this, unless you use it to make some fatal errors non-fatal (which is what block eval is for), such as using @$ref when $ref is a reference to something other than array.

              - tye (but my friends call me "Tye")
        Ok ... so what I was missing was the {}. And, I see why that would make it work. That would fail if you put use strict 'refs' in the eval, right?

        Now, I'm curious as to why you keep saying that string eval is a waste. You've been very adamant about this ... why?