Reputation: 3545
I have a function that accepts an array of positive values only. Dies when any negative value is given.
# Consider edge cases
# First check if all elements are > 0, if not throw informative error
# Then if any of element is zero return 0
# Only else proceed further towards calculation
sub geometric_mean(@data) {
if @data.any < 0 {die "Not possible to calculate geometric mean for negative values"};
if @data.any == 0 { return 0 };
my $sum;
for @data {
$sum += log($_);
}
return exp($sum/@data.elems)
}
With this if I try to run the script:
my @data = [1, 2, 3.8, -1];
say geometric_mean(@data);
say "Hello world";
the code exits at the function call without running the last line i.e does not run the codes down the function:
Not possible to calculate geometric mean for negative values
in method throw at 'SETTING::'src/core.c/Exception.rakumod line 65
in sub die at 'SETTING::'src/core.c/control.rakumod line 255
in sub geometric_mean at c:\Users\suman\sum.p6 line 8
in block <unit> at c:\Users\suman\sum.p6 line 20
The modification:
sub geometric_mean(@data) {
if @data.any < 0 {die "Not possible to calculate geometric mean for negative values"};
CATCH { default { warn " Not possible to calculate geometric mean for negative values"; } };
if @data.any == 0 { return 0 };
my $sum;
for @data {
$sum += log($_);
}
return exp($sum/@data.elems)
}
now runs the last line too with output:
Not possible to calculate geometric mean for negative values
Nil
in sub warn at 'SETTING::'src/core.c/control.rakumod line 269
Hello world
How to handle such cases?
I looked at try
CATCH
blocks but that would execute the code below those blocks within the function which I want to avoid.
I went through this:
Upvotes: 8
Views: 204
Reputation: 7571
I think you are asking "how can I avoid the backtrace details emitted on a fail or die??
If so, you can just not generate an exception, like this:
sub geometric_mean(@data) {
if @data.any < 0 { return "Not possible to calculate geometric mean for negative values" }
if @data.any == 0 { return 0 };
my $sum;
for @data {
$sum += log($_);
}
exp($sum/@data.elems)
}
my @data = [1, 2, 3.8, -1];
say geometric_mean(@data);
say "Hello world";
Not possible to calculate geometric mean for negative values
Hello world
EDIT: removed my speculative speculative try/CATCH variant since per comment not good to use try and CATCH in the same block.
Upvotes: 3
Reputation: 2314
die
is for fatal exceptions. If you want to continue control flow, you don't want a fatal exception.
There are two ways you could fix this. First, use fail
instead of die
, and then check if the call failed with a with
:
sub geometric_mean(@data) {
if @data.any < 0 {fail "Not possible to calculate geometric mean for negative values"};
// etc
}
my @data = [1, 2, 3.8, -1];
with geometric_mean(@data) -> {} else {say .exception.message};
say "Hello world";
The other way is to not throw an exception at all, and instead return:
sub geometric_mean(@data) {
if @data.any < 0 {say "Not possible to calculate geometric mean for negative values"; return};
// etc
}
my @data = [1, 2, 3.8, -1];
geometric_mean(@data);
say "Hello world";
Upvotes: 6