Semantics of toString

Steven Schveighoffer schveiguy at yahoo.com
Thu Nov 12 06:05:56 PST 2009


On Thu, 12 Nov 2009 08:56:06 -0500, Denis Koroskin <2korden at gmail.com>  
wrote:

> On Thu, 12 Nov 2009 16:23:22 +0300, Steven Schveighoffer  
> <schveiguy at yahoo.com> wrote:
>
>> On Thu, 12 Nov 2009 08:22:26 -0500, Steven Schveighoffer  
>> <schveiguy at yahoo.com> wrote:
>>
>>> On Tue, 10 Nov 2009 18:49:54 -0500, Andrei Alexandrescu  
>>> <SeeWebsiteForEmail at erdani.org> wrote:
>>>
>>>> I think the best option for toString is to take an output range and  
>>>> write to it. (The sink is a simplified range.)
>>>
>>> Bad idea...
>>>
>>> A range only makes sense as a struct, not an interface/object.  I'll  
>>> tell you why: performance.
>>>
>>> Ranges are special in two respects:
>>>
>>> 1. They are foreachable.  I think everyone agrees that calling 2  
>>> interface functions per loop iteration is much lower performing than  
>>> using opApply, which calls one delegate function per loop.  My  
>>> recommendation -- use opApply when dealing with polymorphism.  I don't  
>>> think there's a way around this.
>>
>> Oops, I meant 3 virtual functions -- front, popNext, and empty.
>>
>> -Steve
>
> Output range has only one method: put.

I was referring to range's ability to interact with foreach.  An output  
range wouldn't qualify as a foreachable entity anyways (and rightfully  
so).  Just covering all the bases.

> I'm not sure, but I don't think there is a performance difference  
> between calling a virtual function through an interface and invoking a  
> delegate.

Yes, there is:

A delegate is equivalent to a struct member function call.  (load data  
pointer (i.e. this), push args, call function)
A virtual function uses a vtable to look up the function address, and then  
is equivalent to a struct member call.
An interface function call is equivalent to a virtual call with the added  
penalty that you might have to adjust the 'this' pointer before calling.

> But I agree passing a delegate is more generic. You can substitute an  
> output range with a delegate (obj.toString(&range.put, fmt)) without any  
> performance hit, but not vice versa (obj.toString(new  
> DelegateWrapRange(&myput), fmt) implies an additional allocation and  
> additional indirection per range.put call).

You can use scope classes to avoid the allocation, but you can't get  
around the virtual/interface call penalty.

But even if a range is a struct, it's simply a different form of delegate,  
one in which you undoubtedly call only one member function.  Might as well  
use a delegate to allow the most usefulness.

-Steve



More information about the Digitalmars-d mailing list