Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a way to propagate exceptions in Junctions #6181

Closed
p6rt opened this issue Apr 7, 2017 · 12 comments
Closed

Implement a way to propagate exceptions in Junctions #6181

p6rt opened this issue Apr 7, 2017 · 12 comments
Labels
at_larry RFC Request For Comments

Comments

@p6rt
Copy link

p6rt commented Apr 7, 2017

Migrated from rt.perl.org#131118 (status was 'rejected')

Searchable as RT131118$

@p6rt
Copy link
Author

p6rt commented Apr 7, 2017

From @briandfoy

Consider this junction which you probably shouldn't make but you know
will happen in the hands of users​:

  any( 5, 'flarg' ) == 5

Despite having an element that satisfies the condition, it blows up
because one of them doesn't​:

  > any(5, "flarg") == 5
  Cannot convert string to number​: base-10 number must begin with
valid digits or '.' in '⏏flarg' (indicated by ⏏)
  in block <unit> at <unknown file> line 1

But, it should't matter that what happens with any other parts of the
junction if at least one of them satisfies the condition. You could,
for instance, evaluate that differently so the new junction looks
something like this​:

  any( True, Failure );

But, I don't think it should evaluate to another junction at all. The
comparison operator should evaluate to a Boolean. That Failure will
never matter because it's equivalent to False.

@p6rt
Copy link
Author

p6rt commented Apr 7, 2017

From @briandfoy

The person who sent me this example (and who wishes to remain anonymous), wants me to note that I didn't come up with this example. Specifically, "you should note that this bug report was generated who has never used perl6 in any form".

@p6rt
Copy link
Author

p6rt commented Apr 7, 2017

From @zoffixznet

On Fri, 07 Apr 2017 10​:08​:54 -0700, comdog wrote​:

Consider this junction which you probably shouldn't make but you know
will happen in the hands of users​:

any\( 5, 'flarg' \) == 5

Despite having an element that satisfies the condition, it blows up
because one of them doesn't​:

> any\(5, "flarg"\) == 5
Cannot convert string to number&#8203;: base\-10 number must begin with

valid digits or '.' in '⏏flarg' (indicated by ⏏)
in block <unit> at <unknown file> line 1

But, it should't matter that what happens with any other parts of the
junction if at least one of them satisfies the condition. You could,
for instance, evaluate that differently so the new junction looks
something like this​:

any\( True, Failure \);

But, I don't think it should evaluate to another junction at all. The
comparison operator should evaluate to a Boolean. That Failure will
never matter because it's equivalent to False.

FWIW the explosion doesn't involve Junctions​: "flarg".Numeric is a Failure, but then an attempt is made to use that failure to evaluate the `==` op, at which point that Failure's exception is actually thrown​:

  $ perl6 -e 'dd WHAT "flarg".Numeric'
  Failure
 
 
  $ perl6 -e 'dd WHAT "flarg" == 42'
  Cannot convert string to number​: base-10 number must begin with valid digits or '.' in '⏏flarg' (indicated by ⏏)
  in block <unit> at -e line 1
 
  Actually thrown at​:
  in block <unit> at -e line 1
 

@p6rt
Copy link
Author

p6rt commented Apr 7, 2017

The RT System itself - Status changed from 'new' to 'open'

@p6rt
Copy link
Author

p6rt commented Apr 7, 2017

From @zoffixznet

And if you just give a Failure into a Junction it doesn't explode it and propagates it​:

  m​: say so any("flarg",42)».Numeric
  rakudo-moar 15a25d​: OUTPUT​: «True␤»
 
  m​: say sub ($_) { .^name }( +any("flarg",42) )
  rakudo-moar 15a25d​: OUTPUT​: «any(Failure, Int)␤»

Wonder if there's a way to make it handle exceptions too somehow. A sort of Junctionized `try` block

@p6rt
Copy link
Author

p6rt commented Apr 7, 2017

From @AlexDaniel

Correct. This is not a bug for sure, but I wonder if there's anything we can improve.

I created a doc ticket here​: Raku/doc#1271

Now I wonder, can the backtrace mention that this was inside a junction? This will resolve the confusion, I think.

On 2017-04-07 10​:15​:55, cpan@​zoffix.com wrote​:

On Fri, 07 Apr 2017 10​:08​:54 -0700, comdog wrote​:

Consider this junction which you probably shouldn't make but you know
will happen in the hands of users​:

any( 5, 'flarg' ) == 5

Despite having an element that satisfies the condition, it blows up
because one of them doesn't​:

any(5, "flarg") == 5
Cannot convert string to number​: base-10 number must begin with
valid digits or '.' in '⏏flarg' (indicated by ⏏)
in block <unit> at <unknown file> line 1

But, it should't matter that what happens with any other parts of the
junction if at least one of them satisfies the condition. You could,
for instance, evaluate that differently so the new junction looks
something like this​:

any( True, Failure );

But, I don't think it should evaluate to another junction at all. The
comparison operator should evaluate to a Boolean. That Failure will
never matter because it's equivalent to False.

FWIW the explosion doesn't involve Junctions​: "flarg".Numeric is a
Failure, but then an attempt is made to use that failure to evaluate
the `==` op, at which point that Failure's exception is actually
thrown​:

$ perl6 -e 'dd WHAT "flarg".Numeric'
Failure

$ perl6 -e 'dd WHAT "flarg" == 42'
Cannot convert string to number​: base-10 number must begin with valid
digits or '.' in '⏏flarg' (indicated by ⏏)
in block <unit> at -e line 1

Actually thrown at​:
in block <unit> at -e line 1

@p6rt
Copy link
Author

p6rt commented Apr 8, 2017

From @LLFourn

The correct way to do this is any(5,"flarg") ~~ 5. ~~ is very tolerant. I
think it's generally considered a bug anytime ~~ throws an exception
because of invalid LHS. IMO any() junctions should propagate exceptions
regardless of whether one of its other values succeeded.

I tried to think of how I could use a particular comparison operator with a
junction and have it not throw exceptions but it didn't work​:

any(5,"flarg") ~~ { try $_ == 5 }

I guess bare blocks don't autothread because $_ is Mu, but I would have
thought ACCEPTS on Code would autothread but it seems it's also Mu (could
we change this?).

The best I can do is the rather hairy​:

say so any(5,"flarg") ~~ -> Any $_ { try $_ == 5 }

which also throws some "useless use of" exception for some reason :\

LL
On Sat, Apr 8, 2017 at 3​:28 AM Zoffix Znet via RT <
perl6-bugs-followup@​perl.org> wrote​:

And if you just give a Failure into a Junction it doesn't explode it and
propagates it​:

  m​: say so any("flarg",42)».Numeric
  rakudo-moar 15a25d​: OUTPUT​: «True␤»

  m​: say sub ($_) { .^name }( +any("flarg",42) )
  rakudo-moar 15a25d​: OUTPUT​: «any(Failure, Int)␤»

Wonder if there's a way to make it handle exceptions too somehow. A sort of
Junctionized `try` block

@p6rt
Copy link
Author

p6rt commented Apr 8, 2017

From @zoffixznet

On Fri, 07 Apr 2017 19​:09​:55 -0700, lloyd.fourn@​gmail.com wrote​:

IMO any() junctions should propagate exceptions regardless of whether one of its other values succeeded

Well, they do. The exception gets thrown. It just aborts all of the results. In a superimposition of multiple universes calculating $foo == 42, a crash in one universe crashes all of them :|

Would be interesting to see a Junctioned result in $! though :)

I think it's generally considered a bug anytime ~~ throws an exception because of invalid LHS

Yes. Please report anything that explodes in smartmatch. We recentlish fixed Str ~~ Numeric smartmatch exploding, so actually anyone on latest Rakudo Star would get an explosion in `"foo" ~~ 42`

I guess bare blocks don't autothread because $_ is Mu

That's correct. Only subs and methods default to Any. Variables, attributes, and block's params default to Mu type constraint. Asking for a `Mu` is a way to avoid Junctional autothreading in routines. You'll notice a Junction is a Mu, but unlike most Perl 6 classes, is not an Any.

thought ACCEPTS on Code would autothread but it seems it's also Mu (could
we change this?).

Changing it breaks 5 stresstests. We also smartmatch in `when` blocks and `where` constraints, so the impact would be far-reaching. Making ACCEPTS not accept a Mu breaks this code for example; it no longer prints the string​:

  $_ = 42|42; when *.so { say "there"}

@p6rt
Copy link
Author

p6rt commented Apr 8, 2017

From @briandfoy

On Fri, 07 Apr 2017 19​:09​:55 -0700, lloyd.fourn@​gmail.com wrote​:

The correct way to do this is any(5,"flarg") ~~ 5.

Well, for == you can do that. For other comparison operators, such as >, you can't. The point wasn't the particular test but rather the behavior when something wants to fail hard.

@p6rt
Copy link
Author

p6rt commented Apr 9, 2017

From @LLFourn

Thanks for doing that experiment. Not sure why the code breaks. But yeah on
second thought it was a bad idea. If something accepts a Mu in its
signature it should probably be given a Mu even with ~~.

LL

On Sat, Apr 8, 2017 at 12​:58 PM Zoffix Znet via RT <
perl6-bugs-followup@​perl.org> wrote​:

On Fri, 07 Apr 2017 19​:09​:55 -0700, lloyd.fourn@​gmail.com wrote​:

IMO any() junctions should propagate exceptions regardless of whether
one of its other values succeeded

Well, they do. The exception gets thrown. It just aborts all of the
results. In a superimposition of multiple universes calculating $foo == 42,
a crash in one universe crashes all of them :|

Would be interesting to see a Junctioned result in $! though :)

I think it's generally considered a bug anytime ~~ throws an exception
because of invalid LHS

Yes. Please report anything that explodes in smartmatch. We recentlish
fixed Str ~~ Numeric smartmatch exploding, so actually anyone on latest
Rakudo Star would get an explosion in `"foo" ~~ 42`

I guess bare blocks don't autothread because $_ is Mu

That's correct. Only subs and methods default to Any. Variables,
attributes, and block's params default to Mu type constraint. Asking for a
`Mu` is a way to avoid Junctional autothreading in routines. You'll notice
a Junction is a Mu, but unlike most Perl 6 classes, is not an Any.

thought ACCEPTS on Code would autothread but it seems it's also Mu (could
we change this?).

Changing it breaks 5 stresstests. We also smartmatch in `when` blocks and
`where` constraints, so the impact would be far-reaching. Making ACCEPTS
not accept a Mu breaks this code for example; it no longer prints the
string​:

$\_ = 42|42; when \*\.so \{ say "there"\}

@p6rt
Copy link
Author

p6rt commented May 6, 2017

From @zoffixznet

On Fri, 07 Apr 2017 10​:08​:54 -0700, comdog wrote​:

Consider this junction which you probably shouldn't make but you know
will happen in the hands of users​:

any\( 5, 'flarg' \) == 5

Despite having an element that satisfies the condition, it blows up
because one of them doesn't​:

> any\(5, "flarg"\) == 5
Cannot convert string to number&#8203;: base\-10 number must begin with

valid digits or '.' in '⏏flarg' (indicated by ⏏)
in block <unit> at <unknown file> line 1

But, it should't matter that what happens with any other parts of the
junction if at least one of them satisfies the condition. You could,
for instance, evaluate that differently so the new junction looks
something like this​:

any\( True, Failure \);

But, I don't think it should evaluate to another junction at all. The
comparison operator should evaluate to a Boolean. That Failure will
never matter because it's equivalent to False.

Thank you for the report. However, I'm going to reject the ticket.

As previous replies mentioned, there's no problem with Failures in a Junctions,
they work as any other value. The actual explosion in OP's code happens when one of the
Failures—created when 'flarg' was coerced to Numeric—is used as a value for
the purposes of evaluating the `==` op with it. That's when the Exception
gets thrown.

I'm unsure if one of the suggestions was to catch such exceptions and turn
them into Failures again... If it were, it's not a good idea, since Junctions
are not meant to be well-introspectable and just silencing exception like that
is bound to end in tears.

Some of the other suggestions were to make `try` Junctionable and stuff
a Junction into $! variable. If that's possible to do at all, IMO it should be
done as a trial in a module first, to evaluate usability and any issues
with the compatibility with core code.

Lastly, I added a 'Failures and Exceptions' section to Junction docs[^1] that
explains the issues raised in this ticket as well as shows some of possible
ways to attain the goals, if really necessary.

[1] Raku/doc@7628708

@p6rt
Copy link
Author

p6rt commented May 6, 2017

@zoffixznet - Status changed from 'open' to 'rejected'

@p6rt p6rt closed this as completed May 6, 2017
@p6rt p6rt added at_larry RFC Request For Comments labels Jan 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
at_larry RFC Request For Comments
Projects
None yet
Development

No branches or pull requests

1 participant