>
> 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.

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

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

"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.

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.

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