August 19, 2008
Benji Smith wrote:
> Don wrote:
>> I cannot understand the rationale for a toString() member function which doesn't support formatting.
> 
> I agree.
> 
> In Java, the toString() method *must* exist on the base Object class, because of constructs like this:
> 
>    String s = "hello" + (new World());
> 
> Without an implementation of toString(), it'd be impossible to support those kinds of automatic String conversion and concatenation (which actually do end up being pretty handy in logging & debugging statements).
> 
> But since D doesn't support implicit String conversion, it seems pretty pointless.

I think both Tango and phobos allow objects to be converted to strings when specified as parameters to a formatting function -- i.e. Stdout.format("{0}", obj) will call obj.toString().
August 20, 2008
Don wrote:
> I cannot understand the rationale for a toString() member function which doesn't support formatting.
> 
> I don't think I've ever made a class which only has a single format option. If the class contains any integers, I want to specify whether it should use hex or decimal, leading zeros, sign. If it contains floating point numbers, it's number of digits, scientific notation, hex or decimal, and what to do with NaNs. And of course there are locales.
> 
> Seriously, I cannot remember ever not having this requirement, so I cannot imagine a use for toString().
> 
> C++ got around this by giving state to the iostream classes. As far as I can tell, neither Phobos nor Tango provide any support at all.
> 
> Practical example: BigInt (which I'm developing in both Tango and Phobos). It is a struct. How can it support I/O? I can't work out how to do it in either library.

I think you can do much the same as iostream and still take advantage of toString.  Something like:

string foo = a.toString() ~ format(a, "...");

Where format would be special overloaded template (with specialization) that does conversions.

-Joel
August 20, 2008
Robert Fraser wrote:
> Benji Smith wrote:
>> Don wrote:
>>> I cannot understand the rationale for a toString() member function which doesn't support formatting.
>>
>> I agree.
>>
>> In Java, the toString() method *must* exist on the base Object class, because of constructs like this:
>>
>>    String s = "hello" + (new World());
>>
>> Without an implementation of toString(), it'd be impossible to support those kinds of automatic String conversion and concatenation (which actually do end up being pretty handy in logging & debugging statements).
>>
>> But since D doesn't support implicit String conversion, it seems pretty pointless.
> 
> I think both Tango and phobos allow objects to be converted to strings when specified as parameters to a formatting function -- i.e. Stdout.format("{0}", obj) will call obj.toString().

And that's the problem -- it's a really poor design, totally unsuitable for that purpose.

Simple challenge:

class Foo {
public:
 double x;
}

1. You want it to output x in the default way for the current locale.
(eg, 5,35 or 5.35 depending on which country you're in).
Write toString().
2. Now write toString() such that:

double y = 3.156892123;
Foo z = new Foo;
z.x = 3.156892123;
writefln("%.3f, %.3f", y, z);
writefln("%.4f, %.4f", y, z);

(or Tango equivalent) produces the same results for y and z.

Both of these should be trivial.
August 20, 2008
On Mon, 18 Aug 2008 15:15:51 +0200, Don <nospam@nospam.com.au> wrote:

>bearophile wrote:
>> Don Wrote:
>>> I cannot understand the rationale for a toString() member function which doesn't support formatting.
>> 
>> I think the rationale is that it's a simple function that performs a simple thing with an easy to use and easy to learn syntax, I have found it useful often.
>
>I think it encourages a very bad programming style. It makes ONE case very easy, but does nothing for the other cases. It doesn't scale at all.
>
>> For more complex purposes you can write your own printing methods,
>
>> or you can write a method that changes the printing state of the class/struct,
> > that is later read and used when you call toString() and used to
>change its behavior.
>
>But the way it is formatted should be a property of the output stream, I think, not a property of the object. Certainly this is the way C and C++
>  I/O works.
>
>> 
>> So I have created a graph class that by default when you call toString() gives a compact and simple textual representation of the graph.
>Then there are other methods, one that returns a string that shows the matrix of links, another that shows the weights of the arcs too, etc.
>
>  There is also the possibility to modify the printing defaults with
>another method, to then later toString() acts differently.
>
>Then I got suspicious that this might have come from Java or .NET.

FWIW, .NET provides IFormattable interface that allows objects to imlement custom formatting:

interface IFormattable
{
	string toString(string  fmt, IFormatProvider fProvider);
}

class C : IFormattable
{
	string toString(string fmt, IFormatProvider fProvider)
	{
		if (fProvider !is null)
		{
			// try to get a formater for this type
			// from fProvider

		}
		else
		{
			switch (fmt)
			{
				// do formatting based on the format
string
			}
		}
	}
}


>I googled for toString in Java and found:
>---
>http://www.javapractices.com/topic/TopicAction.do?Id=55
>---
>"The toString method is widely implemented. It provides a simple, convenient mechanism for debugging classes during development. It is also widely used for logging, and for passing informative error messages to Exception constructors and assertions. When used in these informal ways, the exact format of toString is not part of the contract of the method, and callers should not rely on the exact format of the returned String."
>---
>Now this makes sense. It's a useful hack. If it's just for debugging and error messages, that's fine. But if that is what it's for, the normal runtime I/O should discourage its use elsewhere (eg, by appending the class name in front).
>
>OTOH if it is intended for general I/O, I think it's a horribly broken design.
August 20, 2008
Don wrote:
> Robert Fraser wrote:
>> Benji Smith wrote:
>>> Don wrote:
>>>> I cannot understand the rationale for a toString() member function which doesn't support formatting.
>>>
>>> I agree.
>>>
>>> In Java, the toString() method *must* exist on the base Object class, because of constructs like this:
>>>
>>>    String s = "hello" + (new World());
>>>
>>> Without an implementation of toString(), it'd be impossible to support those kinds of automatic String conversion and concatenation (which actually do end up being pretty handy in logging & debugging statements).
>>>
>>> But since D doesn't support implicit String conversion, it seems pretty pointless.
>>
>> I think both Tango and phobos allow objects to be converted to strings when specified as parameters to a formatting function -- i.e. Stdout.format("{0}", obj) will call obj.toString().
> 
> And that's the problem -- it's a really poor design, totally unsuitable for that purpose.
> 
> Simple challenge:
> 
> class Foo {
> public:
>  double x;
> }
> 
> 1. You want it to output x in the default way for the current locale.
> (eg, 5,35 or 5.35 depending on which country you're in).
> Write toString().
> 2. Now write toString() such that:
> 
> double y = 3.156892123;
> Foo z = new Foo;
> z.x = 3.156892123;
> writefln("%.3f, %.3f", y, z);
> writefln("%.4f, %.4f", y, z);
> 
> (or Tango equivalent) produces the same results for y and z.
> 
> Both of these should be trivial.

We had actually asked for some compiler changes to support this sort of formatting (necessary since the function signature for toString is hardcoded in the compiler for structs), but the request was denied, presumably as unnecessary.  I don't remember the details of the request however--Lars would have to provide that.


Sean
August 20, 2008
On 2008-08-18 16:28:36 +0200, "Steven Schveighoffer" <schveiguy@yahoo.com> said:

> "Don" wrote
>> I cannot understand the rationale for a toString() member function which
>> doesn't support formatting.
>> [...]
> As you have discovered, it is for simple debugging.

yes

> However, it's not even close to as useful as Java, where if you combine a
> string with an object, it automatically calls the toString function.
> 
> As far as supporting an output method, I think toString is completely the
> wrong way to look at it.  A simple example is a container class, such as a
> vector of ints.
> 
> Let's say you are outputting a vector of ints every time it has changed.
> What ends up happening is you build a (possibly huge) string every time you
> output the vector, and then are throwing the string away!  When all you
> really need is about 20 bytes of stack space to create the individual int
> strings and then output to an i/o function.
> 
> Even with a format string, that doesn't solve this problem.
> 
> What I would like to see is an output method in Object that looks like:
> 
> int output(int delegate(char[] x) sink, char[] fmt = null);

I fully agree I normally write a method that writes to a stream, with handles to tailor the output.
I also often write a desc method that gives a detailed description of all the variables of the object.

Then I write toString that calls one of these methods with some default arguments on a special stream the creates a string.
In general stream based output is much superior to conversion to a string (more efficient and often simpler to write), and when needed one can use a special stream that returns a string.

In tango I use a Print!(T) instance as nice to use stream, nicer than a sink delegate.
I wrote a Stringify class that like Python StringIO returns the collected string upon request.

> And something like how 'toString' works in a struct (where there is an
> xoutput function in the struct typeinfo class).

yes would also be nice to have

> This is a generic solution, it would be customized to the appropriate i/o
> library of Tango or Phobos.  Possibly the format strings would be different
> based on the I/O (i.e. Phobos uses printf style formatting constructs, Tango
> uses .NET style).

I am not too sure that I want to always have a format string, encoding and decoding it might be tedious, normally having a method with extra arguments is better.

Serialization is another topic, there the format should be defined by the stream.

Fawzi

August 20, 2008
Sean Kelly wrote:

> Don wrote:
>> Robert Fraser wrote:
>>> Benji Smith wrote:
>>>> Don wrote:
>>>>> I cannot understand the rationale for a toString() member function
>>>>> which doesn't support formatting.
>>>>
>>>> I agree.
>>>>
>>>> In Java, the toString() method *must* exist on the base Object class, because of constructs like this:
>>>>
>>>>    String s = "hello" + (new World());
>>>>
>>>> Without an implementation of toString(), it'd be impossible to support those kinds of automatic String conversion and concatenation (which actually do end up being pretty handy in logging & debugging statements).
>>>>
>>>> But since D doesn't support implicit String conversion, it seems pretty pointless.
>>>
>>> I think both Tango and phobos allow objects to be converted to strings
>>> when specified as parameters to a formatting function -- i.e.
>>> Stdout.format("{0}", obj) will call obj.toString().
>> 
>> And that's the problem -- it's a really poor design, totally unsuitable for that purpose.
>> 
>> Simple challenge:
>> 
>> class Foo {
>> public:
>>  double x;
>> }
>> 
>> 1. You want it to output x in the default way for the current locale.
>> (eg, 5,35 or 5.35 depending on which country you're in).
>> Write toString().
>> 2. Now write toString() such that:
>> 
>> double y = 3.156892123;
>> Foo z = new Foo;
>> z.x = 3.156892123;
>> writefln("%.3f, %.3f", y, z);
>> writefln("%.4f, %.4f", y, z);
>> 
>> (or Tango equivalent) produces the same results for y and z.
>> 
>> Both of these should be trivial.
> 
> We had actually asked for some compiler changes to support this sort of formatting (necessary since the function signature for toString is hardcoded in the compiler for structs), but the request was denied, presumably as unnecessary.  I don't remember the details of the request however--Lars would have to provide that.

It was more of a suggestion that something accommodating this should exist, with toString(char[] fmt) as an initial suggestion. I think it just slipped away as it wasn't a good enough solution, not really denied.

-- 
Lars Ivar Igesund
blog at http://larsivi.net
DSource, #d.tango & #D: larsivi
Dancing the Tango
August 21, 2008
Lars Ivar Igesund wrote:
> Sean Kelly wrote:
> 
>> Don wrote:
>>> Robert Fraser wrote:
>>>> Benji Smith wrote:
>>>>> Don wrote:
>>>>>> I cannot understand the rationale for a toString() member function
>>>>>> which doesn't support formatting.
>>>>> I agree.
>>>>>
>>>>> In Java, the toString() method *must* exist on the base Object class,
>>>>> because of constructs like this:
>>>>>
>>>>>    String s = "hello" + (new World());
>>>>>
>>>>> Without an implementation of toString(), it'd be impossible to
>>>>> support those kinds of automatic String conversion and concatenation
>>>>> (which actually do end up being pretty handy in logging & debugging
>>>>> statements).
>>>>>
>>>>> But since D doesn't support implicit String conversion, it seems
>>>>> pretty pointless.
>>>> I think both Tango and phobos allow objects to be converted to strings
>>>> when specified as parameters to a formatting function -- i.e.
>>>> Stdout.format("{0}", obj) will call obj.toString().
>>> And that's the problem -- it's a really poor design, totally unsuitable
>>> for that purpose.
>>>
>>> Simple challenge:
>>>
>>> class Foo {
>>> public:
>>>  double x;
>>> }
>>>
>>> 1. You want it to output x in the default way for the current locale.
>>> (eg, 5,35 or 5.35 depending on which country you're in).
>>> Write toString().
>>> 2. Now write toString() such that:
>>>
>>> double y = 3.156892123;
>>> Foo z = new Foo;
>>> z.x = 3.156892123;
>>> writefln("%.3f, %.3f", y, z);
>>> writefln("%.4f, %.4f", y, z);
>>>
>>> (or Tango equivalent) produces the same results for y and z.
>>>
>>> Both of these should be trivial.
>> We had actually asked for some compiler changes to support this sort of
>> formatting (necessary since the function signature for toString is
>> hardcoded in the compiler for structs), but the request was denied,
>> presumably as unnecessary.  I don't remember the details of the request
>> however--Lars would have to provide that.
> 
> It was more of a suggestion that something accommodating this should exist,
> with toString(char[] fmt) as an initial suggestion. I think it just slipped
> away as it wasn't a good enough solution, not really denied.

Oops, I stand corrected.


Sean
August 22, 2008
Don, el 18 de agosto a las 12:41 me escribiste:
> I cannot understand the rationale for a toString() member function which doesn't support formatting.

I think is useful only for debugging purposes.

> C++ got around this by giving state to the iostream classes.

I think C++ formatting is heavily ill. All the manipulator stuff is madness.

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
No existiría el sonido del mar si faltara en la vida oreja y caracol.
	-- Ricardo Vaporeso. Cosquín, 1908.
August 22, 2008
Leandro Lucarella wrote:
> Don, el 18 de agosto a las 12:41 me escribiste:
>> I cannot understand the rationale for a toString() member function which doesn't support formatting.
> 
> I think is useful only for debugging purposes.
> 
>> C++ got around this by giving state to the iostream classes.
> 
> I think C++ formatting is heavily ill. All the manipulator stuff is
> madness.

It's horrific but surprisingly flexible.  I've created stateful formatters for various protocols and made it work all invisibly with the formatting hooks provided in C++.  For example:

   std::cout << a << b << c << std::flush;

The above may perform lazy output of structured XML, some binary encoding, etc.  It might be possible to get close with toString, but because it returns an array rather than writing into a buffer some of the flexibiliy (like lazy encoding) would definitely be lost.

My experience with Java suggests that toString is meant for debugging purposes anyway.  It's rare that an object will produce meaningful user-level output with its toString method.


Sean