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