Thread overview
Template pattern delegate?
Oct 25, 2020
frame
Oct 25, 2020
Ali Çehreli
Oct 26, 2020
frame
Oct 26, 2020
Jacob Carlborg
Oct 26, 2020
frame
October 25, 2020
Is there a possibility to write templated code / custom trait pattern with usage like a delegate?

I have a try-catch block with different types and don't want to repeat myself in every method again. It's always the same, just what's tried changes, eg.:

pseudo code:

template myStuff(mixin code)
{
    try {
        code();
    }
    catch (X e) {
        ...
    }
    catch (Y e) {
        ...
    }
    ...
}

static myStuff!({
   writeln("...");
});

October 25, 2020
On 10/25/20 4:30 AM, frame wrote:
> Is there a possibility to write templated code / custom trait pattern with usage like a delegate?
> 
> I have a try-catch block with different types and don't want to repeat myself in every method again. It's always the same, just what's tried changes, eg.:
> 
> pseudo code:
> 
> template myStuff(mixin code)
> {
>      try {
>          code();
>      }
>      catch (X e) {
>          ...
>      }
>      catch (Y e) {
>          ...
>      }
>      ...
> }
> 
> static myStuff!({
>     writeln("...");
> });
> 

That's one of my DConf Onlide slides but for a limited use case! :)

int tried(Func, string functionName = __FUNCTION__, string file = __FILE__, size_t line = __LINE__)(Func func) {
  static if (!is (ReturnType!Func == int)) {
    pragma(msg, format!"\n%s(%s): Error: %s must return int error code"(file, line, functionName));
    static assert(false);
  }

  void printError(T)(T err) {
    stderr.writefln!"\n%s(%s): Failed to execute %s: %s"(file, line, functionName, err);
  }

  try {
    return func();

  } catch (Exception exc) {
    printError(exc.msg);
    return 1;

  } catch (Error err) {
    printError(err);
    import core.stdc.stdlib : abort;
    abort();
  }

  assert(false);
}

Then, all extern(C) functions would be written the same way:

extern(C) int foo() {
  return tried({
    // ...
    return 0;
  });
}

Ali

October 26, 2020
On Sunday, 25 October 2020 at 12:02:10 UTC, Ali Çehreli wrote:
> On 10/25/20 4:30 AM, frame wrote:
>> Is there a possibility to write templated code / custom trait pattern with usage like a delegate?
>> 
>> I have a try-catch block with different types and don't want to repeat myself in every method again. It's always the same, just what's tried changes, eg.:
>> 
>> pseudo code:
>> 
>> template myStuff(mixin code)
>> {
>>      try {
>>          code();
>>      }
>>      catch (X e) {
>>          ...
>>      }
>>      catch (Y e) {
>>          ...
>>      }
>>      ...
>> }
>> 
>> static myStuff!({
>>     writeln("...");
>> });
>> 
>
> That's one of my DConf Onlide slides but for a limited use case! :)
>
> int tried(Func, string functionName = __FUNCTION__, string file = __FILE__, size_t line = __LINE__)(Func func) {
>   static if (!is (ReturnType!Func == int)) {
>     pragma(msg, format!"\n%s(%s): Error: %s must return int error code"(file, line, functionName));
>     static assert(false);
>   }
>
>   void printError(T)(T err) {
>     stderr.writefln!"\n%s(%s): Failed to execute %s: %s"(file, line, functionName, err);
>   }
>
>   try {
>     return func();
>
>   } catch (Exception exc) {
>     printError(exc.msg);
>     return 1;
>
>   } catch (Error err) {
>     printError(err);
>     import core.stdc.stdlib : abort;
>     abort();
>   }
>
>   assert(false);
> }
>
> Then, all extern(C) functions would be written the same way:
>
> extern(C) int foo() {
>   return tried({
>     // ...
>     return 0;
>   });
> }
>
> Ali

I see that your approach can handle functions and delegates but isn't that not equivalent like this template for a function?

auto myStuff(T)(T function() fn) {
    try {
        return fn();
    }
    catch (Exception e) {
        //
    }
}

I wonder if I could use such a template as static variant and the compiler just expands the code? Just thinking that using a function or delegate is an overhead. Maybe not a function but a delegate will allocate GC memory I think.
October 26, 2020
On Monday, 26 October 2020 at 00:56:26 UTC, frame wrote:

> I see that your approach can handle functions and delegates but isn't that not equivalent like this template for a function?
>
> auto myStuff(T)(T function() fn) {
>     try {
>         return fn();
>     }
>     catch (Exception e) {
>         //
>     }
> }

You cannot pass a delegate to something that expects a function pointer.

> I wonder if I could use such a template as static variant and the compiler just expands the code? Just thinking that using a function or delegate is an overhead. Maybe not a function but a delegate will allocate GC memory I think.

If you pass the delegate as a template parameter/alias parameter, it's more likely to be inlined:

auto myStuff(alias fn)() {
    try return fn();
    catch (Exception e) { }
}

myStuff!( { /* some code */ } );

--
/Jacob Carlborg


October 26, 2020
On Monday, 26 October 2020 at 09:25:03 UTC, Jacob Carlborg wrote:
> On Monday, 26 October 2020 at 00:56:26 UTC, frame wrote:
>
>
> If you pass the delegate as a template parameter/alias parameter, it's more likely to be inlined:
>
> auto myStuff(alias fn)() {
>     try return fn();
>     catch (Exception e) { }
> }
>
> myStuff!( { /* some code */ } );
>
> --
> /Jacob Carlborg

Does not work in my case. Seems to conflict with overloads, but thanks for the hint.