Mailing List Archive

PSC #030 2021-070-23
PSC #030 2021-070-23

Present: Paul, Rik, Neil

We've had a couple of discussions about namespaces, identifying the questions that we think need answering, in particular, what problem might namespaces be the answer to? We're going to invite some relevant members of p5p to join us for a longer discussion on this topic, in a couple of weeks. If you have well-formed opinions you'd like to share, please do that on p5p.

Following on from a discussion on p5p, we had a chat about whether catch should be optional on try. Three quarters of the Try/Catch modules on CPAN support optional catch, but just about all other programming languages require at least one catch, and rethrow the exception if it's not caught. What's the perl'ish approach? We're going to revisit this another time, after we've written up our thoughts. But Paul and Rik are of a mind here, so it's pretty clear how this is going to play out :-)

Paul raised the topic of signature introspection, and whether this is something Perl should support. We had a brief talk, but given "signatures" are on Rik's hit list of experiments to resolve, we decided that should be the driver for working out where signatures should go.

The rest of the time was spent working through some more quirks. One theme was that a number of quirks have been identified because someone was working on JSON encoding/decoding, and other serialisations. Rik suggested it would be useful to have a document that covers "everything you should be aware of if you're writing serialisation code". Paul suggested that a useful precursor doc would be a comprehensive "Perl data model", covering the different sorts of things you might find in scalars, arrays, etc. Some of the quirks would then end up with "ok this is quirky, but read this other document for the gory details".
Re: PSC #030 2021-070-23 [ In reply to ]
On 2021-07-24 1:51 p.m., Neil Bowers wrote:
> Following on from a discussion on p5p, we had a chat about whether catch should be optional on try. Three quarters of the Try/Catch modules on CPAN support optional catch, but just about all other programming languages require at least one catch, and rethrow the exception if it's not caught. What's the perl'ish approach? We're going to revisit this another time, after we've written up our thoughts. But Paul and Rik are of a mind here, so it's pretty clear how this is going to play out :-)

I feel that it is a very poor and dangerous code design when one traps an
exception and then simply ignores it.

If one isn't going to explicitly handle a thrown exception in some reasonable
way, which could be as simple as logging/reporting that it happened, then they
shouldn't be suppressing it with a try/eval either, and instead let the program
die from the exception as would be the default.

Therefore, I feel that Perl's built-in try should either have a mandatory catch
or else when there is no explicit catch it should have a default action that
does something useful, such as printing the details of the caught exception to
STDERR/etc, rather than defaulting to doing nothing.

-- Darren Duncan
Re: PSC #030 2021-070-23 [ In reply to ]
* Darren Duncan <darren@darrenduncan.net> [2021-07-24 18:45:30 -0700]:

> On 2021-07-24 1:51 p.m., Neil Bowers wrote:
> > Following on from a discussion on p5p, we had a chat about whether catch should be optional on try. Three quarters of the Try/Catch modules on CPAN support optional catch, but just about all other programming languages require at least one catch, and rethrow the exception if it's not caught. What's the perl'ish approach? We're going to revisit this another time, after we've written up our thoughts. But Paul and Rik are of a mind here, so it's pretty clear how this is going to play out :-)
>
> I feel that it is a very poor and dangerous code design when one traps an
> exception and then simply ignores it.

Generally, but there is a case where it's useful. See below.

>
> If one isn't going to explicitly handle a thrown exception in some
> reasonable way, which could be as simple as logging/reporting that it
> happened, then they shouldn't be suppressing it with a try/eval either, and
> instead let the program die from the exception as would be the default.

Personally, I use the block form of eval. But from what I've gathered, the
main value that I've seen for using Try::Tiny, is that it automagically
converts $@ to an implicit $_, and avoids the whole need to localize
$@.

My measuring stick for try/catch vs eval is which one makes for the most
elegant "retry" mechanism? Just a quick pass with Try::Tiny leads me to
this, which is gross (all examples are untested but illustrative):

my $retry_count = 0;
my $max_retry = 5;
TRY:
try {
do_something_to_retry();
}
catch {
++$retry_count;
#... do something with $_
goto TRY unless $retry_count > $max_retry;
}
finally {
if ($@) {
print qq{something died after $retry_count attempts ...\n};
}
else {
print qq{something succeded after $retry_count attempts ...\n} if $retry_count > 0;
}
}

But this seems more gross.

my $retry_count = 0;
my $max_retry = 5;
local $@;
do {
++$retry_count;
if ($@) {
#... do something with $@
$@ = undef; # reset $@
}
eval {
do_something_to_retry();
};
} while ($@ or $retry_count > $max_retry);
if ($@) {
print qq{something died after $retry_count attempts ...\n};
}
else {
print qq{something succeded after $retry_count attempts ...\n} if $retry_count > 0;
}

I am sure most can do better; but maybe this is an excercise worth having
if we're talking about forcing try{} to be both "more convenient" eval{}
(wrt to $@ vs $_) *and* making it more annoying/restrictive by requiring
a catch{} (or even nagging the developer). So maybe what's needed is an
"idiom face-off" - what's the most "perlish" "retry" mechanism you are able
to write using either eval{} or try{}catch{}?

On the otherhand, being able to simply suppress errors is a useful tool
when introducing new or risky code into existing production code. This
is just a reality some times.

So in the aforementioned case, it's far more convenient to wrap the risky
code into an eval{} and just do your debugging within that scope. The larger
program is none the wiser.

I don't suppose eval{} is going anywhere; forcing Try::Tiny to include at
least one catch{} seems reasonable. It also delineates at least one use
case where eval{} is going to be more convenient that Try::Tiny (the one
I've outlined above).

There's also the approach that I've seen quite common in production code;
whereby an exception is caught, then rethrown. When the exception is caught,
some logging or preliminary action takes place; then the exception is re-
thrown. This case is more "perlish" using eval{}, to my eyes at least:

# rethrow
my $ok = try {
die "foo!\n";
}
catch {
#... do stuff with $_
die $_;
};
#^^ <~ semi-colon requied to terminate parameter list

# rethrow

local $@;
my $ok = eval {
die "bar!\n";
};
#^^ <~ semi-colon required to terminate block

if (not $ok or $@) {
#... do stuff with $@ and maybe $ok
die $@;
}

> Therefore, I feel that Perl's built-in try should either have a mandatory
> catch or else when there is no explicit catch it should have a default
> action that does something useful, such as printing the details of the
> caught exception to STDERR/etc, rather than defaulting to doing nothing.

If the exception captured in $_ is a blessed reference, then it should be
pretty straightforward to have a DESTROY method that's defined explicitly
for that purpose.

However, if you're going to force a "warning" of some kind regarding the
undefinedness of a "catch" there is going to need to be a familiar way
to turn this warning off - unless you want to start seeing this:

# suppress T::C's warning about no catch{}
eval {
try {
do_something_that_can_die();
}
}

Or perhaps for some, less desirable:

# or just not use T::C here
eval {
do_something_that_can_die();
};

xD

Brett

>
> -- Darren Duncan

--
--
oodler@cpan.org
oodler577@sdf-eu.org
SDF-EU Public Access UNIX System - http://sdfeu.org
irc.perl.org #openmp #pdl #native
Re: PSC #030 2021-070-23 [ In reply to ]
On 2021-07-24 10:19 p.m., Oodler 577 via perl5-porters wrote:
> * Darren Duncan [2021-07-24 18:45:30 -0700]:
>
>> On 2021-07-24 1:51 p.m., Neil Bowers wrote:
>>> Following on from a discussion on p5p, we had a chat about whether catch should be optional on try. Three quarters of the Try/Catch modules on CPAN support optional catch, but just about all other programming languages require at least one catch, and rethrow the exception if it's not caught. What's the perl'ish approach? We're going to revisit this another time, after we've written up our thoughts. But Paul and Rik are of a mind here, so it's pretty clear how this is going to play out :-)
>>
>> I feel that it is a very poor and dangerous code design when one traps an
>> exception and then simply ignores it.
>
> Generally, but there is a case where it's useful. See below.
<snip>

I didn't see you provide any example of where simply pretending the exception
never happened is useful. All your examples still took some kind of explicit
action when and only when an exception was thrown.

I want to be clear that what I'm opposing is code that traps exception-throwing
code for the sole purpose of pretending the code never throws exceptions.

I also want to be clear that the more canonical form of what I'm opposing is the
empty catch block, code like this:

try {
...
} catch {
}

Before I was partly treating "not having a catch block" as being implicitly the
same as having an explicitly empty catch block.

Either should be something that at the very least tools like Perl Critic or
corresponding tools in other languages, that they should be flagging by default
as a bad thing, even if the language itself allows them.

Perl making catch blocks mandatory would help developers not accidentally have
an effectively empty catch block if those are what the semantics of a missing
catch block would be.

If it is important, the only theoretical benefit of not requiring the catch is
it mirrors how Perl's block eval works now in that it isn't mandatory to check
$@ after doing one.

-- Darren Duncan
Re: PSC #030 2021-070-23 [ In reply to ]
* Darren Duncan <darren@darrenduncan.net> [2021-07-24 22:52:47 -0700]:

> On 2021-07-24 10:19 p.m., Oodler 577 via perl5-porters wrote:
> > * Darren Duncan [2021-07-24 18:45:30 -0700]:
> >
> > > On 2021-07-24 1:51 p.m., Neil Bowers wrote:
> > > > Following on from a discussion on p5p, we had a chat about whether catch should be optional on try. Three quarters of the Try/Catch modules on CPAN support optional catch, but just about all other programming languages require at least one catch, and rethrow the exception if it's not caught. What's the perl'ish approach? We're going to revisit this another time, after we've written up our thoughts. But Paul and Rik are of a mind here, so it's pretty clear how this is going to play out :-)
> > >
> > > I feel that it is a very poor and dangerous code design when one traps an
> > > exception and then simply ignores it.
> >
> > Generally, but there is a case where it's useful. See below.
> <snip>
>
> I didn't see you provide any example of where simply pretending the
> exception never happened is useful. All your examples still took some kind
> of explicit action when and only when an exception was thrown.

Just addressing this one point; I simply described the scenario where
you wanted to try something "in production" that could fail but should
be basically hidden away regardless from the main process. It's not
really useful for a long term application unless, but is a practical
and "real life" example of why it's useful to be able to do such a thing.

>
> I want to be clear that what I'm opposing is code that traps
> exception-throwing code for the sole purpose of pretending the code never
> throws exceptions.
>
> I also want to be clear that the more canonical form of what I'm opposing is
> the empty catch block, code like this:
>
> try {
> ...
> } catch {
> }

I'm not opposed or in favor of anything here either, just wanted to point
out that requiring catch when you don't need it will make a developer
choose between eval{} and try{}catch{}, if catch is required.

My biggest curiosity that's stemmed from this thread, is around this idea
of a "retry" idiom - and where it's more "perlish" - eval{}/try{} or some
form of try{}catch{}. The reason in part is because it will test the semantics
in such a way that might provide some practical insight about the wisdom
of requiring catch{} whenver try{} is used. Worst case for me is that it'd
give me a compelling reason to use try/catch.

One other thing to point out is that the POD of Try::Catch makes it very
clear that a lot of thought was put into making it very familiar and naturre
for someone who has traditionally used eval{}. So it seems more of an "improved
eval". This might also lead to a fruitful analysis, i.e., "should we require
an explicit exception handling block to this improved form of eval{}"?

Cheers,
Brett

>
> Before I was partly treating "not having a catch block" as being implicitly
> the same as having an explicitly empty catch block.
>
> Either should be something that at the very least tools like Perl Critic or
> corresponding tools in other languages, that they should be flagging by
> default as a bad thing, even if the language itself allows them.
>
> Perl making catch blocks mandatory would help developers not accidentally
> have an effectively empty catch block if those are what the semantics of a
> missing catch block would be.
>
> If it is important, the only theoretical benefit of not requiring the catch
> is it mirrors how Perl's block eval works now in that it isn't mandatory to
> check $@ after doing one.
>
> -- Darren Duncan

--
--
oodler@cpan.org
oodler577@sdf-eu.org
SDF-EU Public Access UNIX System - http://sdfeu.org
irc.perl.org #openmp #pdl #native
Re: PSC #030 2021-070-23 [ In reply to ]
On 2021-07-24 11:08 p.m., Oodler 577 via perl5-porters wrote:
> * [2021-07-24 22:52:47 -0700]:
>> I didn't see you provide any example of where simply pretending the
>> exception never happened is useful. All your examples still took some kind
>> of explicit action when and only when an exception was thrown.
>
> Just addressing this one point; I simply described the scenario where
> you wanted to try something "in production" that could fail but should
> be basically hidden away regardless from the main process. It's not
> really useful for a long term application unless, but is a practical
> and "real life" example of why it's useful to be able to do such a thing.
>
> I'm not opposed or in favor of anything here either, just wanted to point
> out that requiring catch when you don't need it will make a developer
> choose between eval{} and try{}catch{}, if catch is required.

It still feels to me like you're only finding contrived examples for why one
would want to trap and no-op.

It seems to me that a good language design would be making an option with clear
strong downsides easily accessible when its only use case is rare contrived
situations.

For example your "tried in production" could have an explicit action which is
making a note of whether or not the tried thing succeeded or failed.

The try/catch feature doesn't have to be designed to handle certain weird edge
cases, those who want to do something it isn't designed for can just not use it.

-- Darren Duncan
Re: PSC #030 2021-070-23 [ In reply to ]
2021-7-25 5:51 Neil Bowers <neilb@neilb.org> wrote:

There is always desires to add new functions.


> We've had a couple of discussions about namespaces, identifying the
> questions that we think need answering, in particular, what problem might
> namespaces be the answer to? We're going to invite some relevant members of
> p5p to join us for a longer discussion on this topic, in a couple of weeks.
> If you have well-formed opinions you'd like to share, please do that on p5p.
> ky, but read this other document for the gory details".
>

There are always desires to add new functions.

I feel there are so many requests, but, for fairness, we are not adding any
functions.

In my opinion, adding functions is unlikely to break the core language.

Many users are interested in functions because they are easy to implement.

"It would be convenient if there was such a function in Perl"

Perl, on the other hand, has a cultural habit of dealing with many cases
with a few flexible features.

They are worried about adding thousands of functions to Perl.

People make many suggestions of functions with hope, but most are rejected.

My first question is "is it possible to add frequently used functions to
Scalar::Util and Array::Util namespaces?"
Re: PSC #030 2021-070-23 [ In reply to ]
* Yuki Kimoto <kimoto.yuki@gmail.com> [2021-07-26 09:07:59 +0900]:

> 2021-7-25 5:51 Neil Bowers <neilb@neilb.org> wrote:
>
> There is always desires to add new functions.
>
>
> > We've had a couple of discussions about namespaces, identifying the
> > questions that we think need answering, in particular, what problem might
> > namespaces be the answer to? We're going to invite some relevant members of
> > p5p to join us for a longer discussion on this topic, in a couple of weeks.
> > If you have well-formed opinions you'd like to share, please do that on p5p.
> > ky, but read this other document for the gory details".
> >
>
> There are always desires to add new functions.
>
> I feel there are so many requests, but, for fairness, we are not adding any
> functions.
>
> In my opinion, adding functions is unlikely to break the core language.
>
> Many users are interested in functions because they are easy to implement.
>
> "It would be convenient if there was such a function in Perl"
>
> Perl, on the other hand, has a cultural habit of dealing with many cases
> with a few flexible features.
>
> They are worried about adding thousands of functions to Perl.

I think it's a worry about adding the *wrong* thousands of functions to perl/Perl.

>
> People make many suggestions of functions with hope, but most are rejected.
>
> My first question is "is it possible to add frequently used functions to
> Scalar::Util and Array::Util namespaces?"

Having a "module" that contained experimental functions that must be explicitly
exported to be used might not be a bad idea. Generally when we think of a "new
function" or "new keyword", we're looking for access to a single word.

use Experimental qw/trim tromp unbless/;
...

Cheers,
Brett

--
--
oodler@cpan.org
oodler577@sdf-eu.org
SDF-EU Public Access UNIX System - http://sdfeu.org
irc.perl.org #openmp #pdl #native
Re: PSC #030 2021-070-23 [ In reply to ]
On Sat, Jul 24, 2021 at 10:52:47PM -0700, Darren Duncan wrote:

> I didn't see you provide any example of where simply pretending the
> exception never happened is useful.

Loading optional plugins via something like `eval "require $filename"`
and ignoring the exception is a common idiom. The `eval` is only there
to prevent the `require` from spewing its guts if it fails.

--
David Cantrell | even more awesome than a panda-fur coat

Hail Caesar! Those about to vi ^[ you!
Re: PSC #030 2021-070-23 [ In reply to ]
On Wed, 28 Jul 2021 13:08:13 +0100
David Cantrell <david@cantrell.org.uk> wrote:

> Loading optional plugins via something like `eval "require $filename"`
> and ignoring the exception is a common idiom.

Common and wrong.

Attempting to load App::Plugin::Foo and failing because
App/Plugin/Foo.pm doesn't exist somewhere in @INC is fine.

But attempting to load it, finding the file, having that file start
`use Some::XS::Module` which itself fails because of the XS bootstrap
failing its version check signature because someone updated the perl
version and forgot to recompile that obscure and rarely-used XS module
that only comes up in this one place, is not fine.

Swallowing that error message and ignoring it leads to hours of lost
devel/debug time.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: PSC #030 2021-070-23 [ In reply to ]
> On Jul 28, 2021, at 8:33 AM, Paul LeoNerd Evans <leonerd@leonerd.org.uk> wrote:
>
> On Wed, 28 Jul 2021 13:08:13 +0100
> David Cantrell <david@cantrell.org.uk> wrote:
>
>> Loading optional plugins via something like `eval "require $filename"`
>> and ignoring the exception is a common idiom.
>
> Common and wrong.
>
> Attempting to load App::Plugin::Foo and failing because
> App/Plugin/Foo.pm doesn't exist somewhere in @INC is fine.
>
> But attempting to load it, finding the file, having that file start
> `use Some::XS::Module` which itself fails because of the XS bootstrap
> failing its version check signature because someone updated the perl
> version and forgot to recompile that obscure and rarely-used XS module
> that only comes up in this one place, is not fine.
>
> Swallowing that error message and ignoring it leads to hours of lost
> devel/debug time.

To this end, to return to an oft-made proposal: if Perl could mark those errors with some sort of reliable code, it would be easy to differentiate “file not found” errors from “parse error”, “XS version mismatch”, etc.

An ideal use for a core exception base class?

-F
Re: PSC #030 2021-070-23 [ In reply to ]
> On Jul 28, 2021, at 8:55 AM, Paul LeoNerd Evans <leonerd@leonerd.org.uk> wrote:
>
> On Wed, 28 Jul 2021 08:53:44 -0400
> Felipe Gasper <felipe@felipegasper.com> wrote:
>
>>> On Jul 28, 2021, at 8:33 AM, Paul LeoNerd Evans
>>> <leonerd@leonerd.org.uk> wrote:
>>>
>>> On Wed, 28 Jul 2021 13:08:13 +0100
>>> David Cantrell <david@cantrell.org.uk> wrote:
>>>
>>>> Loading optional plugins via something like `eval "require
>>>> $filename"` and ignoring the exception is a common idiom.
>>>
>>> Common and wrong.
>>>
>>> Attempting to load App::Plugin::Foo and failing because
>>> App/Plugin/Foo.pm doesn't exist somewhere in @INC is fine.
>>>
>>> But attempting to load it, finding the file, having that file start
>>> `use Some::XS::Module` which itself fails because of the XS
>>> bootstrap failing its version check signature because someone
>>> updated the perl version and forgot to recompile that obscure and
>>> rarely-used XS module that only comes up in this one place, is not
>>> fine.
>>>
>>> Swallowing that error message and ignoring it leads to hours of lost
>>> devel/debug time.
>>
>> To this end, to return to an oft-made proposal: if Perl could mark
>> those errors with some sort of reliable code, it would be easy to
>> differentiate “file not found” errors from “parse error”, “XS version
>> mismatch”, etc.
>>
>> An ideal use for a core exception base class?
>
> Yup definitely. It's on my TODO list but it's a long way down.
>
> But yes I live in eternal hope of
>
> try { require Some::Optional::Plugin; }
> catch ($e isa Perl::X::ModuleNotFound) { } #ignore

Not that I wouldn’t want it to come from you :), but is it perhaps something others could help with? Implement first on CPAN/XS, then do it in core if that’s a success? Maybe if there’s a design document that describes the interface, etc. etc.

-F
Re: PSC #030 2021-070-23 [ In reply to ]
On Wed, 28 Jul 2021 09:40:08 -0400
Felipe Gasper <felipe@felipegasper.com> wrote:

> Not that I wouldn’t want it to come from you :), but is it perhaps
> something others could help with? Implement first on CPAN/XS, then do
> it in core if that’s a success? Maybe if there’s a design document
> that describes the interface, etc. etc.

Hrm? CPAN has done all it can here. That syntax entirely works via
Syntax::Keyword::Try.

https://metacpan.org/pod/Syntax::Keyword::Try#catch-(Typed)

The only bit that's missing is that exceptions thrown by core perl
aren't typed, and that is the part my example rested on. I don't think
a CPAN module can fix that, it would have to be core's doing.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/