-
Notifications
You must be signed in to change notification settings - Fork 292
/
Failure.pod6
133 lines (83 loc) · 3.55 KB
/
Failure.pod6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
=begin pod
=TITLE class Failure
=SUBTITLE Delayed exception
class Failure { }
A C<Failure> is a I<soft> or I<unthrown> exception, usually generated by
calling C<&fail>. It acts as a wrapper around an L<Exception|/type/Exception> object.
Sink (void) context causes a Failure to throw, i.e. turn into a normal
exception.
Checking a Failure for truth (with the C<Bool> method) or definedness (with
the C<defined> method) marks the failure as handled, and causes it not to
throw in sink context anymore.
You can call the C<handled> method to check if a failure has been handled.
Calling methods on unhandled failures propagates the failure. The
specification says the result is another C<Failure>, in Rakudo it causes the
failure to throw.
=head1 Methods
=head2 method new
Defined as:
method new(Failure:D: $payload --> Failure)
Returns a new C<Failure> instance with the given payload. The latter can be
either an L<Exception|/type/Exception> or a payload for an C<Exception>. A typical payload
would be a C<Str> with an error message. A list of payloads is also accepted.
my $e = Failure.new(now.DateTime, 'WELP‼');
say $e;
CATCH{ default { say .^name, ': ', .Str } }
# OUTPUT: «X::AdHoc: 2017-09-10T11:56:05.477237ZWELP‼»
=head2 method handled
Defined as:
method handled(Failure:D: --> Bool:D)
Returns C<True> for handled failures, C<False> otherwise.
sub f() { fail }; my $v = f; say $v.handled; # OUTPUT: «False»
The C<handled> method is an lvalue, which means you can also use it to set the
handled state:
sub f() { fail }
my $v = f;
$v.handled = True;
say $v.handled; # OUTPUT: «True»
=head2 method exception
Defined as:
method exception(Failure:D: --> Exception)
Returns the L<Exception|/type/Exception> object that the failure wraps.
sub failer() { fail };
my $failure = failer;
my $ex = $failure.exception;
put "$ex.^name(): $ex";
# OUTPUT: «X::AdHoc: Failed»
=head2 method self
Defined as:
method self(Failure:D: --> Failure:D)
If the invocant is a L<handled|/routine/handled> C<Failure>, returns it as is.
If not handled, throws its L<Exception|/type/Exception>. Since
L<Mu|/type/Mu> type L«provides C<.self>|/type/Mu#method_self» for every
class, calling this method is a handy way to explosively
filter out Failures:
my $num1 = '♥'.Int;
# $num1 now contains a Failure object, which may not be desirable
my $num2 = '♥'.Int.self;
# .self method call on Failure causes an exception to be thrown
my $num3 = '42'.Int.self;
# Int type has a .self method, so here $num3 has `42` in it
(my $stuff = '♥'.Int).so;
say $stuff.self; # OUTPUT: «(HANDLED) Cannot convert string to number…»
# Here, Failure is handled, so .self just returns it as is
=head2 method Bool
Defined as:
multi method Bool(Failure:D: --> Bool:D)
Returns C<False>, and marks the failure as handled.
sub f() { fail }; my $v = f; say $v.handled; $v.Bool; say $v.handled;
# OUTPUT: «False
# True»
=head2 method Capture
Defined as:
method Capture()
Throws C<X::Cannot::Capture> if the invocant is a type object or a L<handled|/routine/handled>
L<Failure|/type/Failure>. Otherwise, throws the invocant's L<exception|/routine/exception>.
=head2 method defined
Defined as:
multi method defined(Failure:D: --> Bool:D)
Returns C<False> (failures are officially undefined), and marks
the failure as handled.
sub f() { fail }; my $v = f; say $v.defined; # OUTPUT: «False»
=end pod
# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6