www.digitalmars.com         C & C++   DMDScript  

D - Variable arguments: opStream

reply Vathix <vathix dprogramming.com> writes:
Operators << and >> are for shifting, overloading opCall("like")("this") 
is ugly to me :P and hard to type. So I have yet another idea for 
type-safe variable arguments. Here's the idea in code:


class Foo
{
    char[] buf;
    void opStream(char[] x) { buf ~= x; }
    void opStream(char x) { buf ~= x; }
    void opStream(Object o) { buf ~= o.toString(); }
    char[] toString() { return buf; }
}


int main()
{
    Foo foo;
    foo$("this calls", " opStream for", " each parameter", '\n');
    printf("Foo = '%.*s'\n", foo.toString());
    return 0;
}


I just threw in the symbol $ so it doesn't conflict with opCall and so 
you can better understand what it's doing. opStream always has void 
return type and exactly one parameter. For input streams you could use 
out parameters.


-- 
Christopher E. Miller
Apr 17 2004
next sibling parent Patrick Down <pat codemoon.com> writes:
Vathix <vathix dprogramming.com> wrote in news:c5rhae$1eek$1
 digitaldaemon.com:

 Operators << and >> are for shifting, overloading opCall("like")("this") 
 is ugly to me :P and hard to type. So I have yet another idea for 
 type-safe variable arguments. 
This is like the proposal I had for opWrite and opRead a while back. In general I like the idea. http://www.digitalmars.com/drn-bin/wwwnews?D/19072
Apr 17 2004
prev sibling next sibling parent John Reimer <jjreimer telus.net> writes:
On Sat, 17 Apr 2004 11:09:04 -0400, Vathix wrote:

 Operators << and >> are for shifting, overloading opCall("like")("this")
 is ugly to me :P and hard to type. So I have yet another idea for
 type-safe variable arguments. Here's the idea in code:
 
 
 class Foo
 {
     char[] buf;
     void opStream(char[] x) { buf ~= x; } void opStream(char x) { buf ~=
     x; }
     void opStream(Object o) { buf ~= o.toString(); } char[] toString() {
     return buf; }
 }
 }
 
 int main()
 {
     Foo foo;
     foo$("this calls", " opStream for", " each parameter", '\n');
     printf("Foo = '%.*s'\n", foo.toString()); return 0;
 }
 }
 
 I just threw in the symbol $ so it doesn't conflict with opCall and so you
 can better understand what it's doing. opStream always has void return
 type and exactly one parameter. For input streams you could use out
 parameters.
I must admit that something along the lines of your opStream example does look desirable.
Apr 17 2004
prev sibling next sibling parent h3r3tic <h3r3tic_member pathlink.com> writes:
i like this idea, it reminds me of the Amos language :)
u have my vote ;)
Apr 17 2004
prev sibling next sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Vathix wrote:

 So I have yet another idea for type-safe variable arguments.
[...] This is not "another idea". You just specialized for streams my general proposal: pre- or postprocessing not possible; only one state in the declaration stage, therefore the next state implicitely denoted by void type; opCall renamed to opStream; at the call stage `,' instead of `;'. Would you please explain, why it would be good, to have another syntax extension for every special case that may arise? So long!
Apr 18 2004
parent reply Vathix <vathix dprogramming.com> writes:
Manfred Nowak wrote:
 Vathix wrote:
 
 
So I have yet another idea for type-safe variable arguments.
[...] This is not "another idea". You just specialized for streams my general proposal: pre- or postprocessing not possible; only one state in the declaration stage, therefore the next state implicitely denoted by void type; opCall renamed to opStream; at the call stage `,' instead of `;'. Would you please explain, why it would be good, to have another syntax extension for every special case that may arise? So long!
I have proposed many ideas here for type safe variable arguments; this is another one. I called it opStream because most (all?) cases where you want variable arguments is to stream data into an object. I am proposing a friendlier syntax, because foo("this is")(" using opCall")(" and doesn't")(" look")(" too pretty"), and the C++ method of using << and >> is out of the question. I don't stand by my proposals 100%, I just say what is interesting to me and hope it is inspiring to improve anything. -- Christopher E. Miller
Apr 18 2004
next sibling parent Manfred Nowak <svv1999 hotmail.com> writes:
Vathix wrote:

[...]
 I am proposing a friendlier syntax, because foo("this is")(" using
 opCall") (" and doesn't")(" look")(" too pretty")
[...] Agreed. However: foo("this is"; " using opCall"; " and doesn't"; "look"; " too pretty") is not lookimg that bad. So long!
Apr 18 2004
prev sibling parent reply Mike <Mike_member pathlink.com> writes:
Hi!

I have proposed many ideas here for type safe variable arguments; this 
is another one. I called it opStream because most (all?) cases where you 
want variable arguments is to stream data into an object. I am proposing 
a friendlier syntax, because foo("this is")(" using opCall")(" and 
doesn't")(" look")(" too pretty"), and the C++ method of using << and >> 
is out of the question. I don't stand by my proposals 100%, I just say 
what is interesting to me and hope it is inspiring to improve anything.
I'm a C++ programmer interested in switching to D, however I dislike not having cin and cout in D. I understand that the << and >> operators are out of question, but since D eliminated the need for a -> operator couldn't you just use <- and -> for streaming? int i; cin -> i; cout <- "i is " <- i <- endl; That would call cin.opStreamIn and cout.opStreamOut ... bad idea? -Mike
Apr 19 2004
next sibling parent Mike <Mike_member pathlink.com> writes:
After thinking a bit about it I came up with an extended solution. No opStream,
but a new keyword ("streaming" or "multi" or whatever):

class bar
{

/* The "streaming" keyword (or "multi" or whatever) declares a property as
"streamable" */

streaming void foo1(int i) { /* ... */ }
streaming void foo1(char c) { /* ... */}

streaming void foo2(int i) { /* ... */}
streaming void foo2(char c) { /* ... */}

streaming int foo1() { return /* ... */}
streaming char foo1() { return /* ... */}

streaming int foo2() { return /* ... */}
streaming char foo2() { return /* ... */}

/* ... */

}

Later on:

bar b;
int i = 3;
char c = 'a'
b.foo1 <- i <- c; // calls void bar.foo1(i) and void bar.foo1(c)
b.foo2 -> i -> c; // calls int bar.foo2() and char bar.foo2()

Maybe you find that plausible in some way or the other, but I think that
wouldn't be too bad :-)

-Mike
Apr 19 2004
prev sibling parent reply John Reimer <jjreimer telus.net> writes:
 I'm a C++ programmer interested in switching to D, however I dislike not having
 cin and cout in D.
 
 I understand that the << and >> operators are out of question, but since D
 eliminated the need for a -> operator couldn't you just use <- and -> for
 streaming?
 
 int i;
 cin -> i;
 cout <- "i is " <- i <- endl;
 
 That would call cin.opStreamIn and cout.opStreamOut ... bad idea?
 
 -Mike
 
 
<< and >> are not out of the question, just likely not preferred by some programmers (probably the reason this discussion doesn't explore them: they're looking for a better way). The DSC.io project provides these C++-style stream operators as well as a different variation. It's the programmers choice as to which to use in an application. This very nicely implemented library is being discussed at www.dscource.org, and I believe is close to beta access so that others can play with it (I'm really, really hoping ;-) ).
Apr 19 2004
next sibling parent John Reimer <jjreimer telus.net> writes:
 << and >> are not out of the question, just likely not preferred by some 
 programmers (probably the reason this discussion doesn't explore them: 
 they're looking for a better way).  The DSC.io project provides these 
 C++-style stream operators as well as a different variation.  It's the 
 programmers choice as to which to use in an application.  This very 
 nicely implemented library is being discussed at www.dscource.org, and I 
 believe is close to beta access so that others can play with it (I'm 
 really, really hoping ;-) ).
Argh! I meant www.dsource.org, of course.
Apr 19 2004
prev sibling parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"John Reimer" <jjreimer telus.net> wrote in message
news:c6137v$vh9$1 digitaldaemon.com...
 I'm a C++ programmer interested in switching to D, however I dislike not
having
 cin and cout in D.

 I understand that the << and >> operators are out of question, but since
D
 eliminated the need for a -> operator couldn't you just use <- and ->
for
 streaming?

 int i;
 cin -> i;
 cout <- "i is " <- i <- endl;

 That would call cin.opStreamIn and cout.opStreamOut ... bad idea?

 -Mike
<< and >> are not out of the question, just likely not preferred by some
Yes they are (unfortunatelly) out of the questions because the order of chained << or >> isn't defined :(
 programmers (probably the reason this discussion doesn't explore them:
 they're looking for a better way).  The DSC.io project provides these
 C++-style stream operators as well as a different variation.  It's the
 programmers choice as to which to use in an application.  This very
 nicely implemented library is being discussed at www.dscource.org, and I
 believe is close to beta access so that others can play with it (I'm
 really, really hoping ;-) ).
Apr 19 2004
parent reply John Reimer <jjreimer telus.net> writes:
 
 Yes they are (unfortunatelly) out of the questions because the order of
 chained << or >> isn't defined :(
 
Are we talking about a different implementation? I'm just saying that it must be possible to do in D. Kris's DSC.io library does this Stdout << x << "this is a test" << y << Stdout.newline; ... and it works flawlessly. Am I missing something?
Apr 19 2004
parent reply John Reimer <jjreimer telus.net> writes:
John Reimer wrote:

 Yes they are (unfortunatelly) out of the questions because the order of
 chained << or >> isn't defined :(
Are we talking about a different implementation? I'm just saying that it must be possible to do in D. Kris's DSC.io library does this Stdout << x << "this is a test" << y << Stdout.newline; ... and it works flawlessly. Am I missing something?
Sorry, where x and y are int or some other numerical type.
Apr 19 2004
parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"John Reimer" <jjreimer telus.net> wrote in message
news:c616ir$16o5$2 digitaldaemon.com...
 John Reimer wrote:

 Yes they are (unfortunatelly) out of the questions because the order of
 chained << or >> isn't defined :(
Are we talking about a different implementation? I'm just saying that it must be possible to do in D. Kris's DSC.io library does this Stdout << x << "this is a test" << y << Stdout.newline; ... and it works flawlessly. Am I missing something?
Sorry, where x and y are int or some other numerical type.
I have also written a class that can be used like that (i will have to check it out to see how it works for classes) But the problem is that someone on this newsgroup said that the order of execution of chained << is implementation specific and code shouldn't be written that depends on this order. I'm not sure if this is true but it is what i read!
Apr 19 2004
parent reply Mike <Mike_member pathlink.com> writes:
Hmm ... I thought it would be out of discussion because in D things like having
the << operator working as streaming AND shifting operator should be avoided.
Therefore I thought using <- and -> could be a good idea. Introducing new
operators with defined behaviour wouldn't be that bad.

Anyway, after being a lurker here for a couple of weeks and being interested in
D I just wanted to express my wish for something similar to cin/cout in D - I'll
have a look at the classes on dsource. You know, I'd certainly like to get rid
of that stupid printf once and for all, really :-)

Good night,
-Mike
Apr 19 2004
parent John Reimer <jjreimer telus.net> writes:
Mike wrote:

 Hmm ... I thought it would be out of discussion because in D things like having
 the << operator working as streaming AND shifting operator should be avoided.
 Therefore I thought using <- and -> could be a good idea. Introducing new
 operators with defined behaviour wouldn't be that bad.
 
 Anyway, after being a lurker here for a couple of weeks and being interested in
 D I just wanted to express my wish for something similar to cin/cout in D -
I'll
 have a look at the classes on dsource. You know, I'd certainly like to get rid
 of that stupid printf once and for all, really :-)
 
 Good night,
 -Mike
 
 
Hey Mike, I brought it up because I realize that some programmers seem to have a real bond with the << and >> operators for stream use, especially when they come from C++ (I can't stand this use of shift operators myself). DSC.io allows use of them on both linux and windows. The library also provides an alternative method that I prefer. The other method is basically a form of multiple function calls. You'll have to see it. These methods could likely be improved upon, but it's nice just to know that we have something other than printf and <<, >>. There is not much documentation for the project yet other than in-source comments and sample unittest code which sufficient for the most part. The author, Kris, is getting ready to release the source at www.dsource.org soon.
Apr 19 2004
prev sibling next sibling parent reply Ben Hinkle <bhinkle4 juno.com> writes:
Vathix wrote:
 Operators << and >> are for shifting, overloading opCall("like")("this") 
 is ugly to me :P and hard to type. So I have yet another idea for 
 type-safe variable arguments. Here's the idea in code:
 
 
 class Foo
 {
    char[] buf;
    void opStream(char[] x) { buf ~= x; }
    void opStream(char x) { buf ~= x; }
    void opStream(Object o) { buf ~= o.toString(); }
    char[] toString() { return buf; }
 }
 
 
 int main()
 {
    Foo foo;
    foo$("this calls", " opStream for", " each parameter", '\n');
    printf("Foo = '%.*s'\n", foo.toString());
    return 0;
 }
Instead of calling these ideas "type safe variable arguments" I think it should be called something like "syntactic sugar for multiple function calls". Manfred's idea of using ";" was similar and it took me forever to realize he wasn't talking about arguments to one function call - he was talking about making multiple function calls. This is quite different from variable arguments using a single function call and I'd expect C/C++ users to see something that looks like a regular function call and expect it to behave like a regular function call. The concept of "varargs" or "variable arguments" has always been applied to a single function call so we should keep it that way. These ideas have been bouncing around at least since Walter's original opCall input/output idea: http://www.digitalmars.com/drn-bin/wwwnews?D/18945 I'm sure you're aware of the history since you mention opCall but not everyone might know what motivates these proposals. -Ben ps - the posting I made a while back http://www.digitalmars.com/drn-bin/wwwnews?D/26932 was what I thought Manfred was talking about with "type-safe variable arguments" since it allows vararg style calls with type checking.
Apr 18 2004
next sibling parent reply Vathix <vathix dprogramming.com> writes:
Ben Hinkle wrote:

 Vathix wrote:
 
 Operators << and >> are for shifting, overloading 
 opCall("like")("this") is ugly to me :P and hard to type. So I have 
 yet another idea for type-safe variable arguments. Here's the idea in 
 code:


 class Foo
 {
    char[] buf;
    void opStream(char[] x) { buf ~= x; }
    void opStream(char x) { buf ~= x; }
    void opStream(Object o) { buf ~= o.toString(); }
    char[] toString() { return buf; }
 }


 int main()
 {
    Foo foo;
    foo$("this calls", " opStream for", " each parameter", '\n');
    printf("Foo = '%.*s'\n", foo.toString());
    return 0;
 }
Instead of calling these ideas "type safe variable arguments" I think it should be called something like "syntactic sugar for multiple function calls". Manfred's idea of using ";" was similar and it took me forever to realize he wasn't talking about arguments to one function call - he was talking about making multiple function calls. This is quite different from variable arguments using a single function call and I'd expect C/C++ users to see something that looks like a regular function call and expect it to behave like a regular function call. The concept of "varargs" or "variable arguments" has always been applied to a single function call so we should keep it that way.
All right, good point. So foo("hello"; " world"); would be at least foo("hello"); foo(" world"); I like it.. Sorry about my post. -- Christopher E. Miller
Apr 18 2004
parent Ben Hinkle <bhinkle4 juno.com> writes:
 All right, good point.
 So
     foo("hello"; " world");
 would be at least
     foo("hello");
     foo(" world");
 I like it..
 Sorry about my post.
Ack - I didn't mean to imply your idea was a bad one. I just don't think it should be called "variable arguments". Whether a semi-colon or $ or something else is used is somewhat secondary. Heck, back in Walter's original thread there were probably other suggestions - well, those who read closely can find I suggested the syntax foo[a,b,c] http://www.digitalmars.com/drn-bin/wwwnews?D/19001 So you see I think the general idea is just swell. -Ben
Apr 19 2004
prev sibling parent Manfred Nowak <svv1999 hotmail.com> writes:
Ben Hinkle wrote:

[...]
 This is quite  different from variable arguments using a single function call
[...] I do not see the difference you are proposing here. If the details of the declaration of such a, lets call it "variadic object", are hidden it would become indistinguishable from a function. I do not see a need to keep up the feeling of "variadic objects" must be functions. I already gave a _working_ example of a generic "variadic object" of a list that is able to adapt to every codable type. None of the proposals I have seen so far has even proposed to be able to do that. Furthermore: by changing the states of a "variadic object" from structs to classes it seems possible to "derive" "variadic objects" from given ones, thereby expanding the language that is accepted by such a "derived variadic object". How does this fit into the feeling of a function? By hiding the details of a declaration I mean something like: variadic( ( T1, T2)*:R ){ R result; // declarations // preprocess switch{ // only one state needed in this special case case T1 p1: // declarations // do something with p1 and result case T2 p2: // declarations // do something else with p2 and result } // postprocess return R; } At the call side: T1 ap1, ap3; T2 ap2; R res; // prepare the call res= variadic( ap1, ap2, ap3); Now please explain why you still consider this as multiple function calls.
 These ideas have been bouncing around at least since Walter's original
 opCall input/output idea:
   http://www.digitalmars.com/drn-bin/wwwnews?D/18945
 I'm sure you're aware of the history since you mention opCall but not
 everyone might know what motivates these proposals.
Thanks! That was some weeks before I started digging into D. I therefore did not notice, that Walter has already laid out the playgrounds of such _packaged_ opCalls and I am somehow reinventing a wheel. Please note, that in the example given above it is very well possible to nest the calls of the "variadic object" provided, that the return types are assigned properly: res= variadic( ap1, variadic( ap2, ap3), ap4);
 ps - the posting I made a while back
    http://www.digitalmars.com/drn-bin/wwwnews?D/26932
 was what I thought Manfred was talking about with "type-safe variable
 arguments" since it allows vararg style calls with type checking.
Commented on it. So long!
Apr 18 2004
prev sibling parent "Scott Egan" <scotte tpg.com.aux> writes:
I know I'm going to get shot for this but...

Why don't we just byte the bullet and allow the opCat to be used, eg

steram.writeLine("Fred was here in: " ~ date ~ ". He has been here " ~ n ~ "
times before.");

Don't hit me too hard.


"Vathix" <vathix dprogramming.com> wrote in message
news:c5rhae$1eek$1 digitaldaemon.com...
 Operators << and >> are for shifting, overloading opCall("like")("this")
 is ugly to me :P and hard to type. So I have yet another idea for
 type-safe variable arguments. Here's the idea in code:


 class Foo
 {
     char[] buf;
     void opStream(char[] x) { buf ~= x; }
     void opStream(char x) { buf ~= x; }
     void opStream(Object o) { buf ~= o.toString(); }
     char[] toString() { return buf; }
 }


 int main()
 {
     Foo foo;
     foo$("this calls", " opStream for", " each parameter", '\n');
     printf("Foo = '%.*s'\n", foo.toString());
     return 0;
 }


 I just threw in the symbol $ so it doesn't conflict with opCall and so
 you can better understand what it's doing. opStream always has void
 return type and exactly one parameter. For input streams you could use
 out parameters.


 -- 
 Christopher E. Miller
Apr 19 2004