Lazy eval -- an example issue

kris foo at bar.com
Wed Aug 23 11:50:44 PDT 2006


John Reimer wrote:
> On Wed, 23 Aug 2006 00:33:08 -0700, Paolo Invernizzi  
> <arathorn at NOSPAM_fastwebnet.it> wrote:
> 
>> kris wrote:
>>
>>> Walter Bright wrote:
>>>
>>>> kris wrote:
>>>>
>>>>> Can't do that; the char[] version have to stay.
>>>>
>>>>
>>>>
>>>> Why?
>>>
>>>   Because my Boss says so
>>
>>
>> kris, really, is it a joke?
>>
>> If not, and I'm supposing you are using the mango logging package in  
>> some big D application, can you post us the performance difference 
>> you  have noticed using the char[] version versus the delegate version?
>>
>> ---
>> Paolo Invernizzi
> 
> 
> 
> I think he was being sarcastic.
> 
> -JJR

No sarcasm required. The recent development of deliberately introducing 
ambiguity into the language warrants serious concern. It's something 
that should, and does, trouble most of us quite deeply (judging by the 
responses).

As for performance differences, I suspect you're missing the bigger 
picture, Paolo? I'll try to draw one: you may have noticed my concern 
about delegates and heap-based frames? If so, you'll probably have seen 
a reponse from Walter noting that specific types of expr can probably be 
identified as not escaping the hosting function? There's a gaping hole 
in that marketing-style claim, and you should treat it with a heathly 
dose of suspicion.

For example; I'd like to use delegates as a nice clean shortcut for 
logging. Instead of writing

# if (log.enabled (log.Trace))
#     log.trace (sprint ("my log message %d, %s", i, s));

I'd instead like to write this

# log.trace ({return sprint ("my log message %d, %s", i, s);});


Makes sense, right? We don't want to invoke the cost of the sprint() 
function unless tracing is enabled. Note that these are guaranteed to be 
synchronous callbacks. The delegates are not "saved for later" like a 
gui delegate might be. Thus, the frame of the hosting function should be 
stack-based.

However, because the callback references local variables, there's no 
guarantee the host-frame will not be allocated on the heap instead. This 
is the issue we'd been trying to address in another thread. Namely, if 
there's going to be ambiguity over whether a delegate is invoked 
syncrhonously or asynchronously, we probably need a way to tell the 
compiler what's what (rather than let it make the wrong choice).

In simplistic terms, if I have a function like so (note that there's no 
delegate intended here):

# real somefunk (real x, real y)
# {
# 	if (x is real.nan || y is real.nan)
#           log.error (sprint ("invalid args %s, %s", x, y));
#
#         // do something with x & y
# }

It's quite possible that the frame for this will be heap-allocated, even 
though the logger invocation is not intending to use delegates at all. 
The damn compiler might go and turn the char[] expr into a sneaky 
delegate, and then decide it needs a heap-frame instead of a stack one. 
That, my friend, is a serious performance issue (heap allocation each 
and every time somefunk() is called), and it's all hidden behind a plush 
blue-velvet curtain.


Supposing we actually *want* to use a delegate in this situation? e.g.

# real somefunk (real x, real y)
# {
# 	if (x is real.nan || y is real.nan)
#           log.error ({return sprint ("invalid args %s, %s", x, y);});
#
#         // do something with x & y
# }

We still need some manner in which to tell the compiler that the 
callback is synchronous, rather than asynchronous, and that it should 
not be trying to allocate a heap-frame for this function. Again, this is 
what the other thread was discussing in depth. One of the ideas 
put-forward there was to somehow mark the hosting function as being a 
synchronous-host; something like this

# scope real somefunk (real x, real y);

Another opinion was to mark the /usage/ of the delegate itself, the 
logger in this case, with something akin to the following

# void error (scope char[] delegate());


Each of these have their relative pros and cons. What *is* evident, is 
that the compiler cannot be trusted to make the appropriate decision. In 
contrast, it's quite likely to make a highly conservative, and very 
poor, decision. Implied behaviour is often entirely the wrong thing to 
do and, without a means for manual control, will quickly become a most 
serious problem.

I hope you can see where the recent ambiguities lead to? You can easily 
wind up with unexpected (and unwanted) delegates, which may well lead to 
unexpected (and unwanted) heap-based frames. To resolve, the ambiguities 
must be removed. Additionally, some *dependable* mechanism should be put 
in place to manage (or override) how & when heap-based frames are 
allocated.









More information about the Digitalmars-d mailing list