Jump to page: 1 2 3
Thread overview
Why does toString() exist? It seems useless.
Aug 18, 2008
Don
Aug 18, 2008
Lars Ivar Igesund
Aug 18, 2008
bearophile
Aug 18, 2008
Don
Aug 18, 2008
Frank Benoit
Aug 18, 2008
bearophile
Aug 20, 2008
Max Samukha
Aug 20, 2008
Fawzi Mohamed
Aug 18, 2008
Benji Smith
Aug 19, 2008
Robert Fraser
Aug 20, 2008
Don
Aug 20, 2008
Sean Kelly
Aug 20, 2008
Lars Ivar Igesund
Aug 21, 2008
Sean Kelly
Aug 18, 2008
BCS
Aug 19, 2008
Christopher Wright
Aug 20, 2008
JAnderson
Aug 22, 2008
Leandro Lucarella
Aug 22, 2008
Sean Kelly
Aug 22, 2008
Leandro Lucarella
Aug 22, 2008
Fawzi Mohamed
Aug 22, 2008
Sean Kelly
Aug 23, 2008
Fawzi Mohamed
Aug 23, 2008
Christopher Wright
Aug 24, 2008
Don
Aug 24, 2008
Ary Borenszweig
August 18, 2008
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.
August 18, 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.

It is not useless, but it would indeed be useful to be able to pass a format string to it - toString(char[] fmt) - or similar.

Note that if structs could have interfaces, then this wouldn't really be a problem.

-- 
Lars Ivar Igesund
blog at http://larsivi.net
DSource, #d.tango & #D: larsivi
Dancing the Tango
August 18, 2008
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.

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.

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.

Bye,
bearophile
August 18, 2008
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.
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 18, 2008
Don schrieb:
> OTOH if it is intended for general I/O, I think it's a horribly broken design.

What do you think about doing one of

1.)
change signature in object.Object to
  char[] toString( char[] fmt = null)
to give the object the possibility to use the format information.
Well, would break all code :/

2.)
Create a standard interface for doing that

interface Formatable {
  char[] toString( char[] fmt );
}

The object can implement this interface, the user can try to cast to this interface.

if( auto formatable = cast(Formatable)obj ){
   print( formatable.toString(fmt));
}
else if( obj !is null ){
   print( obj.toString());
}
else{
   print( "null" );
}

August 18, 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.

As you have discovered, it is for simple debugging.

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);

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

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

-Steve


August 18, 2008
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.

Incidentally, I'd be opposed to a toString(char[] format) method being a part of the Object class. I prefer the Tango (.NET style) formatting, and others surely prefer the printf style formatting in Phobos. If formatting strings became a part of the basic Object definition, I can imagine a lot of very annoyed developers, depending on which formatting style was chosen for Object.

--benji
August 18, 2008
Reply to don,

> 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 the point is to have a least common denominator "Just give me *something*" method for debugging and the like. Anything more demanding is to complicated for the base class as it will never be flexible enough.


August 18, 2008
Don:
> 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.

You may be right, I am learning still a lot about such matters.

But how can the output stream know about the many ways to print a graph? (I don't know enough about C++ streams).

Bye,
bearophile
August 19, 2008
Don wrote:
> I cannot understand the rationale for a toString() member function which doesn't support formatting.

Nothing similar exists in Tango because, for structs, it requires compiler support.

In Tango, you can specify formatting for a particular type by subclassing Layout and overriding munge. Or rather, you could, except munge is private. Relevant ticket: http://dsource.org/projects/tango/ticket/1247

On the other hand, I've only ever used toString for debug output, using external formatters for anything with user-visible results. Again, if Layout.munge were not private, you could add external formatters easily.

This helps you not at all when using Phobos.

« First   ‹ Prev
1 2 3