January 22, 2008
"naryl" <cy@ngs.ru> wrote in message news:op.t5auwulcqr3u58@iriwka...
> On Mon, 21 Jan 2008 18:57:34 +0300, Jarrett Billingsley <kb3ctd2@yahoo.com> wrote:
>>     if(_d_dynamic_cast(e, info))
>>         continue;
>>     else
>>         throw e;
>
> Isn't _d_dynamic_cast implementation specific?

Probably.  :\

But it at least exists in both phobos and Tango.


January 24, 2008
> Also, this function would be a great place to use a lazy void parameter for the toTry parameter ;)

Pardon me for being ignorant, but could you elaborate a little on this subject?



Jarrett Billingsley Wrote:

> "Christopher Wright" <dhasenan@gmail.com> wrote in message news:fn2bqa$25rl$1@digitalmars.com...
> >
> > Closest you could come, if you really didn't want to use a template, is:
> > void retryable(ClassInfo info, int times, void delegate() totry) {
> >    for (int i = 0; i < times; i++) {
> >        try {
> >           totry();
> >           break;
> >        } catch (Exception e) {
> >           if (e.classinfo is info) continue; else throw e;
> >        }
> >    }
> > }
> >
> > retryable(AbandonedMutexException.classinfo, 5, {writefln("Hi!");});
> 
> The only possible issue I could see with that would be if an exception were thrown that was derived from the type that you passed in, which, according to normal exception behavior, should still be caught.  What you have to do then is perform a dynamic cast.  There's no syntax for this, but you can hack around with some of the runtime functions to do the same thing.  Place:
> 
> extern(C) Object _d_dynamic_cast(Object o, ClassInfo c);
> 
> somewhere in your module, then in the catch clause of retryable:
> 
> catch(Exception e)
> {
>     if(_d_dynamic_cast(e, info))
>         continue;
>     else
>         throw e;
> }
> 
> That _should_ work.  It's doing the same thing as the cast operator would but without the pretty syntax.
> 
> Also, this function would be a great place to use a lazy void parameter for the toTry parameter ;)
> 
> 

January 24, 2008
"Hans-Eric Grönlund" <hasse42g@gmail.com> wrote in message news:fn9csm$109r$1@digitalmars.com...
>> Also, this function would be a great place to use a lazy void parameter
>> for
>> the toTry parameter ;)
>
> Pardon me for being ignorant, but could you elaborate a little on this subject?
>
>

:D

void retryable(ClassInfo info, int times, lazy void totry)
{
    for(int i = 0; i < times; i++)
    {
        try
        {
            totry();
            break;
        }
        catch(Exception e)
        {
            if(_d_dynamic_cast(e, info))
                continue;
            else
                throw e;
        }
    }
}

Notice that the body of the function has not changed, we still call totry as a function.

Lazy parameters are sort of syntactic sugar.  You put "lazy T" on a parameter, it is implicitly a "T delegate()".  The magic happens when the function is actually called.  With the old version that took a delegate, we had to write:

retryable(typeid(Exception), 5, { connectToDB(); });

But lazy parameters allow us to use a normal-looking expression there:

retryable(typeid(Exception), 5, connectToDB());

The compiler sees that that's a lazy parameter and implicitly converts it to a delegate literal with that code in it.

If you want to have more code in the lazy parameter, it gets a bit tricky:

retryable(typeid(Exception), 5,
{
    func1();
    func2();
    func3();
}()); // <<< notice extra set of parens here!

The reason we have to have that extra set of parens is that the compiler will wrap this in another delegate literal, leaving us (internally) with something like:

void __temp1()
{
    {
        func1();
        func2();
        func3();
    }();
}

If we don't put the call at the end of the delegate literal, your lazy parameter just defines a function and does nothing else.


1 2
Next ›   Last »