On 2010-12-13 20:04, Nick Sabalausky wrote:
"Jacob Carlborg"<d...@me.com>  wrote in message
news:ie5n2o$2v7...@digitalmars.com...
On 2010-12-12 19:27, Nick Sabalausky wrote:

There's one important difference you missed. Granted, it's not applicable
in
that particular example, but more generally, it's important:

int foo()
{
      foreach (person ; account.people)
      {
          writeln(person.name);
          if(blah)
              return 7; // Returns from foo
      }
}


int bar()
{
      account.people.each((Person person) {
          writeln(person.name);
          if(blah)
              return 7; // Only tries to return from the delegate
      });
}

In D, there is currently no way to convert "foo()" above to use a delgate
(at least not without odd contorsions). So if we were to make syntax
sugar
for "bar()", it would get really confusing:

int bar2()
{
      account.people.each(Person person)
      {
          writeln(person.name);
          if(blah)
              return 7; // Only returns from the delegate, not bar2!!
WTF?!
      }
}

There are similar issues with break, continue, and probably goto.

In Ruby, the syntax sugar works out fine because you can make it work it
either way. You can create something that behaves like a delegate
("return"
only returns from the delegate), or you can create something that is
treated
as part of the function it's declared within ("return" unwinds the stack
and
returns from the function that created it). (Although Ruby leaves the
choice
up the the caller. I'm not entirely convinced that's the right way to do
it.)

D would need something similar for "passing a delegate" sugar to work out
sensibly. One idea is to say that if-and-only-if the "sugar" is used,
it's
considered part of the original function that declared it rather than
being
a true degelate. The function that takes the "sugared delegate" must
declare
that it takes a "sugared delegate" instead of a normal one so that it can
make sure not to do this:

doSomething();
callSugaredDelegateThatMightUnwindTheStackEvenWithoutThrowing();
doCleanup();

Yes, absolutely correct, I totally forgot about this. D would need a way
to return from the delegate and a way to return from the context where the
delegate is called. Perhaps introduce a new keyword "yield"?


I've been reminded in another branch of this thread that foreach/opApply
already handles this issue, so that approach could probably just be copied.
Ie with:

foreach(item; somethingWithOpApply)
{
     if(item.isItBoyant())
         return item;
}

The body gets converted to a delegate which gets passed to opApply, but the
"return" still works as expected. I would be interested to hear how exactly
that works though, particularly when returning something other than void.

That's probably why one has to mess with the result of the delegate in opApply and it's also probably why opApply is unnecessary complicated.

But if I want the other behavior, just return from the delegate, is it common enough to support both behaviors?

BTW have a look at the following code:

struct Foo
{
    string array = "0123456789";

    int opApply(int delegate(ref char) dg)
    {
        int result = 0;

        for (int i = 0; i < array.length; i++)
        {
            result = dg(array[i]);
            //if (result)
                //break;
        }

        return result;
    }
}

void bar ()
{
    Foo foo;

    foreach (c ; foo)
    {
        if (c == '3')
            return;

        writeln(c);
    }
}

void main ()
{
    bar();
}

With the "break" commented out the foreach will just continue even with the return.

--
/Jacob Carlborg

Reply via email to