Loop Abstractions in D
One of the great things with Ruby is the natural way in which you can hide looping constructs behind descriptive names. Like the retryable example that Cheah Chu Yeow gives on his blog.
retryable(:tries => 5, :on => OpenURI::HTTPError) do open('http://example.com/flaky_api') end
Notice how elegantly the loop logic is abstracted; There’s no need to look at the implementation of retryable to figure out what it does. The question is, can we do something similar with D as well? It turns out that with features like delegates and function literals we can actually get pretty close.
bool retryable(int tries, void delegate() dg)
{
for(int i = tries; i > 0; i--)
{
try
{
dg();
return true;
}
catch
{
// Retry
}
}
return false;
}
Which can be used like this:
retryable(5, {
open("http://example.com/flaky_api");
}) ;
Not as nice as with Ruby, but almost.
The custom exception of the Ruby version is a tricky one to implement in D. Templates to our rescue.
bool retryable(E)(int tries, void delegate() dg)
{
for(int i = tries; i > 0; i--)
{
try
{
dg();
return true;
}
catch (E)
{
// Retry
}
}
return false;
}
With the (little bit odd) template syntax, we can then make retryable retry only when, for example, StdioExceptions are thrown.
retryable!(StdioException)(5, {
open("http://example.com/flaky_api");
}) ;
To clean it up a bit, we can add some defaults (which requires us to switch places between the parameters).
bool retryable(E = Exception)(void delegate() dg, int tries = 5)
{
for(int i = tries; i > 0; i--)
{
try
{
dg();
return true;
}
catch (E)
{
// Retry
}
}
return false;
}
That gives us a little more freedom when utilizing retryable.
retryable({
// Retry up to 5 times
});
retryable({
// Retry up to 10 times
}, 10);
retryable!(StdioException)({
// Retry up to three times
// on StdioException failures
}, 3);
I totally agree with Cheah Chu that Ruby is nice, but I think D is pretty cool too.
Cheers!
As usual, an interesting article.
As someone who is just learning D, your posts are very enlightening.
I wouldn’t mind D allowing a more similar syntax to Ruby’s blocks, but so far I am very impressed with D.
It reminds me of a mix of Delphi, C#, C and I suppose C++.
…Michael…
Thanks Michael!
Right on, and if I read the Internet vibes correctly we’ll soon see features in D that better support the functional programming paradigm. That’ll be interesting.
A for() loop would have been clearer; the marginal gains saved in keystrokes are lost in future readability (everyone reading that code from thereon in now has another badly named template to go grepping for).
I agree to some extent, but I do like the possibility to give complex loop logic descriptive names.
In Ruby it feels more natural though. I mean, one has to love code like this:
10.times do
# code goes here
end
A for loop can never communicate intention better than that.
Excellent!
Btw, you have an error in the cleanedup version, should be i– instead of i-
hm can’t seem to add two minuses in a row with comment system, but you know what I mean iminusminus
@Dominik
Ah, you’re right. Thanks for pointing it out. It’s WordPress that doesn’t handle code formatting very well. I fixed the problem temporarily (by switching minuses for -
@Dominik – again
Argh! The entity code translated into a -, but you know what I meant. I really need to find a solution to this…