1

I'm new to Perl Moose, and I'm trying to achieve this simple task. I have my Moose class "TestObject" defined:

package TestObject;
use Moose;
use namespace::autoclean;

has 'Identifier' => (is =>'ro',isa=>'Str');

around BUILDARGS => sub
{
    my $orig = shift;
    my $class = shift;

    if ( @_ == 1 && ! ref $_[0] ) {
        return $class->$orig(Identifier => $_[0]);
    }
    else {
        return $class->$orig(@_);
    }
};
__PACKAGE__->meta->make_immutable;
1;

In another script I'm trying to access the attribute "Identifier" directly from an array of "TestObjects":

use TestObject;
use experimental 'smartmatch';
my @aArray1=(TestObject->new("z003"),TestObject->new("t302"),TestObject->new("r002"));
my $sIdent="t302";
if($sIdent~~@aArray1->Identifier)
{
    print "Element with Identifier".$sIdent." found.";
}

This doesn't work. I could implement a workaround like this:

my @aIdent=();
foreach my $sObject(@aArray1)
{
    push(@aIdent,$sObject->Identifier);
}
if($sIdent~~@aIdent)
{
    print "Element with Identifier".$sIdent." found.";
}

but that doesn't seem to be the most elegant solution. What is the most elegant solution to solve this problem?

2
  • 4
    Don't name your class Object. That's really confusing! Commented Sep 8, 2017 at 11:42
  • 3
    I would say don't use the smartmatch operator. It's experimental and might change or get thrown out finally at some point. Commented Sep 8, 2017 at 11:45

1 Answer 1

4

Do not do this with the smartmatch operator. It's experimental for a reason, and it might be removed from future Perl versions, or change the way it works, as it's done before.

Instead, this can be achieved with a simple grep.

my @aArray1 = ( 
    TestObject->new("z003"), 
    TestObject->new("t302"),
    TestObject->new("r002"),
);

my $sIdent = "t302";
if ( grep { $_->Identifier eq $sIdent } @aArray1 ) {
    print "Element with Identifier" . $sIdent . " found.";
}

If you want that to be a bit shorter, you can also use first from List::Util. This is a bit faster as it will stop looking after the first match.

use List::Util 'first';
my @aArray1 = ( 
    TestObject->new("z003"), 
    TestObject->new("t302"),
    TestObject->new("r002"),
);

my $sIdent = "t302";
if ( first { $_->Identifier eq $sIdent } @aArray1 ) {
    print "Element with Identifier" . $sIdent . " found.";
}

A few words of advice on your code:

  • Do not ever name a class anything with object. It is going to confuse you, future you and the maintenance guy. If you do not understand the difference between class and object, read up on that please.
  • Variable names and functions in Perl are always written in lower case by convention, and we use snake case. Camel case is reserved for package names.
Sign up to request clarification or add additional context in comments.

4 Comments

"Do not ever name a class anything with object." One of my first jobs was working on the database generation component of a data modelling tool. Our database had tables called "database", "table" and "column". It was very confusing!
@simbabque: Thx for your answer. Yes, I know the difference between class and object, just wrote this code snippet for posting on stackoverflow. Could you help me out with a similar issue? I'm struggling to implement the grep syntax into a List::Compare Object: my $lc=List::Compare->new('-u',\@aIdentList,\@{(grep {$_->Identifier}@aArray1)});
@airborne just ask a new question for that please.
@airborne: "I know the difference between class and object, just wrote this code snippet for posting on stackoverflow" How are we so special that we deserve the confusing version?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.