www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Custom Blocks

reply Chris Williams <aahz seanet.com> writes:
I'm not sure whether the design of D 2.0 has stabilized as yet, but if not,
I would like to suggest the ability to create custom block types.

For example, say that I have an object that I'm using in a multithreaded
application. In general, I would do something like:

synchronized (myObject) {
   ...fiddle with it
}

But, now I want to change myObject into being guarded by a read-write mutex.
By best option will be something like:

{
   myObject.readLock();
   scope (exit) myObject.readUnlock();
   ...check contents
}

{
   myObject.writeLock();
   scope (exit) myObject.writeUnlock();
   ...fiddle with it
}

I'd much rather be able to say:

readLock (myObject) {
   ...check contents
}

writeLock (myObject) {
   ...fiddle with it
}

It should be simple enough to add such functionality to D as it's little
different from templating. I'd tenatively propose a syntax like the
following, where the $ symbol is replaced with the contents of the block:

interface IRWLock {
   void readLock();
   void readUnlock();
   void writeLock();
   void writeUnlock();
}

block_template readLock(IRWLock o) {
   o.readLock();
   scope (exit) o.readUnlock();
   $
}

block_template writeLock(IRWLock o) {
   o.writeLock();
   scope (exit) o.writeUnlock();
   $
}

With local, hidden variables you would also be able to do something like:

block_template doOnce() {
   static bool hasRun = false;
   if (!hasRun) {
      hasRun = true;
      $
   }
}

int main() {
   while (true) {
      ...do stuff
      debug {
         doOnce {
            writefln("Value %s", foo);
         }
      }
      ...more stuff
      debug {
         doOnce {
            writefln("Value %s", bar);
         }
      }
   }
}
Aug 09 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Chris Williams wrote:
 I'm not sure whether the design of D 2.0 has stabilized as yet, but if not,
 I would like to suggest the ability to create custom block types.
[snip] FWIW we've been talking a long time ago about a simple lowering - if the last argument to a function is a delegate, allow moving the delegate's body outside of the function: fun(a, b, c) { body } | V fun((a, b, c) { body }); As far as Walter and I could tell, there are no syntactical issues created by such a lowering. But we've been wrong about that in the past (me 10x more often than him). Andrei
Aug 09 2010
next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Mon, 09 Aug 2010 23:21:25 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Chris Williams wrote:
 I'm not sure whether the design of D 2.0 has stabilized as yet, but if  
 not,
 I would like to suggest the ability to create custom block types.
[snip] FWIW we've been talking a long time ago about a simple lowering - if the last argument to a function is a delegate, allow moving the delegate's body outside of the function: fun(a, b, c) { body } | V fun((a, b, c) { body }); As far as Walter and I could tell, there are no syntactical issues created by such a lowering. But we've been wrong about that in the past (me 10x more often than him). Andrei
vote++
Aug 09 2010
prev sibling next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 Chris Williams wrote:
 I'm not sure whether the design of D 2.0 has stabilized as yet, but if not,
 I would like to suggest the ability to create custom block types.
[snip] FWIW we've been talking a long time ago about a simple lowering - if the last argument to a function is a delegate, allow moving the delegate's body outside of the function: fun(a, b, c) { body } | V fun((a, b, c) { body }); As far as Walter and I could tell, there are no syntactical issues created by such a lowering. But we've been wrong about that in the past (me 10x more often than him). Andrei
So this would basically allow the creation of custom flow control constructs at least to a limited extent? For example: void unless(T)(T condition, void delegate() executeThis) { if(!condition) executeThis(); } void until(T)(T condition, void delegate() executeThis) { while(!condition) executeThis(); } void main() { until(someoneKnowsWhetherPequalsNP() ) { writeln("Who knows?"); } unless(P == NP) { writeln("P != NP"); } }
Aug 09 2010
parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Wow! That looks sweet. I Imagine this could be put to good use inside
template constraints.. or so I think.

Thumbs up from me.

On Tue, Aug 10, 2010 at 6:40 AM, dsimcha <dsimcha yahoo.com> wrote:

 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
 article
 Chris Williams wrote:
 I'm not sure whether the design of D 2.0 has stabilized as yet, but if
not,
 I would like to suggest the ability to create custom block types.
[snip] FWIW we've been talking a long time ago about a simple lowering - if the last argument to a function is a delegate, allow moving the delegate's body outside of the function: fun(a, b, c) { body } | V fun((a, b, c) { body }); As far as Walter and I could tell, there are no syntactical issues created by such a lowering. But we've been wrong about that in the past (me 10x more often than him). Andrei
So this would basically allow the creation of custom flow control constructs at least to a limited extent? For example: void unless(T)(T condition, void delegate() executeThis) { if(!condition) executeThis(); } void until(T)(T condition, void delegate() executeThis) { while(!condition) executeThis(); } void main() { until(someoneKnowsWhetherPequalsNP() ) { writeln("Who knows?"); } unless(P == NP) { writeln("P != NP"); } }
Aug 10 2010
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
Andrei Alexandrescu Wrote:

 FWIW we've been talking a long time ago about a simple lowering - if the 
 last argument to a function is a delegate, allow moving the delegate's 
 body outside of the function:
 
 fun(a, b, c) { body }
 
   |
   V
 
 fun((a, b, c) { body });
I don't think, doOnce will work. Though, it's a useful idiom.
Aug 09 2010
parent Stanislav Blinov <blinov loniir.ru> writes:
  10.08.2010 9:19, Kagamin ïèűćò:
 Andrei Alexandrescu Wrote:

 FWIW we've been talking a long time ago about a simple lowering - if the
 last argument to a function is a delegate, allow moving the delegate's
 body outside of the function:

 fun(a, b, c) { body }

    |
    V

 fun((a, b, c) { body });
I don't think, doOnce will work. Though, it's a useful idiom. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Filtered-With-Copfilter: Version 0.84beta4 (ProxSMTP 1.8) Copfilter-Filtered-With: SpamAssassin 3.2.5 Copfilter-Virus-Scanned: ClamAV 0.94.2 by Markus Madlener http://www.copfilter.org
Maybe this one would: block_template doOnce(string F = __FILE__, int L = __LINE__)() { static bool hasRun = false; if (!hasRun) { hasRun = true; $ } } or this one (with proposed lowering syntax): void doOnce(string F = __FILE__, int L = __LINE__)(void delegate() dg) { static bool hasRun = false; if (!hasRun) { hasRun = true; dg(); } } -- **
Aug 10 2010
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2010-08-10 05:21, Andrei Alexandrescu wrote:
 Chris Williams wrote:
 I'm not sure whether the design of D 2.0 has stabilized as yet, but if
 not,
 I would like to suggest the ability to create custom block types.
[snip] FWIW we've been talking a long time ago about a simple lowering - if the last argument to a function is a delegate, allow moving the delegate's body outside of the function: fun(a, b, c) { body } | V fun((a, b, c) { body }); As far as Walter and I could tell, there are no syntactical issues created by such a lowering. But we've been wrong about that in the past (me 10x more often than him). Andrei
This would be awesome. I think Ruby and Scala have one of the best syntax for code blocks/delegates. Until then we can use this somewhat ugly hack: fun(a, b, c) in { // body }; For the above to work "fun" should return a struct which implements the opIn method. -- /Jacob Carlborg
Aug 10 2010
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-08-10 06:01:10 -0400, Jacob Carlborg <doob me.com> said:

 I think Ruby and Scala have one of the best syntax for code 
 blocks/delegates. Until then we can use this somewhat ugly hack:
 
 fun(a, b, c) in {
 // body
 };
 
 For the above to work "fun" should return a struct which implements the 
 opIn method.
But is this ugly hack (as you call it) really better than the "normal way"? fun(a, b, c, { // body }); At least with this one you know what to expect, and fun's code will be much easier to read too because you have no intermediary struct. Ugly hacks should be used only when they improve things substantially, which does not seem to be the case here. If it was part of the language then it'd be less of a hack and probably more usable. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 10 2010
prev sibling next sibling parent reply Mafi <mafi example.org> writes:
Am 10.08.2010 05:21, schrieb Andrei Alexandrescu:
 Chris Williams wrote:
 I'm not sure whether the design of D 2.0 has stabilized as yet, but if
 not,
 I would like to suggest the ability to create custom block types.
[snip] FWIW we've been talking a long time ago about a simple lowering - if the last argument to a function is a delegate, allow moving the delegate's body outside of the function: fun(a, b, c) { body } | V fun((a, b, c) { body }); As far as Walter and I could tell, there are no syntactical issues created by such a lowering. But we've been wrong about that in the past (me 10x more often than him). Andrei
Hi, I don't want to be inpolite but what if fun returns a delegate which accepts a delegate and fun is overloaded (the delegate parameter is optional): void delegate(void delegate()) fun(); void delegate(void delegate()) fun(void delegate()); ... fun(){...} //does this result in void or void delegate(void delegate()) ... It's the same as with property if they are allowed to call with parens. But this is a very unlikely to happen. I don't even know if delegate are allowed to take delegate as parameters.
Aug 10 2010
parent "Robert Jacques" <sandford jhu.edu> writes:
On Tue, 10 Aug 2010 06:59:11 -0400, Mafi <mafi example.org> wrote:

 Am 10.08.2010 05:21, schrieb Andrei Alexandrescu:
 Chris Williams wrote:
 I'm not sure whether the design of D 2.0 has stabilized as yet, but if
 not,
 I would like to suggest the ability to create custom block types.
[snip] FWIW we've been talking a long time ago about a simple lowering - if the last argument to a function is a delegate, allow moving the delegate's body outside of the function: fun(a, b, c) { body } | V fun((a, b, c) { body }); As far as Walter and I could tell, there are no syntactical issues created by such a lowering. But we've been wrong about that in the past (me 10x more often than him). Andrei
Hi, I don't want to be inpolite but what if fun returns a delegate which accepts a delegate and fun is overloaded (the delegate parameter is optional): void delegate(void delegate()) fun(); void delegate(void delegate()) fun(void delegate()); ... fun(){...} //does this result in void or void delegate(void delegate()) ... It's the same as with property if they are allowed to call with parens. But this is a very unlikely to happen. I don't even know if delegate are allowed to take delegate as parameters.
You're not being impolite, this is exactly what Andrei is looking for and delegates can take delegates as parameters. Although, you can't call delegates without (), so my gut says "fun {...}" would have to resolve to "fun(void delegate())". To use "delegate(void delegate()) fun()" the syntax would be "fun()() {...}". In general, overload ambiguities like these are allowed inside a module, but should be hijack errors when source coming from multiple modules.
Aug 10 2010
prev sibling next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
Andrei Alexandrescu wrote:

 Chris Williams wrote:
 I'm not sure whether the design of D 2.0 has stabilized as yet, but if not,
 I would like to suggest the ability to create custom block types.
[snip] FWIW we've been talking a long time ago about a simple lowering - if the last argument to a function is a delegate, allow moving the delegate's body outside of the function: fun(a, b, c) { body } | V fun((a, b, c) { body }); As far as Walter and I could tell, there are no syntactical issues created by such a lowering. But we've been wrong about that in the past (me 10x more often than him). Andrei
Nevertheless, it would be fantastic! This is exactly what can enables Ruby code to be so pleasant, though it is not the same construct. And extensions methods of course :)
Aug 10 2010
prev sibling next sibling parent Jason House <jason.james.house gmail.com> writes:
vote++

It's worth an  keyword if it keeps things simple for both users and the
compiler.


Andrei Alexandrescu Wrote:

 Chris Williams wrote:
 I'm not sure whether the design of D 2.0 has stabilized as yet, but if not,
 I would like to suggest the ability to create custom block types.
[snip] FWIW we've been talking a long time ago about a simple lowering - if the last argument to a function is a delegate, allow moving the delegate's body outside of the function: fun(a, b, c) { body } | V fun((a, b, c) { body }); As far as Walter and I could tell, there are no syntactical issues created by such a lowering. But we've been wrong about that in the past (me 10x more often than him). Andrei
Aug 10 2010
prev sibling next sibling parent Chris Williams <aahz seanet.com> writes:
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
article
 FWIW we've been talking a long time ago about a simple lowering - if
the
 last argument to a function is a delegate, allow moving the
delegate's
 body outside of the function:
 fun(a, b, c) { body }
   |
   V
 fun((a, b, c) { body });
I suppose that any method which works is fine. The advantage with a more preprocessor-like methodology is that it doesn't incur two function calls. Shipping delegates around to functions is nice for self-modifying code, but that's overkill for this sort of functionality. It has a fairly clear use for making complex thread synchronization look prettier, but if you're doing that sort of fancy footwork to begin with, then speed is probably a driving motive (or you're making code that's more complex than it needs to be. ;) ) But again, like I said, any method which works is probably fine. And possibly DMD is good at inlining such things. -Chris
Aug 10 2010
prev sibling next sibling parent aarti_pl <aarti interia.pl> writes:
W dniu 2010-08-10 05:21, Andrei Alexandrescu pisze:
 Chris Williams wrote:
 I'm not sure whether the design of D 2.0 has stabilized as yet, but if
 not,
 I would like to suggest the ability to create custom block types.
[snip] FWIW we've been talking a long time ago about a simple lowering - if the last argument to a function is a delegate, allow moving the delegate's body outside of the function: fun(a, b, c) { body } | V fun((a, b, c) { body }); As far as Walter and I could tell, there are no syntactical issues created by such a lowering. But we've been wrong about that in the past (me 10x more often than him). Andrei
I think it will be great to have it in language! But what about: unittest { } It could be just function call with delegate as a last parameter, but in the context e.g. of class body it is not possible to call functions... If there would be kind of static function call (in the context of class body) it would be easy to add e.g. to D runtime following signatures: unittest(void delegate() test); unittest(string name, void delegate() test); unittest(string name, string group, void delegate() test); ... or maybe function definition with anonymous, immutable last parameter? Just a few thoughts... BR Marcin Kuszczak (aarti_pl)
Aug 10 2010
prev sibling next sibling parent reply Chris Williams <aahz seanet.com> writes:
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
article
 FWIW we've been talking a long time ago about a simple lowering - if
the
 last argument to a function is a delegate, allow moving the
delegate's
 body outside of the function:
 fun(a, b, c) { body }
   |
   V
 fun((a, b, c) { body });
 As far as Walter and I could tell, there are no syntactical issues
 created by such a lowering.
Thinking about this a bit more, essentially we are doing the same thing as foreach<->opApply, where we have a function receiving a delegate that will probably be optimized into a local block. There are some key differences, though. Firstly, I can do this with your method: void doOnce(int delegate() dg) { static bool done = false; if (!done) { done = true; writefln("%s", dg()); } } int main() { for (uint i = 0; i < 5; i++) { doOnce() { return 42; } ...do stuff } return 0; } Having a return value sitting in the middle of what looks like a local block is a bit ugly. It seems like main() will end at "return 42". For creating something that operates like a code block, we would never want a return. That brings us to the second problem. Our last parameter for a custom block is always "void delegate()" and our return is always void. There's nothing to be gained by forcing the coder to write both. I'll grant that the delegate passing solution is overall prettier than the macro version I suggested in the original post. The ability to create a doOnce block that can be re-used in multiple places is lost by using delegates since the static variable will only exist in one place, but I can't say that the ability is a major one. The syntax I presented can be easily updated to match your version by the creation of an assumed void delegate() called $. block readLock(IRWLock o) { o.readLock(); scope (exit) o.readUnlock(); $(); }
Aug 10 2010
next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
Chris Williams wrote:

...
 That brings us to the second problem. Our last parameter for a custom
 block is always "void delegate()" and our return is always void.
 There's nothing to be gained by forcing the coder to write both.
 
ruby blocks have a special syntax for block parameters and foreach in D has it too. It could look like: void until(int limit, void delegate(int) dg); until(5 ; i) { ... } But maybe that is too weird, I dunno. Parameters are reversed here too wrt foreach.
Aug 10 2010
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Chris Williams" <aahz seanet.com> wrote in message 
news:i3s1a9$2vbc$1 digitalmars.com...
 int main() {
 for (uint i = 0; i < 5; i++) {
 doOnce() {
 return 42;
 }
 ...do stuff
 }

 return 0;
 }

 Having a return value sitting in the middle of what looks like a local
 block is a bit ugly. It seems like main() will end at "return 42". For
 creating something that operates like a code block, we would never
 want a return.
That's a very good point.
 That brings us to the second problem. Our last parameter for a custom
 block is always "void delegate()" and our return is always void.
Currently, all blocks are void, but I'm not sure that limitation should be preserved for custom blocks. Example: auto result = collection.reduce(a, b) { return a + b; };
Aug 10 2010
parent Chris Williams <aahz seanet.com> writes:
== Quote from Nick Sabalausky (a a.a)'s article
 "Chris Williams" <aahz seanet.com> wrote in message
 That brings us to the second problem. Our last parameter for a
custom
 block is always "void delegate()" and our return is always void.
Currently, all blocks are void, but I'm not sure that limitation
should be
 preserved for custom blocks. Example:
 auto result = collection.reduce(a, b) { return a + b; };
I considered whether there might be some value in having a block that returns a value and couldn't think of anything that wasn't better done by a true function. A one-use callback for something like QSort or whatever, makes sense though, I'd agree. But, if implemented, I'd wonder if a secondary keyword wouldn't be better like "break" instead of "return", so that there was no confusion of what scope was being referred to -- and so that one -could- actually return from the higher scope, like a regular local block. void doStuff() { lock(o) { if (o.x > 10) { break; // Leaves lock() } else { return; // Leaves doStuff() } } int res = collection.reduce(a, b) { if (a > 0 && b > 0) { break a + b; // Leaves reduce() } else { return; // Leaves doStuff() } } } That is sort of ugly, though.
Aug 11 2010
prev sibling parent reply cemiller <chris dprogramming.com> writes:
On Mon, 09 Aug 2010 20:21:25 -0700, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Chris Williams wrote:
 I'm not sure whether the design of D 2.0 has stabilized as yet, but if  
 not,
 I would like to suggest the ability to create custom block types.
[snip] FWIW we've been talking a long time ago about a simple lowering - if the last argument to a function is a delegate, allow moving the delegate's body outside of the function: fun(a, b, c) { body } | V fun((a, b, c) { body }); As far as Walter and I could tell, there are no syntactical issues created by such a lowering. But we've been wrong about that in the past (me 10x more often than him). Andrei
I think this way will be better: fun(a, b, c) { body } | V fun(a, b, c, { body }); so that you can pass parameters to fun itself. If you want parameters to the delegate, fun can just take ref parameters. Full example with definition: // definition: void fun(int a, int b, ref int c, void delegate() callback) { if(a == b) { c = 2; callback(); } else { c = 1; callback(); } } // call: int var = 0; fun(9, 9, var) { assert(var == 2); } this could be taken another step; if variable declarations could be allowed in a function call, it can be more localized: fun(9, 9, int var) { assert(var == 2); }
Aug 10 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"cemiller" <chris dprogramming.com> wrote in message 
news:op.vg8kr7h9ycwdcp mapddrule1.ffe.foxeg.com...
 On Mon, 09 Aug 2010 20:21:25 -0700, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> wrote:
 fun(a, b, c) { body }

   |
   V

 fun((a, b, c) { body });
I think this way will be better: fun(a, b, c) { body } | V fun(a, b, c, { body });
I was thinking something like this: void fun(int x, int y, int z, delegate void(int, int, int) dg) fun(x, y, z, a, b, c) { body } | V fun(x, y, z, (a, b, c) { body });
Aug 10 2010
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Tue, 10 Aug 2010 15:19:25 -0400, Nick Sabalausky <a a.a> wrote:

 "cemiller" <chris dprogramming.com> wrote in message
 news:op.vg8kr7h9ycwdcp mapddrule1.ffe.foxeg.com...
 On Mon, 09 Aug 2010 20:21:25 -0700, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 fun(a, b, c) { body }

   |
   V

 fun((a, b, c) { body });
I think this way will be better: fun(a, b, c) { body } | V fun(a, b, c, { body });
I was thinking something like this: void fun(int x, int y, int z, delegate void(int, int, int) dg) fun(x, y, z, a, b, c) { body } | V fun(x, y, z, (a, b, c) { body });
Mixing function args with delegate args makes me think of foreach: fun(x, y, z, (a, b, c) { body }); <=> fun(a, b, c; x, y, z) { body }
Aug 10 2010
parent reply Tomek =?UTF-8?B?U293acWEc2tp?= <just ask.me> writes:
Robert Jacques napisaƂ:

 I was thinking something like this:

 void fun(int x, int y, int z, delegate void(int, int, int) dg)

 fun(x, y, z, a, b, c) { body }

|
V

 fun(x, y, z, (a, b, c) { body });
Mixing function args with delegate args makes me think of foreach: fun(x, y, z, (a, b, c) { body }); <=> fun(a, b, c; x, y, z) { body }
All great, but if there's no remedy for the return WTF, I'd leave this (nice) feature in the drawer. void foo() { fun(a, b, c; x, y, z) { return; // who returns? } } Tomek
Aug 11 2010
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Wed, 11 Aug 2010 17:54:35 -0400, Tomek SowiƄski <just ask.me> wrote:

 Robert Jacques napisaƂ:

 I was thinking something like this:

 void fun(int x, int y, int z, delegate void(int, int, int) dg)

 fun(x, y, z, a, b, c) { body }

 |
 V

 fun(x, y, z, (a, b, c) { body });
Mixing function args with delegate args makes me think of foreach: fun(x, y, z, (a, b, c) { body }); <=> fun(a, b, c; x, y, z) { body }
All great, but if there's no remedy for the return WTF, I'd leave this (nice) feature in the drawer. void foo() { fun(a, b, c; x, y, z) { return; // who returns? } } Tomek
Fun does. This is the same as function/delegate literals today. Of course, putting a return statement inside a foreach block is probably a buggy edge case right now; sometimes it causes the parent scope to return and sometimes it doesn't compile.
Aug 11 2010
parent reply KennyTM~ <kennytm gmail.com> writes:
On Aug 12, 10 10:25, Robert Jacques wrote:
 On Wed, 11 Aug 2010 17:54:35 -0400, Tomek SowiƄski <just ask.me> wrote:

 Robert Jacques napisaƂ:

 I was thinking something like this:

 void fun(int x, int y, int z, delegate void(int, int, int) dg)

 fun(x, y, z, a, b, c) { body }

 |
 V

 fun(x, y, z, (a, b, c) { body });
Mixing function args with delegate args makes me think of foreach: fun(x, y, z, (a, b, c) { body }); <=> fun(a, b, c; x, y, z) { body }
All great, but if there's no remedy for the return WTF, I'd leave this (nice) feature in the drawer. void foo() { fun(a, b, c; x, y, z) { return; // who returns? } } Tomek
Fun does. This is the same as function/delegate literals today. Of course, putting a return statement inside a foreach block is probably a buggy edge case right now; sometimes it causes the parent scope to return and sometimes it doesn't compile.
This is an unacceptable buggy edge case. Consider the already-working code int find_three(int[] arr) { foreach (i, x; arr) { if (x == 3) return i; } return -1; } If I replace the foreach with a custom block e.g. int find_three_retro(int[] arr) { foreach_retro (i, x; arr) { if (x == 3) return i; } return -1; } then suddenly the function doesn't work anymore. It's better not to provide a feature inconsistent with other parts of the language.
Aug 12 2010
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 12 Aug 2010 07:43:25 -0400, KennyTM~ <kennytm gmail.com> wrote:

 On Aug 12, 10 10:25, Robert Jacques wrote:
 On Wed, 11 Aug 2010 17:54:35 -0400, Tomek SowiƄski <just ask.me> wrote:

 Robert Jacques napisaƂ:

 I was thinking something like this:

 void fun(int x, int y, int z, delegate void(int, int, int) dg)

 fun(x, y, z, a, b, c) { body }

 |
 V

 fun(x, y, z, (a, b, c) { body });
Mixing function args with delegate args makes me think of foreach: fun(x, y, z, (a, b, c) { body }); <=> fun(a, b, c; x, y, z) { body }
All great, but if there's no remedy for the return WTF, I'd leave this (nice) feature in the drawer. void foo() { fun(a, b, c; x, y, z) { return; // who returns? } } Tomek
Fun does. This is the same as function/delegate literals today. Of course, putting a return statement inside a foreach block is probably a buggy edge case right now; sometimes it causes the parent scope to return and sometimes it doesn't compile.
This is an unacceptable buggy edge case. Consider the already-working code int find_three(int[] arr) { foreach (i, x; arr) { if (x == 3) return i; } return -1; } If I replace the foreach with a custom block e.g. int find_three_retro(int[] arr) { foreach_retro (i, x; arr) { if (x == 3) return i; } return -1; } then suddenly the function doesn't work anymore. It's better not to provide a feature inconsistent with other parts of the language.
Code that exploits a bug in the implementation isn't "working" in any sense of the word. One of the points I was making is that return statements inside a foreach do different things depending on what you're foreaching over. So this feature would be adding consistency, not removing it.
Aug 12 2010
parent reply KennyTM~ <kennytm gmail.com> writes:
On Aug 12, 10 23:42, Robert Jacques wrote:
 On Thu, 12 Aug 2010 07:43:25 -0400, KennyTM~ <kennytm gmail.com> wrote:

 On Aug 12, 10 10:25, Robert Jacques wrote:
 On Wed, 11 Aug 2010 17:54:35 -0400, Tomek SowiƄski <just ask.me> wrote:

 Robert Jacques napisaƂ:

 I was thinking something like this:

 void fun(int x, int y, int z, delegate void(int, int, int) dg)

 fun(x, y, z, a, b, c) { body }

 |
 V

 fun(x, y, z, (a, b, c) { body });
Mixing function args with delegate args makes me think of foreach: fun(x, y, z, (a, b, c) { body }); <=> fun(a, b, c; x, y, z) { body }
All great, but if there's no remedy for the return WTF, I'd leave this (nice) feature in the drawer. void foo() { fun(a, b, c; x, y, z) { return; // who returns? } } Tomek
Fun does. This is the same as function/delegate literals today. Of course, putting a return statement inside a foreach block is probably a buggy edge case right now; sometimes it causes the parent scope to return and sometimes it doesn't compile.
This is an unacceptable buggy edge case. Consider the already-working code int find_three(int[] arr) { foreach (i, x; arr) { if (x == 3) return i; } return -1; } If I replace the foreach with a custom block e.g. int find_three_retro(int[] arr) { foreach_retro (i, x; arr) { if (x == 3) return i; } return -1; } then suddenly the function doesn't work anymore. It's better not to provide a feature inconsistent with other parts of the language.
Code that exploits a bug in the implementation isn't "working" in any sense of the word. One of the points I was making is that return statements inside a foreach do different things depending on what you're foreaching over. So this feature would be adding consistency, not removing it.
void locate_three_or_five(int[] arr) { int res = -1; foreach (i, x; arr) { if_is_one_of(x, [3, 5]) { res = i; break; // now what? } } writeln("found 3 or 5 at ", res); }
Aug 12 2010
next sibling parent KennyTM~ <kennytm gmail.com> writes:
On Aug 13, 10 02:56, KennyTM~ wrote:
 On Aug 12, 10 23:42, Robert Jacques wrote:
 On Thu, 12 Aug 2010 07:43:25 -0400, KennyTM~ <kennytm gmail.com> wrote:

 On Aug 12, 10 10:25, Robert Jacques wrote:
 On Wed, 11 Aug 2010 17:54:35 -0400, Tomek SowiƄski <just ask.me> wrote:

 Robert Jacques napisaƂ:

 I was thinking something like this:

 void fun(int x, int y, int z, delegate void(int, int, int) dg)

 fun(x, y, z, a, b, c) { body }

 |
 V

 fun(x, y, z, (a, b, c) { body });
Mixing function args with delegate args makes me think of foreach: fun(x, y, z, (a, b, c) { body }); <=> fun(a, b, c; x, y, z) { body }
All great, but if there's no remedy for the return WTF, I'd leave this (nice) feature in the drawer. void foo() { fun(a, b, c; x, y, z) { return; // who returns? } } Tomek
Fun does. This is the same as function/delegate literals today. Of course, putting a return statement inside a foreach block is probably a buggy edge case right now; sometimes it causes the parent scope to return and sometimes it doesn't compile.
This is an unacceptable buggy edge case. Consider the already-working code int find_three(int[] arr) { foreach (i, x; arr) { if (x == 3) return i; } return -1; } If I replace the foreach with a custom block e.g. int find_three_retro(int[] arr) { foreach_retro (i, x; arr) { if (x == 3) return i; } return -1; } then suddenly the function doesn't work anymore. It's better not to provide a feature inconsistent with other parts of the language.
Code that exploits a bug in the implementation isn't "working" in any sense of the word. One of the points I was making is that return statements inside a foreach do different things depending on what you're foreaching over. So this feature would be adding consistency, not removing it.
void locate_three_or_five(int[] arr) { int res = -1; foreach (i, x; arr) { if_is_one_of(x, [3, 5]) { res = i; break; // now what? } } writeln("found 3 or 5 at ", res); }
This could be resolved by just disallowing local return in this syntax. And then make these keyword functions (foreach_retro, if_is_one_of) to be written like opApply. Of course this means things like int foo = reduce( ... ) { ... } is impossible.
Aug 12 2010
prev sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 12 Aug 2010 14:56:54 -0400, KennyTM~ <kennytm gmail.com> wrote:

 On Aug 12, 10 23:42, Robert Jacques wrote:
 On Thu, 12 Aug 2010 07:43:25 -0400, KennyTM~ <kennytm gmail.com> wrote:

 On Aug 12, 10 10:25, Robert Jacques wrote:
 On Wed, 11 Aug 2010 17:54:35 -0400, Tomek SowiƄski <just ask.me>  
 wrote:

 Robert Jacques napisaƂ:

 I was thinking something like this:

 void fun(int x, int y, int z, delegate void(int, int, int) dg)

 fun(x, y, z, a, b, c) { body }

 |
 V

 fun(x, y, z, (a, b, c) { body });
Mixing function args with delegate args makes me think of foreach: fun(x, y, z, (a, b, c) { body }); <=> fun(a, b, c; x, y, z) { body }
All great, but if there's no remedy for the return WTF, I'd leave this (nice) feature in the drawer. void foo() { fun(a, b, c; x, y, z) { return; // who returns? } } Tomek
Fun does. This is the same as function/delegate literals today. Of course, putting a return statement inside a foreach block is probably a buggy edge case right now; sometimes it causes the parent scope to return and sometimes it doesn't compile.
This is an unacceptable buggy edge case. Consider the already-working code int find_three(int[] arr) { foreach (i, x; arr) { if (x == 3) return i; } return -1; } If I replace the foreach with a custom block e.g. int find_three_retro(int[] arr) { foreach_retro (i, x; arr) { if (x == 3) return i; } return -1; } then suddenly the function doesn't work anymore. It's better not to provide a feature inconsistent with other parts of the language.
Code that exploits a bug in the implementation isn't "working" in any sense of the word. One of the points I was making is that return statements inside a foreach do different things depending on what you're foreaching over. So this feature would be adding consistency, not removing it.
void locate_three_or_five(int[] arr) { int res = -1; foreach (i, x; arr) { if_is_one_of(x, [3, 5]) { res = i; break; // now what? } } writeln("found 3 or 5 at ", res); }
I was going to say that the break statement only works with for loops, while loops and switch statments, not foreach. But the spec says otherwise: "A break exits the enclosing statement. break exits the innermost enclosing while, for, foreach, do, or switch statement, resuming execution at the statement following it." However, please remember that with opApply, the foreach body gets converted into a delegate and then all the standard delegate rules apply. Which is my point: right now these rules regarding foreach seem to have succumb to spec-rot (i.e. they haven't been re-evaluated based on the introduction of opApply.
Aug 13 2010