July 27, 2012
On Friday, 27 July 2012 at 16:28:50 UTC, Dmitry Olshansky wrote:
>
> But this advantage is unimportant since arbitrary deep recursion is a security risk (especially for servers that typically use threads with tiny stacks).

I would like to point out here that the example VB.NET code I just gave for lazy-populating a list of all files on a drive uses NO recursion whatsoever.

Recursion isn't just a security risk - it's a performance hit as well.
July 27, 2012
On Friday, 27 July 2012 at 19:03:34 UTC, Jonathan M Davis wrote:
>
> Regardless, with where D is right now, there's no way that such a feature would be added the language itself any time soon.

What do you mean? Where *is* D at right now? Has development stopped? Is there a massive feature backlog?
July 27, 2012
On Friday, 27 July 2012 at 19:04:07 UTC, Stuart wrote:
> On Friday, 27 July 2012 at 16:28:50 UTC, Dmitry Olshansky wrote:
>>
>> But this advantage is unimportant since arbitrary deep recursion is a security risk (especially for servers that typically use threads with tiny stacks).
>
> I would like to point out here that the example VB.NET code I just gave for lazy-populating a list of all files on a drive uses NO recursion whatsoever.
>
> Recursion isn't just a security risk - it's a performance hit as well.

Only in languages without tail call optimizations.
July 27, 2012
On Fri, Jul 27, 2012 at 09:04:06PM +0200, Stuart wrote:
> On Friday, 27 July 2012 at 16:28:50 UTC, Dmitry Olshansky wrote:
> >
> >But this advantage is unimportant since arbitrary deep recursion is a security risk (especially for servers that typically use threads with tiny stacks).
> 
> I would like to point out here that the example VB.NET code I just gave for lazy-populating a list of all files on a drive uses NO recursion whatsoever.
> 
> Recursion isn't just a security risk - it's a performance hit as well.

I'm pretty sure Yield has a performance hit as well, 'cos it amounts to an implicit context-switch between two fibers. Once translated to the machine level, there is no such thing as yielding; you have to save your current state and return control to the caller, then recover your state when you get called again.

Of course, from what I understand, C# runs on a VM, correct? If so, this performance hit is probably hidden in the VM overhead, since the VM is already keeping track of states anyway, so the cost of tracking multiple states is absorbed into the VM's overall overhead. So you probably won't _notice_ the cost, but it's definitely there.


T

-- 
People walk. Computers run.
July 27, 2012
On Friday, 27 July 2012 at 19:09:27 UTC, Paulo Pinto wrote:
> On Friday, 27 July 2012 at 19:04:07 UTC, Stuart wrote:
>>
>> Recursion isn't just a security risk - it's a performance hit as well.
>
> Only in languages without tail call optimizations.

Which is pretty much all of them.

Scheme does it, and probably HOPE too; but bugger-all you could write a real program in, like .NET or C++. I mean, we're in bloody FORTRAN territory here. What use is that for writing Windows applications?

Does D have tail call optimisation?
July 27, 2012
On Fri, Jul 27, 2012 at 09:09:25PM +0200, Stuart wrote:
> On Friday, 27 July 2012 at 19:03:34 UTC, Jonathan M Davis wrote:
> >
> >Regardless, with where D is right now, there's no way that such a feature would be added the language itself any time soon.
> 
> What do you mean? Where *is* D at right now? Has development stopped? Is there a massive feature backlog?

Development is far from stopped, which is the problem: we're trying to stabilize the language, and adding more language-level features will only delay an already overdue stable language version.

Nevertheless, D has gotten to the point where it's powerful enough that most feature requests can be implemented in a library rather than as a language extension. There's been a trend of moving away from core language changes and implementing desired features in libraries (esp. Phobos) instead.


T

-- 
That's not a bug; that's a feature!
July 27, 2012
On Friday, 27 July 2012 at 19:12:41 UTC, H. S. Teoh wrote:
>
> I'm pretty sure Yield has a performance hit as well, 'cos it amounts to an implicit context-switch between two fibers.

Unless I'm sorely mistaken, Yield has bugger-all to do with fibers. I say again: I'm not talking about threading. There is more than one meaning of the word "yield". Go look it up. I provided a link in a previous post.

> Of course, from what I understand, C# runs on a VM, correct? If so, this performance hit is probably hidden in the VM overhead,
> since the VM is already keeping track of states anyway, so the
> cost of tracking multiple states is absorbed into the VM's overall
> overhead. So you probably won't _notice_ the cost, but it's definitely
> there.

I'm fairly sure D could implement the Iterator and Yield keywords from VB.NET without all this "overhead" to which you refer. As I said, go look it up.
July 27, 2012
On 07/27/12 20:47, Stuart wrote:
> On Friday, 27 July 2012 at 15:09:38 UTC, Graham Fawcett wrote:
>> On Friday, 27 July 2012 at 13:10:46 UTC, Stuart wrote:
>>> On Friday, 27 July 2012 at 03:00:25 UTC, Brad Anderson wrote:
>>>>
>>>> D equivalent: iota(0, int.max, 2).map!(a => /* do something with even numbers */)();
>>>
>>> I think you're missing the point. The purpose isn't to generate a sequence of numbers, but to illustrate how the Yield keyword is used in VB.NET. Sure, getting a sequence of numbers may be straightforward, but what about a lazy-populated list of all files on a computer? That can be done using Yield - and more importantly, WRITTEN like a normal synchronous function. Let's see you do that with map.
>>
>> That's easy:
>>
>>   [...elided code...]
>>   auto entries = dirEntries(BASE_DIR, SpanMode.breadth);
> 
> Ah, but that depends upon the pre-existence of the dirEntries() function. I think perhaps you're missing the point - which is that "Yield" allows you to WRITE a function synchronously which will then be executed lazily, as an iterator. What you have demonstrated there is USING a lazy function. How would I write, in D, a function that would lazily assemble some data and return it as a lazy collection? I mean, without calling existing lazy functions.

A more or less direct translation of your original example would be:

   auto infiniteSequence1(T, S)(T startValue, S step) {
      struct IS {
         auto opApply(scope int delegate(ref T) yield) {
            while (1)
               if (auto r = yield(startValue))
                  return r;
               else
                  startValue += step;
         }
      }

      return IS();
   }

   void main() {
      import std.stdio;
      foreach(n; infiniteSequence(2, 2)) {
         writeln(n);
         if (n>13)
            break;
      }
   }

and a D-style range based version could look like this:

   auto infiniteSequence(T, S)(T startValue, S step) {
      static struct IS {
         T startValue;
         S step;

         enum empty = false;
         @property ref front() { return startValue; }
         void popFront() { front += step; }
      }

      return IS(startValue, step);
   }

which both are as lazy as it gets. Returning direntries would be done similarly. Is this just about the syntax (which isn't much different)?

artur
July 27, 2012
On Friday, July 27, 2012 21:09:25 Stuart wrote:
> On Friday, 27 July 2012 at 19:03:34 UTC, Jonathan M Davis wrote:
> > Regardless, with where D is right now, there's no way that such a feature would be added the language itself any time soon.
> 
> What do you mean? Where *is* D at right now? Has development stopped? Is there a massive feature backlog?

We're specifically trying _not_ to add language features right now but rather to stabilize the language and its implementation. We've added a few things since the release of TDPL - mostly to resolve major issues that came up - but with the release of TDPL, the language was supposed to have been effectively frozen. We may add more backwards-compatible features once everything in TDPL has been fully implemented and is reasonably stable, but at this point, new language features need a _really_ good justification in order to be added.

- Jonathan M Davis
July 27, 2012
On Friday, 27 July 2012 at 19:17:10 UTC, H. S. Teoh wrote:
>
> Nevertheless, D has gotten to the point where it's powerful enough that most feature requests can be implemented in a
> library rather than as a language extension.

How could Yield be implemented as a library feature? Something like:

   return ITERATOR(
      { ...setup code ... },
      { ...loop body code... })

?

I don't see how that would work. Variables declared in the setup would not be accessible from the body. I guess it could be done a bit like this:

   Enumerable!int ExampleFunction() {
      ... create some variables ...
      return ITERATOR!int( {
         ...do something with variables...
         ...return something...
      } )
   }

That the kind of thing you mean?