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

so, creating a moose class to represent a single record from a db table. The class has a property "Fields" which is a hash which stores the name of each field along with the value of the field in the record being represented.

When the class loads the record, it needs to clear this hash reference, so it can load the "new" record. Being a "property" of the moose class, Fields is a hash ref, not a hash. Getting an error when I try to clear the hash reference before repopulating.

specific line with the problem is

$self->Fields = 0;

in the select method.

package AXRecord; # Our libraries use lib 'C:\Users\Jay\Desktop\SBS DEV\CODE\perl\Utilities'; use AXControl; use AXSQL; use Moose; use DBI; # Attributes has 'Name' => (is => 'rw', isa => 'Str', required => 1); has 'Fields' => (is => 'rw', isa => 'HashRef'); has 'FieldCount' => (is => 'rw', isa => 'Num'); has 'Changed' => (is=>'rw', isa => 'Boolean'); has 'Where' => (is => 'rw', isa => 'Str'); has 'ControlObject' => (is => 'rw', isa => 'Object', required => 1); has 'Keys' => (is => 'rw', isa=>'Array'); has 'Populated' => (is => 'rw', isa => 'Boolean'); # Contains a single record sub BUILD # Constructor { my $self; $self = shift; if (defined $self->Where) { $self->Select(); } else { $self->Populated = 0; } } # Insert the record sub Insert { } #Delete using the keys in the record sub Delete { } #Update using the keys and values in the record sub Update { } #Save the record sub Save { } sub Select { my ($SQLStr, $Cnt, $sql, @Values, $self, $Col, @Flds, $i); $self = shift; $SQLStr = "SELECT * FROM " . $self->Name . ' ' . $self->Where; print "Record.pm \t $SQLStr\n"; $sql = AXSQL->new(ControlObject => $self->ControlObject, SQLString + => $SQLStr); #construct a hash using the metadata and the data from the actual +table $self->Fields = 0; @Values = $sql->Fetch(); if ($sql->Rowcount >= 1) { $self->Populated = 1; } else { $self->Populated = 0; } #Get field Names $sql = AXSQL->new(ControlObject => $self->ControlObject, SQLString + => "show fields from '" . $self->Name . "'"); @Flds = $sql->fetch(); # Construct the hash for ($i..$#Flds) { if ($self->Populate == 0) { $self->Fields->{$Flds[$i]} = $Values[$i]; } Else { $self->Fields->{$Flds[$i]} = ' '; } } #Get the primary key fields $self->Keys = (); $sql = AXSQL->new(ControlObject => $self->ControlObject, SQLString + => "SELECT column_name FROM information_schema.`key_column_usage` WH +ERE table_name = '" . $self->name . "' order by ordinal_position"); while (($Col) = $sql.fetch()) { push $self->Keys, $Col; } $Cnt = $self->Fields; $self->FieldCount = $Cnt; $self->Changed = -1; } 1;
Error message is

C:\Users\Jay\Desktop\SBS DEV\CODE\perl>perl -w CollectEmail.pl Record.pm SELECT * FROM customer WHERE NAME = 'Testing' RowCount 1 Can't modify non-lvalue subroutine call at C:\Users\Jay\Desktop\SBS DEV\CODE\per l\Utilities/AXRecord.pm line 73. C:\Users\Jay\Desktop\SBS DEV\CODE\perl>

Replies are listed 'Best First'.
Re: Clearing a hash reference
by haukex (Archbishop) on Oct 18, 2017 at 23:41 UTC

    Please try to reduce your code down to the minimum needed to reproduce the issue - see SSCCE. Like this:

    use warnings; use strict; use Data::Dump; { package Foo; use Moose; has 'Fields' => (is => 'rw', isa => 'HashRef'); } my $foo = Foo->new(Fields=>{}); $foo->Fields->{x}++; dd $foo->Fields; # prints { x => 1 } #$foo->Fields = 0; # wrong, fails $foo->Fields({}); dd $foo->Fields; # prints {}

    The problem is that $foo->Fields is a method call, to which you cannot assign anything ($foo->Fields = ...;) by default; it's as if you had written sin($pi) = 123;. The normal way to set an object property is to pass its new value as an argument to the method, as I showed above: $foo->Fields({});

    There is a way to make methods that you can assign to in Perl, Lvalue subroutines, but at least in my experience they seem to be pretty uncommon. I suggest you stick to normal setter calls.

    Also, let me repeat Mr. Muskrat's suggestion to look into DBIx::Class instead of reinventing that wheel.

Re: Clearing a hash reference
by kcott (Archbishop) on Oct 18, 2017 at 23:51 UTC

    G'day jorba,

    "... Can't modify non-lvalue subroutine call at ..."

    Methods are subroutines. "$self->Fields" is the same as "$self->Fields()". You are attempting to assign zero to that "non-lvalue subroutine":

    $self->Fields = 0;

    I haven't delved too deeply into your code but I suspect you want something closer to:

    $self->Fields({});

    — Ken