Object-InsideOut - Re: How To Deal With Arrays Passed Into Objects During Initialization

Posted on Wed Nov 30 20:11:34 2005 by jdhedden in response to 1420 (See the whole thread of 6)
Re: How To Deal With Arrays Passed Into Objects During Initialization
> this is my first time using Perl as anything other than a glorified awk.

Well, I hope this is a good beginning for you. Thanks for taking a look at Object::InsideOut.

First, let's tackle the following bug:

$test1[$$self] = @$tmpref;

An array in a scalar context returns its 'length'. Thus, you end up storing the number 3, which is not what you want. What you want is to store the array ref itself in the field. Thus, for the fix, you have several options: You can either store the input directly with:

$test1[$$self] = $tmpref;

or you can make a copy, and then store that:

my @copy = @$tmpref; $test1[$$self] = \@copy;

Since your input is assigned to $arrref, the latter might be preferable if your code will be making any changes to the the array ref's contents via $arrref. If not, the former is simpler.

However, the option that is preferable to the above is to use the 'set' method:

$self->set(\@test1, $tmpref);

This has the same effect as the first example above with one crucial difference: If your code is being used in a threads::shared environment, the 'set' method handles all the details of making a shared copy of the data you're going to store in your fields.

Now, as to your question, I'll be working with a slightly modified version of your example. Most notably, I'll be using Test::More because it makes it easy to show test results.

The first thing you should try is to let Object::InsideOut do the menial work for you. Consider your :Init subroutine: All it does is store the input into the field. By uncommenting the 'Field' parameter in your :InitArgs, you can have Object::InsideOut automatically do this for you such that you don't even need an :Init subroutine at all:

use warnings; use strict; use Test::More 'no_plan'; package Hashtest; { use Object::InsideOut; my @data :Field('Standard' => 'data'); my %init_args :InitArgs = ( 'DATA' => { 'Regex' => qr/^data/i, 'Type' => 'ARRAY', 'Field' => \@data, }, ); } package main; my $input = [ "hunger", "pain", "misery" ]; my $obj = Hashtest->new('data' => $input); my $output = $obj->get_data(); is_deeply($input, $output => 'Equality for all'); exit(0);

Note that I added accessor generation parameters to the :Field attribute so that the data could be accessed via the object.

Here's the same example with the :Init subroutine added back in, and using the 'set' method as discussed above:

use warnings; use strict; use Test::More 'no_plan'; package Hashtest; { use Object::InsideOut; my @data :Field('Standard' => 'data'); my %init_args :InitArgs = ( 'DATA' => { 'Regex' => qr/^data/i, 'Type' => 'ARRAY', }, ); sub _init :Init { my ($self, $args) = @_; if (exists($args->{'DATA'})) { $self->set(\@data, $args->{'DATA'}); } } } package main; my $input = [ "hunger", "pain", "misery" ]; my $obj = Hashtest->new('data' => $input); my $output = $obj->get_data(); is_deeply($input, $output => 'Equality for all'); exit(0);

Since you did not make the 'DATA' parameter mandatory, the :Init subroutine needs to check for existance prior to trying to store the data.

Hope this answered your question adequately.

Direct Responses: 1427 | 1428 | Write a response