Mailing List Archive

Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings]
On Wed, 8 Jun 2022 09:04:23 +0200
Alexander Hartmaier <alex.hartmaier@gmail.com> wrote:

> I really wonder that I've never read a blog post or mailing list
> thread about the lack in exception handling in Perl 5. It's my
> biggest pain point with Perl 5 and I'd love to help to improve the
> situation!

Well-volunteered :)

If you want to assist, probably the first main question that needs
answering is working out what the programmer-visible API on these
things ought to be.

While it is initially tempting to suggest that `catch` would expose
core-thrown exceptions as objects, there is already a problem here. In
the past 20-odd years, the $@ variable (and more recently catch) have
always exposed core-thrown exceptions as plain strings; anything that
appears as an object must have been some user-thrown object:

use builtin 'blessed';

try {
maybe_call_a_func();
}
catch ($e) {
if(blessed $e) {
warn "Caught a user-defined exception of type " . (blessed $e);
}
else {
warn "Caught a plain stringy exception";
}
}

What should we do here?

1) Throw objects of some core-defined type, so `ref` and `blessed` are
now true on these things, meaning they can be distinguished -
including by some sort of `isa` test as might someday be added to
`catch`, but thus breaking all existing code which inspects $@ or
$e.

2) Throw plain strings that have some other, new way to query some
hidden "error type" information stored within them. Maybe lets
invent some new `builtin` funcs and imagine a hypothetical future

use builtin 'extype';

...
catch($e) {
my $t = extype $e;
if($t eq "SOMETHING") { ... }
elsif ...
}

Here the model is that $@ or catch would expose "exception values";
things that look and feel like plain strings (and so not upsetting
`ref` or `blessed`, etc...) but nevertheless have extra information
about the exception stored inside them. There's also then temptation
to add other information:

my $errno = exerrno $e; # $!, like ENOENT, EACCESS, ...
my @callers = excallers $e; # each value looking like the result
# of caller()
etc...

Once we have an `extype` that can query on the type string(?) or
other information stored inside an error value, it becomes tempting
to try to get `try`/`catch` in on the action as well:

try { ... }
catch($e extype X::ENOENT) { warn "File missing" }
catch($e extype X::EACCESS) { warn "Access not permitted" }
...

This is partly the reason why `try`/`catch` syntax is still marked
experimental. I still want to save room to add things like this.

The Syntax::Keyword::Try CPAN module already permits `catch` blocks
conditional on object type or stringy regexp match (the latter
simply because of core's existing message strings):

try { ... }
catch($e isa X::SomeExceptionClass) { ... }
catch($e =~ m/^Can't call method ".*" on an undefined value at /) { ... }

It'd be great to have something better than these really fragile
string matches here.


0) Do nothing and leave the situation as it is.


Currently, perl core has taken option 0. I want to change this.

I don't like option 1 because of all the breakage it causes.

I think option 2 could work but it needs a lot more careful design
work, thinking, (pre)RFCs writing, etc...

Do you want to help with that?

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
> What should we do here?
>
> 1) Throw objects of some core-defined type, so `ref` and `blessed` are
> now true on these things, meaning they can be distinguished -
> including by some sort of `isa` test as might someday be added to
> `catch`, but thus breaking all existing code which inspects $@ or
> $e.
>

What about ref == false, blessed == true scenario?
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
> On Jun 8, 2022, at 07:12, Paul LeoNerd Evans <leonerd@leonerd.org.uk> wrote:
>
> use builtin 'blessed';
>
> try {
> maybe_call_a_func();
> }
> catch ($e) {
> if(blessed $e) {
> warn "Caught a user-defined exception of type " . (blessed $e);
> }
> else {
> warn "Caught a plain stringy exception";
> }
> }
>
> What should we do here?
>
> 1) Throw objects of some core-defined type, so `ref` and `blessed` are
> now true on these things, meaning they can be distinguished -
> including by some sort of `isa` test as might someday be added to
> `catch`, but thus breaking all existing code which inspects $@ or
> $e.

Worth clarifying: this won’t “break all existing code which inspects $@ or $e”; it would only break code that expects exception objects to be user-thrown errors.

(I know, of course, that you know that, but IMO it’s worth being specific about the scope.)

FWIW, I’ve never written such code. Whenever I care about an error object’s blessed-ness, I check its class. So I’d write, e.g.:

-----
try {
throw_object();
}
catch ($e isa Some::TLS::X::Base) {
# It’s a TLS-level error
}
catch ($e isa IO::Socket::X::Base) {
# It’s a socket-level error
}
catch ($e) {
warn "Some unhandled error: $e";
}
-----

I can’t speak for what others may have written, of course.

> 2) Throw plain strings that have some other, new way to query some
> hidden "error type" information stored within them. Maybe lets
> invent some new `builtin` funcs and imagine a hypothetical future
>
> use builtin 'extype';
>
> ...
> catch($e) {
> my $t = extype $e;
> if($t eq "SOMETHING") { ... }
> elsif ...
> }

Attaching metadata to plain scalars could be powerful. It feels like it would encourage “weirdness”, but I haven’t researched it. I know decorator-type things are a common feature in other languages.

-FG
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
Thanks for your lengthy response Paul!
I'm also happy that there is already quite some feedback!

On Wed, Jun 8, 2022 at 1:13 PM Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
wrote:

> On Wed, 8 Jun 2022 09:04:23 +0200
> Alexander Hartmaier <alex.hartmaier@gmail.com> wrote:
>
> > I really wonder that I've never read a blog post or mailing list
> > thread about the lack in exception handling in Perl 5. It's my
> > biggest pain point with Perl 5 and I'd love to help to improve the
> > situation!
>
> Well-volunteered :)
>

mst took over your mail account!


>
> If you want to assist, probably the first main question that needs
> answering is working out what the programmer-visible API on these
> things ought to be.
>
> While it is initially tempting to suggest that `catch` would expose
> core-thrown exceptions as objects, there is already a problem here. In
> the past 20-odd years, the $@ variable (and more recently catch) have
> always exposed core-thrown exceptions as plain strings; anything that
> appears as an object must have been some user-thrown object:
>
> use builtin 'blessed';
>
> try {
> maybe_call_a_func();
> }
> catch ($e) {
> if(blessed $e) {
> warn "Caught a user-defined exception of type " . (blessed $e);
> }
> else {
> warn "Caught a plain stringy exception";
> }
> }
>
> What should we do here?
>
> 1) Throw objects of some core-defined type, so `ref` and `blessed` are
> now true on these things, meaning they can be distinguished -
> including by some sort of `isa` test as might someday be added to
> `catch`, but thus breaking all existing code which inspects $@ or
> $e.
>
> 2) Throw plain strings that have some other, new way to query some
> hidden "error type" information stored within them. Maybe lets
> invent some new `builtin` funcs and imagine a hypothetical future
>
> use builtin 'extype';
>
> ...
> catch($e) {
> my $t = extype $e;
> if($t eq "SOMETHING") { ... }
> elsif ...
> }
>
> Here the model is that $@ or catch would expose "exception values";
> things that look and feel like plain strings (and so not upsetting
> `ref` or `blessed`, etc...) but nevertheless have extra information
> about the exception stored inside them. There's also then temptation
> to add other information:
>
> my $errno = exerrno $e; # $!, like ENOENT, EACCESS, ...
> my @callers = excallers $e; # each value looking like the result
> # of caller()
> etc...
>
> Once we have an `extype` that can query on the type string(?) or
> other information stored inside an error value, it becomes tempting
> to try to get `try`/`catch` in on the action as well:
>
> try { ... }
> catch($e extype X::ENOENT) { warn "File missing" }
> catch($e extype X::EACCESS) { warn "Access not permitted" }
> ...
>
> This is partly the reason why `try`/`catch` syntax is still marked
> experimental. I still want to save room to add things like this.
>
> The Syntax::Keyword::Try CPAN module already permits `catch` blocks
> conditional on object type or stringy regexp match (the latter
> simply because of core's existing message strings):
>
> try { ... }
> catch($e isa X::SomeExceptionClass) { ... }
> catch($e =~ m/^Can't call method ".*" on an undefined value at /) {
> ... }
>
> It'd be great to have something better than these really fragile
> string matches here.
>
>
> 0) Do nothing and leave the situation as it is.
>
>
> Currently, perl core has taken option 0. I want to change this.
>
> I don't like option 1 because of all the breakage it causes.
>
> I think option 2 could work but it needs a lot more careful design
> work, thinking, (pre)RFCs writing, etc...
>

3) use a new variable that holds the exception object and populate $@ with
its string representation?


> Do you want to help with that?
>

Yes!


> --
> Paul "LeoNerd" Evans
>
> leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
> http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
>
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
On Wed, 8 Jun 2022 14:06:01 +0200
Branislav Zahradník <happy.barney@gmail.com> wrote:

> > What should we do here?
> >
> > 1) Throw objects of some core-defined type, so `ref` and `blessed`
> > are now true on these things, meaning they can be distinguished -
> > including by some sort of `isa` test as might someday be added
> > to `catch`, but thus breaking all existing code which inspects $@ or
> > $e.
> >
>
> What about ref == false, blessed == true scenario?

That's not going to work. Don't forget these aren't boolean-returning
functions.. They return the class into which the item is blessed, or
undef if it isn't.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
On Wed, Jun 8, 2022 at 2:39 PM Felipe Gasper <felipe@felipegasper.com>
wrote:

> Attaching metadata to plain scalars could be powerful. It feels like it
> would encourage “weirdness”, but I haven’t researched it. I know
> decorator-type things are a common feature in other languages.
>

Side note: there are many awesome things we could do with metadata, if we
could find a decent API. The difference between "uninitialized" and
"undefined" would be amazing. Pseudo-code because I have no idea what an
API would look like:

sub name ($self, ?$name) {
if ( not builtin:uninitialized($name) ) {
# or: builtin:initialized($name) would return true even if
undef
$self->{name} = $name;
}
return $name;
}

That would make it *much easier* to eliminate @_.

Best,
Ovid
CTO, All Around the World
World-class software development and consulting
https://allaroundtheworld.fr/
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
On Wed, Jun 8, 2022 at 1:13 PM Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
wrote:

> What should we do here?
>
> 1) Throw objects of some core-defined type, so `ref` and `blessed` are
> now true on these things, meaning they can be distinguished -
> including by some sort of `isa` test as might someday be added to
> `catch`, but thus breaking all existing code which inspects $@ or
> $e.
>
>

<snip>

>
> I don't like option 1 because of all the breakage it causes.
>

Paul, can you elaborate on the breakage? If try {...} catches non-blessed
errors and upgrades them to a Exception::Legacy object which stringifies
(or numifies) on demand (feature guarded, of course), why does this break
stuff? Maybe I missed it in the thread, and I'm sure there will be code
which still breaks, but it seems the majority of legacy code would work
with this (especially since the majority of legacy code doesn't use your
try/catch).

Ovid
CTO, All Around the World
World-class software development and consulting
https://allaroundtheworld.fr/
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
On Wed, 8 Jun 2022 18:17:44 +0200
Ovid <curtis.poe@gmail.com> wrote:

> Paul, can you elaborate on the breakage? If try {...} catches
> non-blessed errors and upgrades them to a Exception::Legacy object
> which stringifies (or numifies) on demand (feature guarded, of
> course), why does this break stuff? Maybe I missed it in the thread,
> and I'm sure there will be code which still breaks, but it seems the
> majority of legacy code would work with this (especially since the
> majority of legacy code doesn't use your try/catch).

Ah, now that's an interesting thought. Combined with:

On Wed, 8 Jun 2022 16:06:47 +0200
Alexander Hartmaier <alex.hartmaier@gmail.com> wrote:

> 3) use a new variable that holds the exception object and populate $@
> with its string representation?

This might actually be a thing.

We can't change the existing behaviour of $@, but we *could* create
some other variable, say, ${^EXCEPTION}, that would receive these new
objects, and say that actually the catch var uses that instead:

try { ... }
catch($e) {
if($e isa X::Perl::ENOENT) { ... }
}

These objects could then have whatever new interface we decided.

If the user is still using "legacy" eval-and-$@ then they'll receive a
stringified version of the object in that case, so as to not break
legacy behaviour.

I could imagine that being a thing.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
On 6/8/22 10:25, Paul "LeoNerd" Evans wrote:
> On Wed, 8 Jun 2022 18:17:44 +0200
> Ovid <curtis.poe@gmail.com> wrote:
>
>> Paul, can you elaborate on the breakage? If try {...} catches
>> non-blessed errors and upgrades them to a Exception::Legacy object
>> which stringifies (or numifies) on demand (feature guarded, of
>> course), why does this break stuff? Maybe I missed it in the thread,
>> and I'm sure there will be code which still breaks, but it seems the
>> majority of legacy code would work with this (especially since the
>> majority of legacy code doesn't use your try/catch).
>
> Ah, now that's an interesting thought. Combined with:
>
> On Wed, 8 Jun 2022 16:06:47 +0200
> Alexander Hartmaier <alex.hartmaier@gmail.com> wrote:
>
>> 3) use a new variable that holds the exception object and populate $@
>> with its string representation?
>
> This might actually be a thing.
>
> We can't change the existing behaviour of $@, but we *could* create
> some other variable, say, ${^EXCEPTION}, that would receive these new
> objects, and say that actually the catch var uses that instead:
>
> try { ... }
> catch($e) {
> if($e isa X::Perl::ENOENT) { ... }
> }
>
> These objects could then have whatever new interface we decided.
>
> If the user is still using "legacy" eval-and-$@ then they'll receive a
> stringified version of the object in that case, so as to not break
> legacy behaviour.
>
> I could imagine that being a thing.
>
+1
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
2022-6-9 1:26 Paul "LeoNerd" Evans <leonerd@leonerd.org.uk> wrote:

>
> > 3) use a new variable that holds the exception object and populate $@
> > with its string representation?
>
> This might actually be a thing.
>
> We can't change the existing behaviour of $@, but we *could* create
> some other variable, say, ${^EXCEPTION}, that would receive these new
> objects, and say that actually the catch var uses that instead:
>
> try { ... }
> catch($e) {
> if($e isa X::Perl::ENOENT) { ... }
> }
>
> These objects could then have whatever new interface we decided.
>
> If the user is still using "legacy" eval-and-$@ then they'll receive a
> stringified version of the object in that case, so as to not break
> legacy behaviour.
>
>
I feel good.

try - catch is yet experimental. In the only case of try - catch (remaining
of the behavior eval {}; if ($@) { } ), the content of "$e" can be changed.
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
On Wed, Jun 8, 2022 at 6:25 PM Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
wrote:

> > Paul, can you elaborate on the breakage? If try {...} catches
> > non-blessed errors and upgrades them to a Exception::Legacy object
> > which stringifies (or numifies) on demand <snip>
>
> Ah, now that's an interesting thought. Combined with:
>
> On Wed, 8 Jun 2022 16:06:47 +0200
> Alexander Hartmaier <alex.hartmaier@gmail.com> wrote:
>
> > 3) use a new variable that holds the exception object and populate $@
> > with its string representation?
>
> This might actually be a thing.
>
> We can't change the existing behaviour of $@, but we *could* create
> some other variable, say, ${^EXCEPTION}, that would receive these new
> objects, and say that actually the catch var uses that instead:
>
> try { ... }
> catch($e) {
> if($e isa X::Perl::ENOENT) { ... }
> }
>
> These objects could then have whatever new interface we decided.
> <leonerd@leonerd.org.uk>


And if we want to go even further, this is from the Carp documentation:

BUGS
The Carp routines don't handle exception objects currently. If called
with
a first argument that is a reference, they simply call die() or warn(),
as
appropriate.


Might be something interesting to consider there.

Best,
Ovid
CTO, All Around the World
World-class software development and consulting
https://allaroundtheworld.fr/
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
On Wed, Jun 8, 2022, at 07:12, Paul "LeoNerd" Evans wrote:
> While it is initially tempting to suggest that `catch` would expose
> core-thrown exceptions as objects, there is already a problem here. In
> the past 20-odd years, the $@ variable (and more recently catch) have
> always exposed core-thrown exceptions as plain strings; anything that
> appears as an object must have been some user-thrown object:

I believe you eventually came around to agreeing that this made sense. "catch ($e)" could get an object in $e, while $@ would remain a string. (You did this through the creation of a hypothetical ${^EXCEPTION}, but I think it's largely immaterial.)

This likely means that try/catch remain experimental a bit longer, but also seems well worth it to me.

--
rjbs
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
On Sat, Jun 18, 2022 at 2:20?AM Ricardo Signes <perl.p5p@rjbs.manxome.org>
wrote:

> On Wed, Jun 8, 2022, at 07:12, Paul "LeoNerd" Evans wrote:
>
> While it is initially tempting to suggest that `catch` would expose
> core-thrown exceptions as objects, there is already a problem here. In
> the past 20-odd years, the $@ variable (and more recently catch) have
> always exposed core-thrown exceptions as plain strings; anything that
> appears as an object must have been some user-thrown object:
>
>
> I believe you eventually came around to agreeing that this made sense.
> "catch ($e)" could get an object in $e, while $@ would remain a string.
> (You did this through the creation of a hypothetical ${^EXCEPTION}, but I
> think it's largely immaterial.)
>
> This likely means that try/catch remain experimental a bit longer, but
> also seems well worth it to me.
>
> --
> rjbs
>

@Ovid: I hope you're lurking around here. I just read your post at
https://www.reddit.com/r/perl/comments/1515tkj/what_do_we_need_for_perl_8/
and wanted you to point here regarding the native exception proposal which
I'm also highly interessted in but wasn't able to accomplish it alone.

Count me in if/when design on it starts!
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
On Wed, 8 Jun 2022 at 13:13, Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
wrote:

> On Wed, 8 Jun 2022 09:04:23 +0200
> Alexander Hartmaier <alex.hartmaier@gmail.com> wrote:
>
> > I really wonder that I've never read a blog post or mailing list
> > thread about the lack in exception handling in Perl 5. It's my
> > biggest pain point with Perl 5 and I'd love to help to improve the
> > situation!
>
> Well-volunteered :)
>
> If you want to assist, probably the first main question that needs
> answering is working out what the programmer-visible API on these
> things ought to be.
>
> While it is initially tempting to suggest that `catch` would expose
> core-thrown exceptions as objects, there is already a problem here. In
> the past 20-odd years, the $@ variable (and more recently catch) have
> always exposed core-thrown exceptions as plain strings;


FWIW, this partially interacts with a bug which I fixed in 5.38. I say
partially because the core does indeed put a string in $@, but it combined
with a bug in how eval was handled that $SIG{__DIE__} was not executed for
compile errors consistently such that code that expected to upgrade those
string errors into exception objects would not execute. IN 5.38 i fixed
eval so that if it dies during compilation it will always call
$SIG{__DIE__} and thus any handlers intended to upgrade $@ to an object
will now fire consistently.


anything that
> appears as an object must have been some user-thrown object:
>
> use builtin 'blessed';
>
> try {
> maybe_call_a_func();
> }
> catch ($e) {
> if(blessed $e) {
> warn "Caught a user-defined exception of type " . (blessed $e);
> }
> else {
> warn "Caught a plain stringy exception";
> }
> }
>
> What should we do here?
>
> 1) Throw objects of some core-defined type, so `ref` and `blessed` are
> now true on these things, meaning they can be distinguished -
> including by some sort of `isa` test as might someday be added to
> `catch`, but thus breaking all existing code which inspects $@ or
> $e.
>
> 2) Throw plain strings that have some other, new way to query some
> hidden "error type" information stored within them. Maybe lets
> invent some new `builtin` funcs and imagine a hypothetical future
>

The problem with throwing objects is that there is no standard way to allow
them to be modified by the calling code to add data to the error. With
strings it is obvious how you can change them, but unfortunately you change
the context the error was thrown from.

For example in

eval $code or die "While executing $code: $@";

the error is extended, but its source changes. The error would be reported
as coming from the line where the eval was executed, not where the
exception actually occurred.

cheers,
Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
On 2023-07-17 17:15, demerphq wrote:
>
> The problem with throwing objects is that there is no standard way to
> allow them to be modified by the calling code to add data to the
> error. With strings it is obvious how you can change them, but
> unfortunately you change the context the error was thrown from.
>
> For example in
>
> eval $code or die "While executing $code: $@";
>
> the error is extended, but its source changes. The error would be
> reported as coming from the line where the eval was executed, not
> where the exception actually occurred.
>

I think we also still have @@ available, to use as a stack.

Maybe $@ should represent $@[-1].

-- Ruud
Re: Core exception types [was: Re: Pre-RFC: Improve “wide character” warnings] [ In reply to ]
On Mon, Jul 17, 2023 at 5:16?PM demerphq <demerphq@gmail.com> wrote:

>
> The problem with throwing objects is that there is no standard way to
> allow them to be modified by the calling code to add data to the error.
> With strings it is obvious how you can change them, but unfortunately you
> change the context the error was thrown from.
>

Far beyond the scope of what I have bandwidth for right now, but for one
large client, I implemented a core exception mechanism for their ORM. What
surprised me is every place the code would die, it would catch the error.
If it was an object, it would die with the object. If it was a plain
string, it would promote it to a "generic" exception object. All objects
had overloaded stringification to ensure the previous code worked as
expected, even when we hit messes like this:

try {
$customer->update(@args);
}
catch ($error) {
if ( $error =~ /bad version number/ ) {
...
}
}

In short, *every* exception was an object. Honestly, given the
multi-million line size of their code base, I'm surprised it worked so
seamlessly, with old code working exactly as expected, but new code being
able to query the object, even when it used to be a plain die.

I imagine having die return an object with overloaded stringification might
not scale for the darkpan. That's mainly because I know there are going to
be edge cases I haven't thought about, but there's a potential path forward.

Best,
Ovid
--
Curtis "Ovid" Poe
--
CTO, All Around the World
World-class software development and consulting
https://allaroundtheworld.fr/