January 08, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 2014-01-07 21:44, H. S. Teoh wrote: > If you have a good motivating use case in favor of this addition that > can be used in a DIP, I'd vote for it. I'm usually not good at these arguments. I mean, it would be nice to have but I don't have any strong arguments for it. It's just syntax sugar. > I like the alias idea, so here's the revised proposal: > > 1) Argumentless trailing-delegate syntax: > > // Given this declaration: > void foo(alias dg)(); > > // We can write this: > foo { > // body > } > > // which will get translated into: > foo!({ /* body */ }); > > 2) With arguments: > > // Given this declaration: > void foo(alias dg, A...)(A args); > > // Or its non-template equivalent: > void foo(alias dg)(A arg1, B arg2, C arg3, ...); > > // We can write this: > foo(a,b,c,...) { > // body > } > > // which gets translated into: > foo!({ /* body */})(a,b,c,...); > > 3) With indexing arguments: > > // Given this declaration: > void foo(alias dg, I..., A...)(A args) > if (is(typeof(dg(I)))); > > // Or its non-template equivalent: > void foo(alias dg)(A arg1, B arg2, C arg3, ...) { > ... > dg(i, j, k); > ... > } > > // We can write this: > foo(i,j,k,... ; a,b,c,...) { > // body > } I would prefer to have the delegate arguments last. > // which gets translated into: > foo!((i,j,k,...) { /* body */ })(a,b,c,...); > > > EXAMPLE: > > void for_every_other(alias loopBody, R)(R range) > if (is(typeof(loopBody(ElementType!R.init)))) > { > while (!range.empty) { > loopBody(range.front); > range.popFront(); > if (!range.empty) > range.popFront(); > } > } > > // Prints: > // --- > // 1 > // 3 > // 5 > // --- > for_every_other (i; [1,2,3,4,5,6]) { > writeln(i); > } If we instead have the delegate argument last UFCS still works: [1,2,3,4,5,6].for_every_other(i) { writeln(i); } Hmm. Actually, your example is more D like. I don't know which I example I like best. I'll see if I can write something down. -- /Jacob Carlborg |
January 08, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Wed, Jan 08, 2014 at 08:32:15AM +0100, Jacob Carlborg wrote: > On 2014-01-07 21:44, H. S. Teoh wrote: [...] > >I like the alias idea, so here's the revised proposal: > > > >1) Argumentless trailing-delegate syntax: > > > > // Given this declaration: > > void foo(alias dg)(); > > > > // We can write this: > > foo { > > // body > > } > > > > // which will get translated into: > > foo!({ /* body */ }); > > > >2) With arguments: > > > > // Given this declaration: > > void foo(alias dg, A...)(A args); > > > > // Or its non-template equivalent: > > void foo(alias dg)(A arg1, B arg2, C arg3, ...); > > > > // We can write this: > > foo(a,b,c,...) { > > // body > > } > > > > // which gets translated into: > > foo!({ /* body */})(a,b,c,...); > > > >3) With indexing arguments: > > > > // Given this declaration: > > void foo(alias dg, I..., A...)(A args) > > if (is(typeof(dg(I)))); > > > > // Or its non-template equivalent: > > void foo(alias dg)(A arg1, B arg2, C arg3, ...) { > > ... > > dg(i, j, k); > > ... > > } > > > > // We can write this: > > foo(i,j,k,... ; a,b,c,...) { > > // body > > } > > I would prefer to have the delegate arguments last. The reason I wrote it this way is so that it parallels the foreach construction better: my_foreach (i; range) { ... } parallels: foreach (i; range) { ... } [...] > >EXAMPLE: > > > > void for_every_other(alias loopBody, R)(R range) > > if (is(typeof(loopBody(ElementType!R.init)))) > > { > > while (!range.empty) { > > loopBody(range.front); > > range.popFront(); > > if (!range.empty) > > range.popFront(); > > } > > } > > > > // Prints: > > // --- > > // 1 > > // 3 > > // 5 > > // --- > > for_every_other (i; [1,2,3,4,5,6]) { > > writeln(i); > > } > > If we instead have the delegate argument last UFCS still works: > > [1,2,3,4,5,6].for_every_other(i) { > writeln(i); > } > > Hmm. Actually, your example is more D like. I don't know which I example I like best. [...] Keep in mind that the identifier list before the ';' is actually the delegate's parameter list, it's not passing anything in. They are placeholders for what the function will pass to the delegate. So: my_foreach (i,j ; range) { writeln(i + j); } actually means: my_foreach(range, (i,j) => writeln(i + j)); and my_foreach could be implemented something like this: void my_foreach(alias dg, R)(R range) if (is(typeof(dg(size_t.init, ElementType!R.init)))) { size_t idx = 0; while (!range.empty) { // N.B.: calls dg with i = idx, j = range.front dg(idx, range.front); range.popFront(); idx++; } } If we go by this, then UFCS should still work: range.my_foreach(i,j) { /* body */ } should be translated to: my_foreach(i, j ; range) { /* body */ } which in turn translates to: my_foreach!((i, j) { /* body */ })(range); In the first case, there is no ambiguity with `range.my_foreach(i,j);`, which should translate to `my_foreach(range,i,j);`, because the presence of the trailing code block without an intervening ';' makes it clear that the above is intended, rather than `my_foreach(range,i,j);`. In fact, we can already almost get the desired syntax in the current language: /* Current D already supports this: */ range.my_foreach!((i,j) { /* body */ }); which isn't that much different from the proposed syntactic sugar: range.my_foreach(i,j) { /* body */ } We're just saving on the '!', ';', and an extra pair of parentheses. I guess the only real advantage is that we get to imitate built-in foreach syntax. E.g., if we use the form with arguments but no indexing arguments, we can pretend to be an if-statement: // (Whatever "dynamic if" means...) void dynamic_if(alias dg)(bool cond) if (is(typeof(dg()))) { // Haha, we're just wrapping the built-in 'if' cuz we // can. if (cond) dg(); } int x; dynamic_if (x==0) { writeln("Boo yah!"); } Or if we use the argumentless form to implement custom block constructs: void pure_block(alias dg)() pure if (is(typeof(dg()))) { dg(); } void nothrow_block(alias dg)() nothrow if (is(typeof(dg()))) { dg(); } void safe_block(alias dg)() @safe if (is(typeof(dg()))) { dg(); } void main() { pure_block { // Whoopie! now we acquired a construct for // marking blocks of code pure! } nothrow_block { // And we can have multiple such blocks in a // single function. } safe_block { // Now I'm just showing off. :P } } T -- Curiosity kills the cat. Moral: don't be the cat. |
January 09, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 2014-01-08 19:04, H. S. Teoh wrote: > The reason I wrote it this way is so that it parallels the foreach > construction better: > > my_foreach (i; range) { > ... > } > > parallels: > > foreach (i; range) { > ... > } I guessed that. > Keep in mind that the identifier list before the ';' is actually the > delegate's parameter list, it's not passing anything in. They are > placeholders for what the function will pass to the delegate. So: > > my_foreach (i,j ; range) { > writeln(i + j); > } > > actually means: > > my_foreach(range, (i,j) => writeln(i + j)); Yeah, I know. > and my_foreach could be implemented something like this: > > void my_foreach(alias dg, R)(R range) > if (is(typeof(dg(size_t.init, ElementType!R.init)))) > { > size_t idx = 0; > while (!range.empty) { > // N.B.: calls dg with i = idx, j = range.front > dg(idx, range.front); > > range.popFront(); > idx++; > } > } > > > If we go by this, then UFCS should still work: > > range.my_foreach(i,j) { /* body */ } > > should be translated to: > > my_foreach(i, j ; range) { /* body */ } > > which in turn translates to: > > my_foreach!((i, j) { /* body */ })(range); > > In the first case, there is no ambiguity with `range.my_foreach(i,j);`, > which should translate to `my_foreach(range,i,j);`, because the presence > of the trailing code block without an intervening ';' makes it clear > that the above is intended, rather than `my_foreach(range,i,j);`. Didn't think of that. > In fact, we can already almost get the desired syntax in the current > language: > > /* Current D already supports this: */ > range.my_foreach!((i,j) { > /* body */ > }); Almost ;) > which isn't that much different from the proposed syntactic sugar: > > range.my_foreach(i,j) { > /* body */ > } > > We're just saving on the '!', ';', and an extra pair of parentheses. It quickly get clumsy when you need to pass regular arguments to the function: void foo (alias dg) (int a, int b); foo!((i, j) { // body })(1, 2); Not pretty. > I guess the only real advantage is that we get to imitate built-in > foreach syntax. E.g., if we use the form with arguments but no indexing > arguments, we can pretend to be an if-statement: > > // (Whatever "dynamic if" means...) > void dynamic_if(alias dg)(bool cond) > if (is(typeof(dg()))) > { > // Haha, we're just wrapping the built-in 'if' cuz we > // can. > if (cond) dg(); > } > > int x; > dynamic_if (x==0) { > writeln("Boo yah!"); > } > > Or if we use the argumentless form to implement custom block constructs: BTW, what do you think about not needing braces if the delegate body only contains a single statement, like with regular statements: dynamic_if (x==0) writeln("foo"); With the alias syntax, I'm wondering if the compiler will have any problem with that you can pass almost anything to an alias parameter and not just a delegate. -- /Jacob Carlborg |
January 09, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Thu, Jan 09, 2014 at 09:49:17AM +0100, Jacob Carlborg wrote: > On 2014-01-08 19:04, H. S. Teoh wrote: [...] > >In fact, we can already almost get the desired syntax in the current language: > > > > /* Current D already supports this: */ > > range.my_foreach!((i,j) { > > /* body */ > > }); > > Almost ;) > > >which isn't that much different from the proposed syntactic sugar: > > > > range.my_foreach(i,j) { > > /* body */ > > } > > > >We're just saving on the '!', ';', and an extra pair of parentheses. > > It quickly get clumsy when you need to pass regular arguments to the function: > > void foo (alias dg) (int a, int b); > > foo!((i, j) { > // body > })(1, 2); > > Not pretty. True. So this should be one of the motivating use cases for our DIP. > >I guess the only real advantage is that we get to imitate built-in foreach syntax. E.g., if we use the form with arguments but no indexing arguments, we can pretend to be an if-statement: > > > > // (Whatever "dynamic if" means...) > > void dynamic_if(alias dg)(bool cond) > > if (is(typeof(dg()))) > > { > > // Haha, we're just wrapping the built-in 'if' cuz we > > // can. > > if (cond) dg(); > > } > > > > int x; > > dynamic_if (x==0) { > > writeln("Boo yah!"); > > } > > > >Or if we use the argumentless form to implement custom block constructs: > > BTW, what do you think about not needing braces if the delegate body only contains a single statement, like with regular statements: > > dynamic_if (x==0) > writeln("foo"); > > With the alias syntax, I'm wondering if the compiler will have any problem with that you can pass almost anything to an alias parameter and not just a delegate. [...] I'm afraid that this might become ambiguous, for example: int* gun(...) {...} func (x==0) *gun(y); Does the second statement mean `func!(() => *gun(y))(x==0)`, or does it mean `func(x==0) * gun(y)`? While it's not hard to disambiguate this semantically, it means it's impossible to parse before you analyze it, which is probably a bad idea. T -- Nobody is perfect. I am Nobody. -- pepoluan, GKC forum |
January 09, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 2014-01-09 18:57, H. S. Teoh wrote: > I'm afraid that this might become ambiguous, for example: > > int* gun(...) {...} > > func (x==0) > *gun(y); > > Does the second statement mean `func!(() => *gun(y))(x==0)`, or does it > mean `func(x==0) * gun(y)`? While it's not hard to disambiguate this > semantically, it means it's impossible to parse before you analyze it, > which is probably a bad idea. Right, probably not a good idea. -- /Jacob Carlborg |
Copyright © 1999-2021 by the D Language Foundation