www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - metaprogramming question

reply Graham Fawcett <fawcett uwindsor.ca> writes:
Hi folks,

I'd like to wrap a family of C functions that look like this:

      gboolean fooXXX(arg1, ..., argN, GError** err)

Their signatures and arities vary, but they all have a GError** as
their last argument. If a function returns false, then 'err' will be
set to a relevant Error struct.

I would like to write a wrapper that would let me call these functions
sort of like this:

      check!(fooXXX(arg1, ..., argN))

where the 'check' expression would be equivalent to:

      GError* err;
      bool ok = fooXXX(arg1, ..., argN, &err);
      if (!ok)
        throw new Exception((*err).message);

Does D (2.0) offer a metaprogramming technique I could use to
accomplish this -- particularly, to inject that 'err' argument into
the tail of the fooXXX call?

Thanks,
Graham
Apr 18 2010
next sibling parent reply Justin Spahr-Summers <Justin.SpahrSummers gmail.com> writes:
On Mon, 19 Apr 2010 00:12:28 +0000 (UTC), Graham Fawcett 
<fawcett uwindsor.ca> wrote:
 
 Hi folks,
 
 I'd like to wrap a family of C functions that look like this:
 
       gboolean fooXXX(arg1, ..., argN, GError** err)
 
 Their signatures and arities vary, but they all have a GError** as
 their last argument. If a function returns false, then 'err' will be
 set to a relevant Error struct.
 
 I would like to write a wrapper that would let me call these functions
 sort of like this:
 
       check!(fooXXX(arg1, ..., argN))
 
 where the 'check' expression would be equivalent to:
 
       GError* err;
       bool ok = fooXXX(arg1, ..., argN, &err);
       if (!ok)
         throw new Exception((*err).message);
 
 Does D (2.0) offer a metaprogramming technique I could use to
 accomplish this -- particularly, to inject that 'err' argument into
 the tail of the fooXXX call?
 
 Thanks,
 Graham

You can use some expression tuple magic to accomplish something like that: bool check(alias func, EL ...)() { GError* err; bool ok = func(EL, &err); if (!ok) throw new Exception((*err).message); return ok; } // used like: check!(fooXXX, arg1, ..., argN); See http://digitalmars.com/d/2.0/template.html#TemplateTupleParameter
Apr 18 2010
next sibling parent reply BCS <none anon.com> writes:
Hello Justin Spahr-Summers,

 On Mon, 19 Apr 2010 00:12:28 +0000 (UTC), Graham Fawcett
 <fawcett uwindsor.ca> wrote:
 
 Hi folks,
 
 I'd like to wrap a family of C functions that look like this:
 
 gboolean fooXXX(arg1, ..., argN, GError** err)
 
 Their signatures and arities vary, but they all have a GError** as
 their last argument. If a function returns false, then 'err' will be
 set to a relevant Error struct.
 
 I would like to write a wrapper that would let me call these
 functions sort of like this:
 
 check!(fooXXX(arg1, ..., argN))
 
 where the 'check' expression would be equivalent to:
 
 GError* err;
 bool ok = fooXXX(arg1, ..., argN, &err);
 if (!ok)
 throw new Exception((*err).message);
 Does D (2.0) offer a metaprogramming technique I could use to
 accomplish this -- particularly, to inject that 'err' argument into
 the tail of the fooXXX call?
 
 Thanks,
 Graham

that: bool check(alias func, EL ...)() { GError* err; bool ok = func(EL, &err); if (!ok) throw new Exception((*err).message); return ok; } // used like: check!(fooXXX, arg1, ..., argN);

IIRC that should be: check!(fooXXX, argType1, ..., argTypeN)(arg1, ..., argN);
 See http://digitalmars.com/d/2.0/template.html#TemplateTupleParameter
 

Or you can mangel that a bit: template check(alias func) { bool check(EL ...)() { GError* err; bool ok = func(EL, &err); if (!ok) throw new Exception((*err).message); return ok; } } that should allow you to call it like: check!(fooXXX)(arg1, ..., argN); -- ... <IXOYE><
Apr 18 2010
parent fawcett uwindsor.ca writes:
On 10-04-19 01:31 AM, BCS wrote:
 Hello Justin Spahr-Summers,

 On Mon, 19 Apr 2010 00:12:28 +0000 (UTC), Graham Fawcett
 <fawcett uwindsor.ca> wrote:

 Hi folks,

 I'd like to wrap a family of C functions that look like this:

 gboolean fooXXX(arg1, ..., argN, GError** err)

 Their signatures and arities vary, but they all have a GError** as
 their last argument. If a function returns false, then 'err' will be
 set to a relevant Error struct.

 I would like to write a wrapper that would let me call these
 functions sort of like this:

 check!(fooXXX(arg1, ..., argN))

 where the 'check' expression would be equivalent to:

 GError* err;
 bool ok = fooXXX(arg1, ..., argN, &err);
 if (!ok)
 throw new Exception((*err).message);
 Does D (2.0) offer a metaprogramming technique I could use to
 accomplish this -- particularly, to inject that 'err' argument into
 the tail of the fooXXX call?

 Thanks,
 Graham

that: bool check(alias func, EL ...)() { GError* err; bool ok = func(EL, &err); if (!ok) throw new Exception((*err).message); return ok; } // used like: check!(fooXXX, arg1, ..., argN);

IIRC that should be: check!(fooXXX, argType1, ..., argTypeN)(arg1, ..., argN);
 See http://digitalmars.com/d/2.0/template.html#TemplateTupleParameter

Or you can mangel that a bit: template check(alias func) { bool check(EL ...)() { GError* err; bool ok = func(EL, &err); if (!ok) throw new Exception((*err).message); return ok; } } that should allow you to call it like: check!(fooXXX)(arg1, ..., argN);

Remarkable! Thank you to everyone who responded. I can't wait to give these a try tonight. :) Cheers, Graham
Apr 19 2010
prev sibling next sibling parent Justin Spahr-Summers <Justin.SpahrSummers gmail.com> writes:
On Mon, 19 Apr 2010 07:28:09 +0200, Philippe Sigaud 
<philippe.sigaud gmail.com> wrote:
 
 On Mon, Apr 19, 2010 at 05:21, Justin Spahr-Summers <
 Justin.SpahrSummers gmail.com> wrote:
 
 You can use some expression tuple magic to accomplish something like
 that:

 bool check(alias func, EL ...)() {
    GError* err;
    bool ok = func(EL, &err);
     if (!ok)
        throw new Exception((*err).message);

     return ok;
 }

 // used like:
 check!(fooXXX, arg1, ..., argN);

them run-time values that way: bool check(alias func, EL ...)(EL el) { GError* err; bool ok = func(el, &err); if (!ok) throw new Exception((*err).message); return ok; } // used like: check!fooXXX(arg1, ..., argN);

Yes, sorry. That's what I was trying to do originally, but I couldn't quite spit it out. Indeed, templating the actual arguments is a horrible idea.
Apr 18 2010
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--00032555a25264a6e3048490828f
Content-Type: text/plain; charset=ISO-8859-1

On Mon, Apr 19, 2010 at 07:31, BCS <none anon.com> wrote:

 Or you can mangel that a bit:

 template check(alias func) {
  bool check(EL ...)() {

     GError* err;
     bool ok = func(EL, &err);
     if (!ok)
        throw new Exception((*err).message);
     return ok;
  }
 }

 that should allow you to call it like:

 check!(fooXXX)(arg1, ..., argN);

(I guess you meant bool check(EL...)(EL el) in the second stage.) Yes, this example is even more powerful. The version I posted already allows you to write check!fun(params); // no need to give explictly the EL, the compiler wil deduce them for you but yours allow you to 'store' the checking of fun and then to use it for any parameter typetuple. Maybe not useful for the OP, but mighty handy in some other cases. I discovered this trick a few weeks ago and, though a bitch to code sometimes, it's very nice to have. Usage: alias check!foo fooCheck; // checkFoo is a templated function, so it's _not_ a function. You cannot assign it to a variable. // use alias instead. // some other code // auto check1 = fooCheck(1,2,3); // auto check2 = fooCheck("a","b", 2.34); It's particularly useful when foo is polymorphic. Again, not interesting for the OP, but very fun. Philippe --00032555a25264a6e3048490828f Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <br><br><div class=3D"gmail_quote">On Mon, Apr 19, 2010 at 07:31, BCS <span= dir=3D"ltr">&lt;<a href=3D"mailto:none anon.com">none anon.com</a>&gt;</sp= an> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0p= t 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"> Or you can mangel that a bit:<br> <br> template check(alias func) {<br> =A0bool check(EL ...)() {<div class=3D"im"><br> =A0 =A0 GError* err;<br> =A0 =A0 bool ok =3D func(EL, &amp;err);<br> =A0 =A0 if (!ok)<br> =A0 =A0 =A0 =A0throw new Exception((*err).message);<br> =A0 =A0 return ok;<br> =A0}<br> }<br> <br></div> that should allow you to call it like:<br> <br> check!(fooXXX)(arg1, ..., argN);<font color=3D"#888888"></font></blockquote=
<div><br>(I guess you meant bool check(EL...)(EL el) in the second stage.)=

dy allows you to write <br> <br>check!fun(params); // no need to give explictly the EL, the compiler wi= l deduce them for you<br><br>=A0but yours allow you to &#39;store&#39; the = checking of fun and then to use it for any parameter typetuple. Maybe not u= seful for the OP, but mighty handy in some other cases.<br> I discovered this trick a few weeks ago and, though a bitch to code sometim= es, it&#39;s very nice to have.<br><br>Usage:<br><br>alias check!foo fooChe= ck; // checkFoo is a templated function, so it&#39;s _not_ a function. You = cannot assign it to a variable.<br> =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 // us= e alias instead.<br><br>// some other code //<br>auto check1 =3D fooCheck(1= ,2,3);<br>//<br>auto check2 =3D fooCheck(&quot;a&quot;,&quot;b&quot;, 2.34)= ;<br><br>It&#39;s particularly useful when foo is polymorphic. Again, not i= nteresting for the OP, but very fun.<br> <br>Philippe<br><br><br></div></div> --00032555a25264a6e3048490828f--
Apr 18 2010
prev sibling next sibling parent Daniel Keep <daniel.keep.lists gmail.com> writes:
http://while-nan.blogspot.com/2007/06/wrapping-functions-for-fun-and-profit.html

It shouldn't be too difficult to inject an extra parameter; just add it
to the end of the call to the wrapped function after args.
Apr 18 2010
prev sibling next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
--0015174c1442f7c064048490390d
Content-Type: text/plain; charset=ISO-8859-1

On Mon, Apr 19, 2010 at 05:21, Justin Spahr-Summers <
Justin.SpahrSummers gmail.com> wrote:

 You can use some expression tuple magic to accomplish something like
 that:

 bool check(alias func, EL ...)() {
    GError* err;
    bool ok = func(EL, &err);
     if (!ok)
        throw new Exception((*err).message);

     return ok;
 }

 // used like:
 check!(fooXXX, arg1, ..., argN);

them run-time values that way: bool check(alias func, EL ...)(EL el) { GError* err; bool ok = func(el, &err); if (!ok) throw new Exception((*err).message); return ok; } // used like: check!fooXXX(arg1, ..., argN); Of course, it'd be nice to check the EL at CT to see if they correspond to func parameters types. I don't know if you can do this with C functions, but for D funcs you can add: import std.traits; bool check(alias func, EL ...)(EL el) if (is(ParameterTypeTuple!func[0..$-1] == TypeTuple!(EL, GError*)) { ... It's a bit strict, as it doesn't deal with implicit conversions. Cheers, Philippe --0015174c1442f7c064048490390d Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <br><br><div class=3D"gmail_quote">On Mon, Apr 19, 2010 at 05:21, Justin Sp= ahr-Summers <span dir=3D"ltr">&lt;<a href=3D"mailto:Justin.SpahrSummers gma= il.com">Justin.SpahrSummers gmail.com</a>&gt;</span> wrote:<br><blockquote = class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px = solid rgb(204, 204, 204); padding-left: 1ex;"> <div><div></div>You can use some expression tuple magic to accomplish somet= hing like<br></div> that:<br> <br> bool check(alias func, EL ...)() {<br> =A0 =A0GError* err;<br> =A0 =A0bool ok =3D func(EL, &amp;err);<br> <div class=3D"im"> =A0 =A0if (!ok)<br> =A0 =A0 =A0 =A0throw new Exception((*err).message);<br> <br> </div> =A0 =A0return ok;<br> }<br> <br> // used like:<br> check!(fooXXX, arg1, ..., argN);<br> <br></blockquote><div><br>But in this case, you need to know the ELs at com= pile-time. You can make them run-time values that way:<br><br>bool check(al= ias func, EL ...)(EL el) {<br> =A0 =A0GError* err;<br> =A0 =A0bool ok =3D func(el, &amp;err);<br> <div class=3D"im"> =A0 =A0if (!ok)<br> =A0 =A0 =A0 =A0throw new Exception((*err).message);<br> <br> </div> =A0 =A0return ok;<br> }<br> <br> // used like:<br> check!fooXXX(arg1, ..., argN);<br><br><br>Of course, it&#39;d be nice to ch= eck the EL at CT to see if they correspond to func parameters types. I don&= #39;t know if you can do this with C functions, but for D funcs you can add= :<br> <br>import std.traits;<br>bool check(alias func, EL ...)(EL el) if (is(Para= meterTypeTuple!func[0..$-1] =3D=3D TypeTuple!(EL, GError*))<br>{<br>...<br>= <br>It&#39;s a bit strict, as it doesn&#39;t deal with implicit conversions= .<br> <br>Cheers,<br><br>=A0 Philippe<br><br></div></div> --0015174c1442f7c064048490390d--
Apr 18 2010
parent BCS <none anon.com> writes:
Hello Philippe,


 Of course, it'd be nice to check the EL at CT to see if they
 correspond to func parameters types.

The call inside check will coever that for you as long as you don't mind getting the error in an odd place. -- ... <IXOYE><
Apr 18 2010
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--00032555945e222fe5048490a5eb
Content-Type: text/plain; charset=ISO-8859-1

On Mon, Apr 19, 2010 at 07:43, Justin Spahr-Summers <
Justin.SpahrSummers gmail.com> wrote:

 Yes, sorry. That's what I was trying to do originally, but I couldn't
 quite spit it out. Indeed, templating the actual arguments is a horrible
 idea.

Sorry to comment on it, then. I'm discovering all this by myself, so I don't know if what I generally post is a well-known established practice or a nice trick few people use... (or a brillant idea only a genius could utter, but hey...) Just to complete it, and as it's on my mind: I found one case, yesterday, when you have to pass the args as CT args: filtering on a tuple. Strange idea maybe, but fun to code. That is: auto t = tuple(1, 'a', "abc", 3.14159); auto f = filterTuple!(polymorphicPredicate)(t); // should return a smaller tuple, with 1, 'a',... filtered according to polymPredicate This does not work, because I have to determine the return type of filterTuple as CT, obviously. And this return type in turn depends on the _values_ stored inside the tuple. At CT, I can check the types, but not the values, unless I use them as CT args: auto f = filterTuple!(polymorphicPredicate, t)(); But then, I'm limited by what you can use as a template parameter (not all possible D types are allowed, I think). Maybe as an alias... I'll stop, now, before derailing the thread. I'm trying to use tuples as a sort-of cousin of ranges, by mapping, chaining or truncating them... Philippe --00032555945e222fe5048490a5eb Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Mon, Apr 19, 2010 at 07:43, Justin Spahr-Summ= ers <span dir=3D"ltr">&lt;<a href=3D"mailto:Justin.SpahrSummers gmail.com">= Justin.SpahrSummers gmail.com</a>&gt;</span> wrote:<br><blockquote class=3D= "gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rg= b(204, 204, 204); padding-left: 1ex;"> <br> Yes, sorry. That&#39;s what I was trying to do originally, but I couldn&#39= ;t<br> quite spit it out. Indeed, templating the actual arguments is a horrible<br=

</blockquote></div><br>Sorry to comment on it, then. I&#39;m discovering al= l this by myself, so I don&#39;t know if what I generally post is a well-kn= own established practice or a nice trick few people use... (or a brillant i= dea only a genius could utter, but hey...)<br> <br>Just to complete it, and as it&#39;s on my mind: I found one case, yest= erday, when you have to pass the args as CT args: filtering on a tuple. Str= ange idea maybe, but fun to code.<br>That is:<br><br>auto t =3D tuple(1, &#= 39;a&#39;, &quot;abc&quot;, 3.14159);<br> auto f =3D filterTuple!(polymorphicPredicate)(t); // should return a smalle= r tuple, with 1, &#39;a&#39;,... filtered according to polymPredicate<br><b= r>This does not work, because I have to determine the return type of filter= Tuple as CT, obviously. And this return type in turn depends on the _values= _ stored inside the tuple. At CT, I can check the types, but not the values= , unless I use them as CT args:<br> auto f =3D filterTuple!(polymorphicPredicate, t)();<br><br>But then, I&#39;= m limited by what you can use as a template parameter (not all possible D t= ypes are allowed, I think). Maybe as an alias...<br><br>I&#39;ll stop, now,= before derailing the thread. I&#39;m trying to use tuples as a sort-of cou= sin of ranges, by mapping, chaining or truncating them...<br> <br>Philippe<br><br> --00032555945e222fe5048490a5eb--
Apr 18 2010