The Perl Toolchain Summit 2025 Needs You: You can help 🙏 Learn more

NAME

Try::Chain - Call method, hash and/or array chains with break on undef

VERSION

0.005

SYNOPSIS

The module exports:

try

imported from Try::Tiny

catch

imported from Try::Tiny

finally

imported from Try::Tiny

try_chain

implemented here to call a complete chain or break

$call_m

implemented here to call a method or break

$call_em

implemented here to call an existing method or break

$fetch_i

implemented here to fetch an array index or break

$fetch_ei

implemented here to fetch an existing array index or break

$fetch_k

implemented here to fetch a hash key or break

$fetch_ek

implemented here to fetch an existing hash key or break

Import what needed. The following code describes the full import:

use Try::Chain qw(
try catch finally
try_chain
$call_m $call_em
$fetch_i $fetch_ei
$fetch_k $fetch_ek
);

EXAMPLE

Inside of this Distribution is a directory named example. Run this *.pl files.

DESCRIPTION

Call method, hash and/or array chains with break on undef means, that in some cases it is ok to get back nothing late or early.

Problem

In case of method chain like

my $scalar = $obj->foo(1)->bar(2)->baz(3);
my %hash = (
any => 'any',
baz => scalar $obj->foo(1)->bar(2)->baz(3),
);

and foo or bar can return nothing or undef, you get an error: Can't call method ... on an undefined value.

A quick solution is:

my $scalar
= $obj->foo(1)
&& $obj->foo(1)->bar(2)
&& $obj->foo(1)->bar(2)->baz(3);
my %hash = (
any => 'any',
baz => scalar $obj->foo(1)
&& $obj->foo(1)->bar(2)
&& $obj->foo(1)->bar(2)->baz(3),
);

In case of method foo and/or bar is performance critical code it is a bad idea to call the method code more then one time. The the solution looks like this:

my $foo = $obj->foo(1);
my $bar = $foo && $foo->bar(2);
my $scalar = $bar && $bar->baz(3);
my %hash = (
any => 'any',
baz => do {
my $foo = $obj->foo(1);
my $bar = $foo && $foo->bar(2);
$bar && scalar $bar->baz(3);
},
);

Solution

This module allows to call the chain by ignoring all undef errors in block:

my $scalar = try_chain { $obj->foo(1)->bar(2)->baz(3) };
my %hash = (
any => 'any',
baz => scalar try_chain { $obj->foo(1)->bar(2)->baz(3) },
);

Or better step by step?

my $scalar = $obj->$call_m('foo', 1)->$call_m('bar', 2)->$call_m('baz', 3);
my %hash = (
any => 'any',
baz => scalar $obj
->$call_m('foo', 1)
->$call_m('bar', 2)
->$call_m('baz', 3),
);

Also possible with maybe not existing hash or array references:

... = try_chain { $any->foo->[0]->bar(@params)->{key}->baz };

Or better step by step?

... = $any
->$call_m('foo')
->$fetch_i(0)
->$call_m(bar => @params)
->$fetch_k('key')
->$call_m('baz');

Full Try::Tiny support:

... = try_chain { ... } catch { ... } finally { ... };

Solution for the autovivification problem

Switch off possible autovivication:

$result = try_chain {
no autovivification;
$any->foo->{key}->bar(@params)->[0]->baz;
};
@result = try_chain {
no autovivification;
$any->foo->{key}->bar(@params)->[0]->baz;
};

SUBROUTINES/METHODS

sub try_chain

Calls the whole try block, breaks and ignores undef errors.

sub $call_m

Calls the next method if possible.

sub $call_em

Calls the next method if possible and method exists.

sub $fetch_i

Calls the next index of an array reference if possible.

sub $fetch_ei

Calls the next index of an array reference if possible and index exists.

sub $fetch_k

Calls the next key of a hash reference if possible.

sub $fetch_ek

Calls the next key of a hash reference if possible and key exists.

DIAGNOSTICS

none

CONFIGURATION AND ENVIRONMENT

nothing

DEPENDENCIES

parent

Exporter

Try::Tiny

INCOMPATIBILITIES

not known

BUGS AND LIMITATIONS

none

SEE ALSO

Try::Tiny

autovivification

AUTHOR

Steffen Winkler

LICENSE AND COPYRIGHT

Copyright (c) 2017, Steffen Winkler <steffenw at cpan.org>. All rights reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.