tags:

views:

1294

answers:

18

Do you generally assume that toString() on any given object has a low cost (i.e. for logging)? I do. Is that assumption valid? If it has a high cost should that normally be changed? What are valid reasons to make a toString() method with a high cost? The only time that I get concerned about toString costs is when I know that it is on some sort of collection with many members. From: http://jamesjava.blogspot.com/2007/08/tostring-cost.html

Update: Another way to put it is: Do you usually look into the cost of calling toString on any given class before calling it?

+1  A: 

Since I generally only call toString() on methods and classes that I have written myself and overrode the base method, then I generally know what the cost is ahead of time. The only time I use toString() otherwise is error handling and or debugging when speed is not of the same importance.

Chris J
+4  A: 

Do you generally assume that toString() on any given object has a low cost? I do.

Why would you do that? Profile your code if you're running into performance issues; it'll save you a lot of time working past incorrect assumptions.

Shog9
I make that assumption because I have found it to be true. Do you look into the toString cost of a new class before deciding if you should call it?
James A. N. Stauffer
Of course not, i decide to call it because it does what i need. I don't worry about its cost until i see that it detracts significantly from the performance of my app. A single, astonishingly slow call that only happens once doesn't matter; a much faster call that happens 20million times/sec OTOH...
Shog9
My point is, fast and slow, high cost / low cost... are irrelevant except in the context of *your* program. Nothing anyone says here will matter if you're doing something fundamentally different from what they are.
Shog9
Well... i mean... if someone replied with proof that, in the majority of cases, toString() takes a month or two to execute... then it's probably gonna affect your program no matter what you're doing with it. But i don't expect that.
Shog9
It appears that we agree than. Assume it doesn't have significant cost(i.e. don't worry about the cost ahead of time) and if you have problems then profile.
James A. N. Stauffer
Yes, i think your second question was the better one. It's a bit of a tricky subject, since if you start to assume that an operation is *free* you can end up over-using it. Regular, comprehensive profiling will (assuming the existence of real-world test scenarios) tend to highlight such issues.
Shog9
+32  A: 

No it's not. Because ToString() can be overloaded by anyone, they can do whatever they like. It's a reasonable assumption that ToString() SHOULD have a low cost, but if ToString() accesses properties that do "lazy loading" of data, you might even hit a database inside your ToString().

Scott Hanselman
Note the word "generally" in my question. I am asking if we should assume that 90% of the time toString is low costs. Do you always look into the the toString implementation to determine the cost just because there is a chance that it is high cost?
James A. N. Stauffer
@James: "Generally" != "Usually".
codekaizen
A: 

Possibly the largest cost with naive toString() chaining is appending all those strings. If you want to generate large strings, you should use an underlying representation that supports an efficient append. If you know the append is efficient, then toString()s probably have a relatively low cost.

For example, in Java, StringBuilder will preallocate some space so that a certain amount of string appending takes linear time. It will reallocate when you run out of space.

In general, if you want to append sequences of things and you for whatever reason don't want to do something similar, you can use difference lists. These support linear time append by turning sequence appending into function composition.

Denis Bueno
A: 

toString() is used to represent an object as a String. So if you need slow running code to create a representation of an object, you need to be very careful and have a very good reason to do so. Debugging would be the only one I can think of where a slow running toString is acceptable.

Mike Pone
+8  A: 

The best way to find out is to profile your code. However, rather than worry that a particular function has a high overhead, it's (usually) better to worry about the correctness of your application and then do performance profiling on it (but be wary that real-world use and your test setup may differ radically). As it turns out, programmers generally guess wrong about what's really slow in their application and they often spend a lot of time optimizing things that don't need optimizing (eliminating that triple nested loop which only consumes .01% of your application's time is probably a waste).

Fortunately, there are plenty of open source profilers for Java.

Ovid
+16  A: 

The Java standard library seems to have been written with the intent of keeping the cost of toString calls very low. For example, Java arrays and collections have toString methods which do not iterate over their contents; to get a good string representation of these objects you must use either Arrays.toString or Collections.toString from the java.util package.

Similarly, even objects with expensive equals methods have inexpensive toString calls. For example, the java.net.URL class has an equals method which makes use of an internet connection to determine whether two URLs are truly equal, but it still has a simple and constant-time toString method.

So yes, inexpensive toString calls are the norm, and unless you use some weird third-party package which breaks with the convention, you shouldn't worry about these taking a long time.

Of course, you shouldn't really worry about performance until you find yourself in a situation where your program is taking too long, and even then you should use a profiler to figure out what's taking so longer rather than worrying about this sort of thing ahead of time.

Eli Courtwright
AbstractCollection iterates over its elements with an Iterator, as is not overridden for efficiency even in classes like ArrayList. I haven't checked Java 6, but in Java 1.5, its still using StringBuffer instead of StringBuilder. Definitely not optimized for efficiency.
erickson
+1  A: 

My pragmatic answer would be: yes, you always assume a toString() call is cheap, unless you make an enormous amount of them. On the one hand, it is extremely unlikely that a toString() method would be expensive and on the other hand, it is extremely unlikely that you run into trouble if it isn't. I generally don't worry about issues like these, because there are too many of them and you won't get any code written if you do ;).

If you do run into performance issues, everything is open, including the performance of toString() and you should, as Shog9 suggest, simply profile the code. The Java Puzzlers show that even Sun wrote some pretty nasty constructors and toString() methods in their JDK's.

Confusion
A: 

My thought is:

Yes on standard-library objects

No on non-standard objects unless you have the source code in front of you and can check it.

workmad3
A: 

Cheap but not free. Where I work, the philosophy seems to be "when in doubt, use ToString()". Not the worst thing in the world, but it seems that redundant ToString() calls clutter code, and they may falsely communicate that you're intending to convert a non-string to a string. I would recommend that it only be used it as needed. I consider this approach idiomatic.

MrBoJangles
A: 

I will always override toString to put in whatever I think I will need to debug problems. It it usually up to the developer to use it by either calling the toString method itself or having another class call it for you (println, logging, etc.).

Javamann
+3  A: 

Your question's title uses the contradictory words "safe" and "generally." So even though in comments you seem to be emphasizing the general case, to which the answer is probably "yes, it's generally not a problem," a lot of people are seeing "safe" and therefore are answering either "No, because there's a risk of arbitrarily poor performance," or "No, because if you want to be 'safe' with a performance question, you must profile."

Larry OBrien
generally + safe < 100% safe
James A. N. Stauffer
A: 

There's an easy answer to this one, which I first heard in a discussion about reflection: "if you have to ask, you can't afford it."

Basically, if you need ToString() of large objects in the day-to-day operation of your program, then your program is crazy. Even if you need to ToString() an integer for anything time critical, your program is crazy, because it's obviously using a string where an integer would do.

ToString() for log messages is automatically okay, because logging is already expensive. If your program is too slow, turn down the log level! It doesn't really matter how slow it is to actually generate the debug messages, as long as you can choose to not generate them. (Note: your logging infrastructure should call ToString() itself, and only when the log message is supposed to be printed. Don't ToString() it by hand on the way into the log infrastructure, or you'll pay the price even if the log level is low and you won't be printing it after all! See http://www.colijn.ca/~caffeine/?m=200708#16 for more explanation of this.)

apenwarr
A: 

Since you put "generally" in your question, I would say yes. For -most- objects, there isn't going to be a costly ToString overload. There definitely can be, but generally there won't be.

Mike Comstock
+1  A: 

I think the question has a flaw. I wouldn't even assume toString() will print a useful piece of data. So, if you begin with that assumption, you know you have to check it prior to calling it and can assess it's 'cost' on a case by case basis.

Nathan Feger
Absolutely right. ToString on a reference type just returns the type name, and the KISS principle says it shouldn't be overridden in the vast majority of cases.
Joe
toString generally at least includes the class name and that is often somewhat useful.
James A. N. Stauffer
A: 

In general I consider toString() low cost when I use it on simple objects, such as an integer or very simple struct. When applied to complex objects, however, toString() is a bit of crap shoot. There are two reason's for this. First, complex objects tend to contain other objects, so a single call to toString() can cascade into many calls to toString() on other objects plus the overehead of concatenating all those results. Second, there is no "standard" for converting complex objects to strings. One toString() call may yeild a single line of comma-separated values; another a much more verbose form. Only by checking it yourself can you know.

So my rule is toString() on simple objects is generally safe but on complex objects is suspect until checked.

A: 

I'd avoid using toString() on objects other than the basic types. toString() may not display anything useful. It may iterate over all the member variables and print them out. It may load something not yet loaded. Depending on what you plan to do with that string, you should consider not building it.

There are typically a few reasons why you use toString(): logging/debugging is probably the most common for random objects; display is common for certain objects (such as numbers). For logging I'd do something like

if(logger.isDebugEnabled()) {
    logger.debug("The zig didn't take off.  Response: {0}", response.getAsXML().toString());
}

This does two things: 1. Prevents constructing the string and 2. Prevents unnecessary string addition if the message won't be logged.

Mr. Shiny and New
A: 

In general, I don't check every implementation. However, if I see a dependency on Apache commons, alarm bells go off and I look at the implementation more closely to make sure that they aren't using ToStringBuilder or other atrocities.

erickson