http://www.perlmonks.org?node_id=593388

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

Dear monks,

I wrote a little script called excelPerl.pl (like xlsPerl, but using Win32::OLE for getting read/write-access to the excel file) which tries to do to an excel file what perl -ane does for a text file, and to keep the interface as similar as possible, I also use the array @F for accessing the cells of one row. Since I want to save changes of elements of @F into the excel file, I decided to use a tied array.

The program works fine, but I couldn't find a clean way to return the tied array from a subroutine so I can use it as array (and not as array reference)

Here a minimal code example returning as arrayref which works:

my $array = TieVariable(); ### Pos1 print "### Initialization finished\n"; for (0..$#$array) { print "$_: $array->[$_]\n"; } # for $array->[6] = 1000; untie $array; # ------------------------------------------------------------ sub TieVariable { tie my @array, 'Tie::Excel::Array'; $array[$_] = 5 * $_ for 0..5; return \@array; ### Pos2 } # TieVariable # ============================================================ package Tie::Excel::Array; sub TIEARRAY { my( $class ) = @_; return bless [], $class; } # TIEARRAY # ------------------------------------------------------------ sub STORE { my( $self, $index, $value ) = @_; warn "STORE: \$self->[$index] = $value;\n"; $self->[$index] = $value; } # STORE # ------------------------------------------------------------ sub FETCH { my( $self, $index ) = @_; warn "FETCH: \$self->[$index] = $self->[$index];\n"; return $self->[$index]; } # STORE # ------------------------------------------------------------ sub FETCHSIZE { my( $self ) = @_; return $#$self; } # FETCHSIZE # ------------------------------------------------------------ sub UNTIE { my( $self ) = @_; warn "UNTIE\n"; } # UNTIE # ...

Using array

If I just change POS1 to my @array = TieVariable(); and POS2 to return @array; to be able to work with an array in my main program, the array looses its binding, and the change in $array->[6] = 1000; can't be written to the excel file.

Using a global variable

If I use @F as global variable and fill it, it would work; but then I have to know the name of the global variable in the subroutine, and can only use one @F.

Working with an alias

using a package variable and working with something like: our @F; *F = \@MyPackage::Array1;, but then I have to know the variable's name in my main program, and can only use one @MyPackage::Array1

Move the tie into the main program

I like this solution best, but then in the main program you have to know you are working with a tied array

Writing a sourcefilter or similar

Working with the arrayref-solution and writing a source filter which converts accesses to $F[0] to $F->[0] looks much to complicated.

Do you know another solution how I can do it?

The main program of excelPerl.pl should look something like:

# ... parsing parameters: $filename, $perlCode, $separator, ... my $xls = XlsPerl->new( ... parameters ... ); while( my @F = $xls->getNextRowData ) { ### POS 1 local $_ = join( $separator, @F ); eval $perlCode; die $@ if $@; } # while

Best regards,
perl -e "s>>*F>e=>y)\*martinF)stronat)=>print,print v8.8.8.32.11.32"

Replies are listed 'Best First'.
Re: returning tied array
by nobull (Friar) on Jan 07, 2007 at 13:54 UTC
    Another solution is to declare @array in the main program and pass a reference to &TieVariable.
    TieVariable(\my @array); ### Pos1 print "### Initialization finished\n"; for (0..$#array) { print "$_: $array[$_]\n"; } # for $array[6] = 1000; untie @array; sub TieVariable { my $array = shift; tie @$array, 'Tie::Excel::Array'; $array->[$_] = 5 * $_ for 0..5; }

    You can get rid of then need for the backlash at Pos1 by giving TieVariable a prototype, but I would not recommend it.

      nobull: Thank you very much. The current version uses the alias version, because I have been thinking in a much too complicated way. The "Call-by-Reference" does exactly what I was looking for, and I will use it for the next version.

      When it is finished, I'll post the script under Cool Uses For Perl ;-)

      Best regards,
      perl -e "s>>*F>e=>y)\*martinF)stronat)=>print,print v8.8.8.32.11.32"

Re: returning tied array
by nobull (Friar) on Jan 07, 2007 at 14:00 UTC
    The reason you give for not working with an alias using a package variable is not valid. You can say:
    our @F; *F = TieVariable;

    You can also create lexical aliases using Lexical::Alias.

Re: returning tied array
by ysth (Canon) on Jan 07, 2007 at 18:57 UTC
    You seem to have discovered that subs return lists, not arrays. I'm not sure why you want a lexical @F; seems to me that if you want to emulate perl's -a switch, you want to set the global @F and $_, and if you don't want to, using a returned arrayref is fine.

    But I hope one of the things suggested by others helps you get where you want.

      Hi all, (please ignore the "intermidate" thing) as far as i know, returning anything from a sub, object etc, usualy returns an array, sorry dont have time to check the script, but try,
      @MyArray = &YourFunction(pass variables here); ## or $MyString = &YourFunction(pass variables here); ##might work! -------------- sub YourFunction{ @array =@_; (do something) return $YourString; ##wich ya get a string return @YourArray; ##wich ya get an array, i think the array objects seperated by spaces! (and furthermore you can change the space to something else through a special command to the perl interperter! :P ) } ---------------
      calling objects is done a different way! :P if your going to pass hashes there is another way to do it, but ya gonna have to ask! :P

      c ya, have fun! www.arobcorp.com

        If you return a list from a subroutine, then you get that list back. If it was in scalar context, then you only get the first item of the list.

        You can use wantarray to see what context you were called in.

        Update: s/\barray\b/list/g per chromatic's comment.
Re: returning tied array
by diotalevi (Canon) on Jan 08, 2007 at 16:25 UTC

    TieVariable() returns a reference to your tied array. That's as good as you're going to get. There are tricks like alias which will let you alias your array reference into an array. There are other glob-assignment tricks which I simply cannot recommend so I mention them only to say that if you see one, it's not a good idea.

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊