www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 1839] New: Give D a modern varargs system that allows forwarding

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839

           Summary: Give D a modern varargs system that allows forwarding
           Product: D
           Version: 2.010
          Platform: PC
        OS/Version: Windows
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: wbaxter gmail.com


Given function

void A(...) {
 ...
}

It should be possible to write a function wrapsA of this sort:

void wrapsA(...) {
    pre_call();
    A(...); // or whatever syntax you want for forwarding the varargs.
    post_call();
}

That D --  a supposedly modern, easy-to-use languages -- can't do this
conceptually simple thing is sad.

The whole point of procedural programming is that code is encapsulated into
reusable blocks.  Not being able to forward varargs means that a big chunk of
that reusability is lost any time you write a varargs function.  

The workaround is to write every varargs function in two flavors, one thats got
(...) args, and one that's got (_argptr,_arguments) args.  But if the solution
is so mechanical and straightforward then why can't the compiler at just do
that for us?  I'm not saying that's the right way to implement vararg
forwarding, but barring a more elegant solution, that sounds like at least a
plausible solution.


-- 
Feb 14 2008
next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 15/02/2008, d-bugmail puremagic.com <d-bugmail puremagic.com> wrote:
  That D --  a supposedly modern, easy-to-use languages -- can't do this
  conceptually simple thing is sad.

Will this not work? import std.traits; ReturnType!(f) wraps(alias f)(ParameterTypeTuple!(f) t) { pre_call(); ReturnType!(f) x = f(t); post_call(); return x; } wrap!(A)(params);
Feb 14 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839





------- Comment #2 from wbaxter gmail.com  2008-02-15 01:56 -------
Sometimes you can't / don't want to use a template.

If templates were an answer then we wouldn't need the regular vararg functions
to begin with.


-- 
Feb 14 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839





------- Comment #3 from wbaxter gmail.com  2008-02-15 01:58 -------
...and what is the parameter type tuple of a varargs function?  

I suspect that probably doesn't work actually.


-- 
Feb 14 2008
prev sibling next sibling parent reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839


andrei metalanguage.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |INVALID




------- Comment #4 from andrei metalanguage.com  2008-02-15 02:36 -------
"..."-style varargs predate template varargs and have a number of disadvantages
compared to them, so it is likely they will get deprecated in favor of
templates and macros.


-- 
Feb 15 2008
parent Lars Ivar Igesund <larsivar igesund.net> writes:
d-bugmail puremagic.com wrote:

 http://d.puremagic.com/issues/show_bug.cgi?id=1839

 
 ------- Comment #4 from andrei metalanguage.com  2008-02-15 02:36 -------
 "..."-style varargs predate template varargs and have a number of
 disadvantages compared to them, so it is likely they will get deprecated
 in favor of templates and macros.
 
 
 --

If there is absolutely no bloat when using such a template, only then will it be acceptible to remove a runtime alternative.
Feb 15 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839





------- Comment #5 from wbaxter gmail.com  2008-02-15 02:39 -------
If (...) functions go away, then yes, this bug report becomes pointless.  The
template versions of forwarding will do the trick.

But how do I create a delegate that takes an arbitrary list of arbitrary
arguments using templates?


-- 
Feb 15 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839





------- Comment #6 from andrei metalanguage.com  2008-02-15 02:47 -------
(In reply to comment #5)
 If (...) functions go away, then yes, this bug report becomes pointless.  The
 template versions of forwarding will do the trick.
 
 But how do I create a delegate that takes an arbitrary list of arbitrary
 arguments using templates?
 

import std.stdio; void before() {} void after() {} void forward(F, T...)(F fun, T args) { before(); scope(exit) after(); fun(args); } void main() { forward((int a) { writeln(a + 40); }, 2); } --
Feb 15 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839





------- Comment #7 from wbaxter gmail.com  2008-02-15 02:58 -------
I mean this:
----
void delegate(...) callback = &fn;

...

callback("hi", 10, "mom");
----

Does your snippet of code show how to do that?  If so, I'm not seeing the
connection, so please explain again.


-- 
Feb 15 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839





------- Comment #8 from andrei metalanguage.com  2008-02-15 03:35 -------
I misunderstood your initial code sample. In fact that's a simpler problem:

import std.stdio;

void before() {}
void after() {}

void fn(...)
{
    foreach (i; 0 .. _arguments.length)
    {
        _arguments[i].print;
    }
    if (_arguments[0] == typeid(int))
    {
        int j = *cast(int *)_argptr;
        writeln(j);
    }
}

void wrapsFn(T...)(T args)
{
    before();
    scope(exit) after();
    fn(args);
}

void main()
{
    wrapsFn(2, 42, "a");
}


-- 
Feb 15 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839





------- Comment #9 from aarti interia.pl  2008-02-15 04:16 -------
Isn't it that variable arguments templates have its own problems also? 

Executable size will increase very quickly for different types/combinations of
parameters. AFAIK it will happen especially when template body will be very
big. Sure you can split big template into smaller, but it means also that size
of program will heavily depend on coding style of programmer. Or is it possible
to optimize such a big template automagically?

But I think that, if variable argument templates are not able to be instant
replacement (considering e.g. size of executable), variable arguments functions
should stay...

When they would stay a few simple fixes would probably enhance current
situation in order of magnitude.

1. Defining struct, which will keep typeinfo pointer and data pointer
   e.g. struct Arg {TypeInfo type; void* ptr;}
2. Then variable argument functions could be declared like other type safe
variadic argument functions in D:
void func(Arg[] param...) {}

...and the problem with passing arguments would be solved... (also ugly local
variables (=hacks): _argptr, _arguments could disappear).


-- 
Feb 15 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839





------- Comment #10 from wbaxter gmail.com  2008-02-15 04:58 -------
(In reply to comment #8)
 I misunderstood your initial code sample. In fact that's a simpler problem:
 
 import std.stdio;
 
 void before() {}
 void after() {}
 
 void fn(...)
 {
     foreach (i; 0 .. _arguments.length)
     {
         _arguments[i].print;
     }
     if (_arguments[0] == typeid(int))
     {
         int j = *cast(int *)_argptr;
         writeln(j);
     }
 }
 
 void wrapsFn(T...)(T args)
 {
     before();
     scope(exit) after();
     fn(args);
 }
 
 void main()
 {
     wrapsFn(2, 42, "a");
 }
 

Ok, but it's no longer a function. I can't do with wrapFn the same things I can do with a regular function, namely taking it's address and passing that around or calling through it later. If there were a simple and efficient way to convert the wrapsFn template into a function pointer then I'd be satisfied with that solution. --
Feb 15 2008
prev sibling next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
<d-bugmail puremagic.com> wrote in message 
news:bug-1839-3 http.d.puremagic.com/issues/...
 http://d.puremagic.com/issues/show_bug.cgi?id=1839

           Summary: Give D a modern varargs system that allows forwarding
           Product: D
           Version: 2.010
          Platform: PC
        OS/Version: Windows
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: wbaxter gmail.com


 Given function

 void A(...) {
 ...
 }

 It should be possible to write a function wrapsA of this sort:

 void wrapsA(...) {
    pre_call();
    A(...); // or whatever syntax you want for forwarding the varargs.
    post_call();
 }

 That D --  a supposedly modern, easy-to-use languages -- can't do this
 conceptually simple thing is sad.

 The whole point of procedural programming is that code is encapsulated 
 into
 reusable blocks.  Not being able to forward varargs means that a big chunk 
 of
 that reusability is lost any time you write a varargs function.

 The workaround is to write every varargs function in two flavors, one 
 thats got
 (...) args, and one that's got (_argptr,_arguments) args.  But if the 
 solution
 is so mechanical and straightforward then why can't the compiler at just 
 do
 that for us?  I'm not saying that's the right way to implement vararg
 forwarding, but barring a more elegant solution, that sounds like at least 
 a
 plausible solution.

I'll suggest it again: given a typesafe variadic function whose variadic parameter's array element type is a struct: void A(Variant[] args...) calling that function: A(1, 2, "hi") should be sugar for: A(Variant(1), Variant(2), Variant("hi")) This alone would obviate the need for ... style vararg functions. A Variant array is far, far more useful than the platform-dependent hard-to-use inflexible _arguments/_argptr crap. And at the same time, solves the "OMG template bloat!!" problem.
Feb 15 2008
parent Lars Ivar Igesund <larsivar igesund.net> writes:
Jarrett Billingsley wrote:

 <d-bugmail puremagic.com> wrote in message
 news:bug-1839-3 http.d.puremagic.com/issues/...
 http://d.puremagic.com/issues/show_bug.cgi?id=1839

           Summary: Give D a modern varargs system that allows forwarding
           Product: D
           Version: 2.010
          Platform: PC
        OS/Version: Windows
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: wbaxter gmail.com


 Given function

 void A(...) {
 ...
 }

 It should be possible to write a function wrapsA of this sort:

 void wrapsA(...) {
    pre_call();
    A(...); // or whatever syntax you want for forwarding the varargs.
    post_call();
 }

 That D --  a supposedly modern, easy-to-use languages -- can't do this
 conceptually simple thing is sad.

 The whole point of procedural programming is that code is encapsulated
 into
 reusable blocks.  Not being able to forward varargs means that a big
 chunk of
 that reusability is lost any time you write a varargs function.

 The workaround is to write every varargs function in two flavors, one
 thats got
 (...) args, and one that's got (_argptr,_arguments) args.  But if the
 solution
 is so mechanical and straightforward then why can't the compiler at just
 do
 that for us?  I'm not saying that's the right way to implement vararg
 forwarding, but barring a more elegant solution, that sounds like at
 least a
 plausible solution.

I'll suggest it again: given a typesafe variadic function whose variadic parameter's array element type is a struct: void A(Variant[] args...) calling that function: A(1, 2, "hi") should be sugar for: A(Variant(1), Variant(2), Variant("hi")) This alone would obviate the need for ... style vararg functions. A Variant array is far, far more useful than the platform-dependent hard-to-use inflexible _arguments/_argptr crap. And at the same time, solves the "OMG template bloat!!" problem.

Only that that would move Variant into the runtime which is unfortunate.
Feb 15 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839





------- Comment #13 from andrei metalanguage.com  2008-02-15 16:32 -------
(In reply to comment #10)
 Ok, but it's no longer a function.  I can't do with wrapFn the same things I
 can do with a regular function, namely taking it's address and passing that
 around or calling through it later.  If there were a simple and efficient way
 to convert the wrapsFn template into a function pointer then I'd be satisfied
 with that solution.

I understand, and that's a good point. There can't be a conversion from that template to a delegate(...) without breaking type safety. Here are some other thoughts. 1. The feature you are suggesting offers diminishing returns. It will help people who: (a) write a ton of (...) functions so they hate the forwarding idea (b) don't like macros that would partially automate (a) (c) call a ton of (...) functions and work so any syntactical burden would be unacceptable (d) are in an environment such that template bloat is an issue There are things that D can't do today, and things that it can do in clunky ways that are encountered more often than the above. I think it's best we focus on those first. 2. That being said, I've tried to convice Walter of the utility of the "return goto" statement, which replaces one function entirely with another. That would be extremely cheap forwarding for a variety of cases, and would make tail recursion and mutual recursion obvious and documentable. If that feature were in, you'd have half of your needed feature: void foo(...) { ... } void callfoo(...) { before(); return goto foo; } You can't do an "after" action because the return goto statement effectively "execs" foo, and as such callfoo's frame ceases existence. This statement is easy to typecheck and generates good modular code, but it has certain limitations (e.g. callfoo cannot have scope() statements, locals with destructors etc.) So this feature would cover some things, and yours would cover some overlapping things. I'm not sure whether either or both have critical mass. Andrei --
Feb 15 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839


wbaxter gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|INVALID                     |




------- Comment #14 from wbaxter gmail.com  2008-02-15 17:04 -------
(In reply to comment #13)
 (In reply to comment #10)
 Ok, but it's no longer a function.  I can't do with wrapFn the same things I
 can do with a regular function, namely taking it's address and passing that
 around or calling through it later.  If there were a simple and efficient way
 to convert the wrapsFn template into a function pointer then I'd be satisfied
 with that solution.

I understand, and that's a good point. There can't be a conversion from that template to a delegate(...) without breaking type safety. Here are some other thoughts. 1. The feature you are suggesting offers diminishing returns. It will help people who: (a) write a ton of (...) functions so they hate the forwarding idea (b) don't like macros that would partially automate (a) (c) call a ton of (...) functions and work so any syntactical burden would be unacceptable (d) are in an environment such that template bloat is an issue

(e) want to have a callback/signal-slot/observer/notification system capable of using varargs functions as callbacks.
 There are things that D can't do today, and things that it can do in clunky
 ways that are encountered more often than the above. I think it's best we focus
 on those first.

Agreed. I certainly didn't mean to imply by filing this that I thought this problem should be prioritized over other pressing issues. But it's something that I've long found annoying and seen discussed at various time, and yet there didn't seem to be a bug/enh filed for it yet. But it seems in conclusion that you agree with me that this should not be marked "resolved invalid". --
Feb 15 2008
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1839


andrei metalanguage.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|REOPENED                    |ASSIGNED




------- Comment #15 from andrei metalanguage.com  2008-02-15 17:33 -------
(In reply to comment #14)
 (In reply to comment #13)
 There are things that D can't do today, and things that it can do in clunky
 ways that are encountered more often than the above. I think it's best we focus
 on those first.

Agreed. I certainly didn't mean to imply by filing this that I thought this problem should be prioritized over other pressing issues. But it's something that I've long found annoying and seen discussed at various time, and yet there didn't seem to be a bug/enh filed for it yet. But it seems in conclusion that you agree with me that this should not be marked "resolved invalid".

Oh. I planned to do so myself, but forgot while I was writing the post. Andrei --
Feb 15 2008