Dart and Smalltalk have method cascades.
It seems that a similar style can be achieved via do with
.
For example, here's a simple program which uses GTK::Simple
:
use v6;
use GTK::Simple;
my $app = GTK::Simple::App.new(title => "abc");
$app.set-content(
GTK::Simple::VBox.new(
my $button_a = GTK::Simple::Button.new(label => 'bcd'),
my $button_b = GTK::Simple::Button.new(label => 'cde')
)
);
$app.border-width = 20;
$button_a.clicked.tap({ .sensitive = False; $button_b.sensitive = True });
$button_b.sensitive = False;
$button_b.clicked.tap({ $app.exit });
$app.run;
Here's the equivalent program using do with
in a few places to achive an effect similar to method cascades:
use v6;
use GTK::Simple;
my $app;
my $button_a;
my $button_b;
do with GTK::Simple::App.new(title => 'abc')
{
$app = $_;
.set-content(
GTK::Simple::VBox.new(
$button_a = do with GTK::Simple::Button.new(label => 'bcd')
{
.clicked.tap({ .sensitive = False; $button_b.sensitive = True });
$_
},
$button_b = do with GTK::Simple::Button.new(label => 'cde')
{
.sensitive = False;
.clicked.tap({ $app.exit });
$_
}
)
);
.border-width = 20;
.run;
};
My question is, is there a more idiomatic way to express the method cascade style in Perl 6?
A drawback to do with
is that you must explictly return $_
. With traditional method cascades, the original receiver object is implicitly returned.
For example, here's how $button_a
is set:
$button_a = do with GTK::Simple::Button.new(label => 'bcd')
{
.clicked.tap({ .sensitive = False; $button_b.sensitive = True });
$_
}
It would be nice if $_
didn't have to be explicly returned. For example, something like:
$button_a = do cascade GTK::Simple::Button.new(label => 'bcd')
{
.clicked.tap({ .sensitive = False; $button_b.sensitive = True });
}
Another drawback to do with
is that the syntax is more heavyweight than Dart and Smalltalk method cascade syntax. Something closer to the Dart style might look like:
$button_a = GTK::Simple::Button.new(label => 'bcd')
..clicked.tap({ .sensitive = False; $button_b.sensitive = True });
https://doc.perl6.org/routine/andthen
my $obj = IO::Path.new($*CWD) andthen do { .say; 42 }; say $obj.perl
With this subroutine:
sub cascade ($obj, &proc) { proc($obj); $obj; }
the example can be written as follows:
use v6;
use GTK::Simple;
sub cascade ($obj, &proc) { proc($obj); $obj; }
GTK::Simple::App.new(title => 'abc').&cascade: {
my $app = $_;
my $button;
.set-content:
GTK::Simple::VBox.new(
GTK::Simple::Button.new(label => 'bcd').&cascade: {
.clicked.tap({ .sensitive = False; $button.sensitive = True; });
};
$button = GTK::Simple::Button.new(label => 'cde').&cascade: {
.clicked.tap({ $app.exit; });
}
);
.border-width = 20;
.run;
};
I think using given
rather than do with
is more idiomatic for the exact same functionality. Given just passes whatever through as the topic $_
value for the following block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With