July 12, 2007
> 
> Yuck. Operator overloading should not be ambiguous. Each operator should mean one thing and one thing only, or as close as possible. When I see ++ in code, it should indicate that some form of incrementation is going on, not that something is being sent to a stream somewhere. I shouldn't need to know the context in which the operator is being used in order to determine what is going on. There's absolutely no reason to use operator overloads for IO when function calls do the job just fine.
> 
> The use of << and >> for IO in C++ is one of that languages nastiest features. Anything remotely resembling it has no place in D.

Well yes and no. I find myself using the << and >> operators to mean streaming 99% of the time. I use them for shifting much less often.
I thought I read that the argument about operator overloading was one reason D wasn't going to have it a while back. A year or two on and here we are.
I don't want to have to use format strings because of the type safety issues (unless you go down the C# {} route)

stdout << foo << bar << 2 << std::endl;

Is more concise than:

stdout.write(foo);
stdout.write(bar);
stdout.write(2);
stdout.wrteln();

and type safe compared to:

stdout.writefln("%s%s%i", foo,bar,2);

as nothing ensures foo and bar are strings or 2 is a integer or even that there are enough arguments at compile time.

A compromise like the following
still wouldn't solve the number of arguments problem.

typeinfo[] types = { char[], char[], int };
stdout.write("%%%", types, foo, bar, 2);


lint for C would probably tell me to add a ,0 as a sentinel as well. With true arrays that shouldn't be a problem for D.

Can we do some clever template foo to make something like the following work?

typeinfo[] types = { char[], char[], int };
object[] args = { foo, bar, 2 };
stdout.write!(types, object);

Of course then I'd want a way of constructing lists of objects easily like

foo+bar+2 or cons(foo,bar,2); or use write!(typeinfo[],...)

but crucially one that works at compile time.
Actually why bother with the typeinfo[] at all.

How about:

stdout.write!(...)  -->  foreach (arg;list) { stdout.write(list); }

but with typeof or some such template foo to make it expand at compile time. I think this would remove the need for << by turning:

cout << foo << bar << 2 << endl;

into:

stdout.write!(foo,bar,2,endl);

Any takers?
Look like I still want an IO manipulator class hierarchy.

Regards,

Bruce.




July 12, 2007
Bruce Adams escribió:
> 
> and type safe compared to:
> 
> stdout.writefln("%s%s%i", foo,bar,2);
> 

D has typesafe variadics, so you can just say:

dout.writefln("%s%s%s", foo,bar,2);

%s doesn't mean "pretend it's a string," but rather "write its string representation."

-- 
Carlos Santander Bernal
July 12, 2007
Carlos Santander Wrote:

> Bruce Adams escribió:
> > 
> > and type safe compared to:
> > 
> > stdout.writefln("%s%s%i", foo,bar,2);
> > 
> 
> D has typesafe variadics, so you can just say:
> 
> dout.writefln("%s%s%s", foo,bar,2);
> 
> %s doesn't mean "pretend it's a string," but rather "write its string representation."
> 
> -- 
> Carlos Santander Bernal

I see. That makes quite a lot of difference. Now is there a way to remove the format string entirely.
  a) as a function
  b) as a template that can be expanded at compile time.

It sounds like its trivial to write a) if it doesn't already exist. Hopefully, it does though.

Regards,

Bruce.

July 12, 2007
Carlos Santander wrote:
> Bruce Adams escribió:
>>
>> and type safe compared to:
>>
>> stdout.writefln("%s%s%i", foo,bar,2);
>>
> 
> D has typesafe variadics, so you can just say:
> 
> dout.writefln("%s%s%s", foo,bar,2);

Or just dout.writefln(foo,bar,2); in this case.


> %s doesn't mean "pretend it's a string," but rather "write its string representation."

I agree that compile time type-checked format parameters would be nice.

  writefln("%d", someObject);

  >> ERROR: someObject is not an integer

Would be nice.  A couple of people were trying to get this to work using compile time string processing.  Maybe they'll pipe in here at some point...

--bb
July 12, 2007
Bruce Adams wrote:
> Carlos Santander Wrote:
> 
>> Bruce Adams escribió:
>>> and type safe compared to:
>>>
>>> stdout.writefln("%s%s%i", foo,bar,2);
>>>
>> D has typesafe variadics, so you can just say:
>>
>> dout.writefln("%s%s%s", foo,bar,2);
>>
>> %s doesn't mean "pretend it's a string," but rather "write its string representation."
>>
>> -- 
>> Carlos Santander Bernal
> 
> I see. That makes quite a lot of difference. Now is there a way to remove the format string entirely.
>   a) as a function
>   b) as a template that can be expanded at compile time.

Easier than that:

writefln("This is test number ", i, " out of ", num_tests, " test(s).");

But it doesn't really buy you any safety over the %s version.  It doesn't do anything differently except maybe avoid a tiny bit of string processing to extract and replace the "%s" strings.


> It sounds like its trivial to write a) if it doesn't already exist. Hopefully, it does though.


--bb
July 12, 2007
"Bruce Adams" <tortoise_74@ya.nos.pam.hoo.co.uk> wrote in message news:f7445a$1g7g$1@digitalmars.com...
> I see. That makes quite a lot of difference. Now is there a way to remove
> the format string entirely.
>  a) as a function
>  b) as a template that can be expanded at compile time.
>
> It sounds like its trivial to write a) if it doesn't already exist. Hopefully, it does though.

Bill showed one way to do it with writefln, which still happens all at runtime.  Another way is with variadic templates:

void myWritefln(T...)(T args)
{
    foreach(arg; args)
        writef("%s", arg);

    writefln();
}

myWritefln("Hi! ", 5, " that's all.");

There are a few things to note about this:

1) That foreach loop in the function is actually run at compile time and unrolled; if you call this function with three arguments, the body will be repeated three times, once for each argument.

2) You don't necessarily have to use writef[ln]() on the inside; you could use this to wrap Tango-style (blah)(x) output in a more natural-looking function call.

3) The issue with this is code bloat -- an instance of this template is created for each separate list of parameter types.

(But ignoring the code bloat, it's just too damn cool of a feature not to use it ;) )

Furthermore some people (as has been mentioned in this thread) have been working on compile-time formatting which checks that the formatting strings match up, typewise, with their arguments.


July 12, 2007
Jarrett Billingsley Wrote:

> "Bruce Adams" <tortoise_74@ya.nos.pam.hoo.co.uk> wrote in message news:f7445a$1g7g$1@digitalmars.com...
> > I see. That makes quite a lot of difference. Now is there a way to remove
> > the format string entirely.
> >  a) as a function
> >  b) as a template that can be expanded at compile time.
> >
> > It sounds like its trivial to write a) if it doesn't already exist. Hopefully, it does though.
> 
> Bill showed one way to do it with writefln, which still happens all at runtime.  Another way is with variadic templates:
> 
> void myWritefln(T...)(T args)
> {
>     foreach(arg; args)
>         writef("%s", arg);
> 
>     writefln();
> }
> 
> myWritefln("Hi! ", 5, " that's all.");
> 
> There are a few things to note about this:
> 
> 1) That foreach loop in the function is actually run at compile time and unrolled; if you call this function with three arguments, the body will be repeated three times, once for each argument.
> 
I believe this is exactly what I'm looking for.
I see this is actually in the example for variadic templates.
http://www.digitalmars.com/d/variadic-function-templates.html

Just one small problem. I can't get it to compile. At first I thought
you were using incomplete/pseudo code to demonstrate but now I'm guessing maybe the compiler I'm using is incomplete.

void myWritefln(T...)(T args)    // line 7
{
    foreach(arg; args)               // line 9
        writef("%s", arg);

    writefln();
}

test.d:7: found '...' when expecting ')'
test.d:7: semicolon expected following function declaration
test.d:7: Declaration expected, not ')'
test.d:9: no identifier for declarator args
test.d:9: semicolon expected, not ')'
test.d:9: Declaration expected, not ')'
test.d:12: no identifier for declarator writefln
test.d:13: unrecognized declaration

F:\projects>gdc --version
gdc (GCC) 3.4.4 (cygming special, gdc 0.23, using dmd 1.007))

Before I post this as a bug can someone check I haven't made a noob error.

Regards,

Bruce.


July 12, 2007
Bruce Adams wrote:
> Jarrett Billingsley Wrote:
> 
[snip]
>> void myWritefln(T...)(T args)
>> {
>>     foreach(arg; args)
>>         writef("%s", arg);
>>
>>     writefln();
>> }
>>
>> myWritefln("Hi! ", 5, " that's all.");
>>
[snip]
>>
> I believe this is exactly what I'm looking for.
> I see this is actually in the example for variadic templates.
> http://www.digitalmars.com/d/variadic-function-templates.html
> 
> Just one small problem. I can't get it to compile. At first I thought
> you were using incomplete/pseudo code to demonstrate but now I'm guessing maybe the compiler I'm using is incomplete.
> 
> void myWritefln(T...)(T args)    // line 7
> {
>     foreach(arg; args)               // line 9
>         writef("%s", arg);
> 
>     writefln();
> }
> 
> test.d:7: found '...' when expecting ')'
> test.d:7: semicolon expected following function declaration
> test.d:7: Declaration expected, not ')'
> test.d:9: no identifier for declarator args
> test.d:9: semicolon expected, not ')'
> test.d:9: Declaration expected, not ')'
> test.d:12: no identifier for declarator writefln
> test.d:13: unrecognized declaration
> 
> F:\projects>gdc --version
> gdc (GCC) 3.4.4 (cygming special, gdc 0.23, using dmd 1.007))

It was /slightly/ incomplete, but I can't reproduce your error messages.
This works for me, using "gdc (GCC) 4.1.1 20060524 (  (gdc 0.23, using dmd 1.007))" (Linux x64 version):
---
import std.stdio;

void myWritefln(T...)(T args)
{
    foreach(arg; args)
        writef("%s", arg);

    writefln();
}

void main() {
	myWritefln("Hi! ", 5, " that's all.");
}
---
July 12, 2007
Bill Baxter wrote:
> Carlos Santander wrote:
>> Bruce Adams escribió:
>>>
>>> and type safe compared to:
>>>
>>> stdout.writefln("%s%s%i", foo,bar,2);
>>>
>>
>> D has typesafe variadics, so you can just say:
>>
>> dout.writefln("%s%s%s", foo,bar,2);
> 
> Or just dout.writefln(foo,bar,2); in this case.

That would cause foo and possibly (if no '%' in foo) bar to be interpreted as format strings. The %i can safely be left out though.
July 12, 2007
I agree with most that the use of << and >> or other forms of operator overloading are inappropriate to process variable number of arguments.  D has variable template args built in to the freakin language.  It's typesafe, elegant, and straightforward.

// C++ yuck
cout << "x is " << x << endl;

// Tango yuck
Stdout("x is ")(x).newline;

// Would be best and very easy to implement
write("x is ", x, newline);

-Craig