January 05, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | On Sunday, 5 January 2014 at 17:17:27 UTC, Artur Skawina wrote:
> While 'void' is not a first class type in D, there /is/ a special
> case for returning 'void' from functions - so all of the above can
> simply be written as:
>
> struct gl {
> static auto ref opDispatch(string name, Args...)(Args args) {
> scope (exit) checkGLError();
> return mixin("gl"~name~"(args)");
> }
> }
>
> artur
That's awesome! Thanks for enlightening me!
|
January 05, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Sun, Jan 5, 2014 at 5:18 PM, Jacob Carlborg <doob@me.com> wrote: > Just for the record. In Rails, that's the old, now discourage, Rails 2 syntax. I didn't know that, thanks. I read it during the holidays in Martin Fowler's book on DSL, but indeed that book is from 2005, IIRC. > In Rails 3 and later the following syntax is preferred: > > Table.where(first_name: "foo").first > > Which in D would look like: > > Table.where(["first_name": "foo"]).first; Yes, using AA is a nice idea, which avoids introducing first_name in the current scope. Some other possibilities could be: Table.where!(e => e.first_name == "foo").first; // Similar to std.range.filter Table.where.first_name!(e => e == "foo").first; Table.where((string first_name) => first_name == "foo").first; // By extracting the parameter name The syntax is heavier than your example, but some nice logic can put into a closure. Some also advocate: Table.where.first_name.equals("foo").first; But I find it a bit too clunky. |
January 06, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Philippe Sigaud | On 2014-01-05 22:44, Philippe Sigaud wrote: > I didn't know that, thanks. I read it during the holidays in Martin > Fowler's book on DSL, but indeed that book is from 2005, IIRC. That's a bit old :). According to this site[1] Rails 1.0 was released in December 2005. Rails 4.0 was released in June 2013. I think there are two reasons why they deprecated that syntax: * They want to avoid method_missing (same as opDispatch in D) * They want to have the name of a column close to the value of that column. Example: Table.find_first_by_fist_name_and_last_name("foo", "bar") In the above example the values and the columns they belongs to are quite disconnected. The column names are far to the right and the values are far to the left. With the AA syntax you get the column name and its value closely connected. It's clear to see which value belongs to which column. > Yes, using AA is a nice idea, which avoids introducing first_name in > the current scope. I have to admit that it looks a lot better in Ruby than in D. > Some other possibilities could be: > > Table.where!(e => e.first_name == "foo").first; // Similar to std.range.filter This is the one I like best and it's possible to have the same syntax in Ruby as well with a plugin, Squeel[2]. This allows to have more advanced quires containing "or" and negation. The problem is it's basically only equality that works with this syntax. You cannot overload !=, && or || in D. You could of course use method names like "equals", "and" and "or". In Squeel they "solved" it by overloading | and & to mean "or" and "and". That causes other problems with operator precedence, one needs to wrap everything in parentheses. In D we would need more finer grained control of operator overloading, like overload == separately from !=. Or, I come back to this all the time, AST macros. > Table.where.first_name!(e => e == "foo").first; If I look at the API in Rails I think this could cause some conflicts with all the methods that are available on the object returned by Table.where. > Table.where((string first_name) => first_name == "foo").first; // By > extracting the parameter name > > The syntax is heavier than your example, but some nice logic can put > into a closure. Same problem as above. > Some also advocate: > > Table.where.first_name.equals("foo").first; > > But I find it a bit too clunky. Same problem as above. [1] http://railsapps.github.io/rails-release-history.html [2] https://github.com/activerecord-hackery/squeel -- /Jacob Carlborg |
January 06, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | >> I didn't know that, thanks. I read it during the holidays in Martin Fowler's book on DSL, but indeed that book is from 2005, IIRC. > > > That's a bit old :). According to this site[1] Rails 1.0 was released in December 2005. Rails 4.0 was released in June 2013. Ouch, that was 2010, my bad. > > I think there are two reasons why they deprecated that syntax: > > * They want to avoid method_missing (same as opDispatch in D) > > * They want to have the name of a column close to the value of that column. Example: > > Table.find_first_by_fist_name_and_last_name("foo", "bar") > > In the above example the values and the columns they belongs to are quite disconnected. The column names are far to the right and the values are far to the left. With the AA syntax you get the column name and its value closely connected. It's clear to see which value belongs to which column. Yes indeed. Too clever for its own good. > I have to admit that it looks a lot better in Ruby than in D. Ruby does have a clean syntax (though I find blocks to be a bit heavy). > > >> Some other possibilities could be: >> >> Table.where!(e => e.first_name == "foo").first; // Similar to >> std.range.filter > > > This is the one I like best and it's possible to have the same syntax in Ruby as well with a plugin, Squeel[2]. This allows to have more advanced quires containing "or" and negation. > > The problem is it's basically only equality that works with this syntax. You cannot overload !=, && or || in D. You could of course use method names like "equals", "and" and "or". But I'm not overloading any syntax here. I'm using a closure, not an expression template. Table.where!(e => e.first_name != "foo" && e.first_name.length > 4).first; |
January 07, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Philippe Sigaud | On 2014-01-06 22:07, Philippe Sigaud wrote: > Ruby does have a clean syntax (though I find blocks to be a bit heavy). I like the block syntax. It allows one to create what looks like new statements: loop do # endless loop end I would like to have that in D as well, but with braces instead: void loop (void delegate () dg); loop { // endless loop } In Ruby 1.9 they introduced a slight more lightweight syntax for lambdas: callback = -> { p "foo" } bar(callback) > But I'm not overloading any syntax here. I'm using a closure, not an > expression template. > > Table.where!(e => e.first_name != "foo" && e.first_name.length > 4).first; How is that being transformed in to SQL then? -- /Jacob Carlborg |
January 07, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Tue, Jan 7, 2014 at 8:50 AM, Jacob Carlborg <doob@me.com> wrote:
> I would like to have that in D as well, but with braces instead:
>
> void loop (void delegate () dg);
>
> loop {
> // endless loop
> }
What about:
void loop(void delegate() dg);
loop({
...
});
Since any block is a void delegate().
|
January 07, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Philippe Sigaud | On 2014-01-07 13:22, Philippe Sigaud wrote: > What about: > > void loop(void delegate() dg); > > loop({ > ... > > }); > > Since any block is a void delegate(). That's what we have now, and that doesn't look like a built-in statement ;) -- /Jacob Carlborg |
January 07, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Tue, Jan 07, 2014 at 03:35:43PM +0100, Jacob Carlborg wrote: > On 2014-01-07 13:22, Philippe Sigaud wrote: > > >What about: > > > >void loop(void delegate() dg); > > > >loop({ > >... > > > >}); > > > >Since any block is a void delegate(). > > That's what we have now, and that doesn't look like a built-in statement ;) [...] Y'know, I've always wanted "trailing delegate syntax": func(x, y, z; p, q, r) { // body } gets translated into: func(p, q, r, (x, y, z) => /* body */); Since we already have UFCS, which translates a leading fragment into the first argument (x.func(y) --> func(x,y)), it seems perfectly reasonable to do something with the final argument too, like the above. This would allow one to implement, for example, foreach_reverse as a library function instead of a language keyword: void foreach_reverse(I, R)(R range, void delegate(I) dg) { ... dg(idx); ... } // Gets translated to: // foreach_reverse(range, (uint i) => /* body */); foreach_reverse (uint i; range) { ... // body } // And you can use UFCS too: range.foreach_reverse(uint i) { ... // body } I'm not holding my breath on this one, though. It's a rather big change and ultimately is just syntactic sugar. Maybe it can go on the list of features for D3... ;-) T -- Famous last words: I wonder what will happen if I do *this*... |
January 07, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 2014-01-07 16:58, H. S. Teoh wrote: > Y'know, I've always wanted "trailing delegate syntax": > > func(x, y, z; p, q, r) { > // body > } > > gets translated into: > > func(p, q, r, (x, y, z) => /* body */); > > Since we already have UFCS, which translates a leading fragment into the > first argument (x.func(y) --> func(x,y)), it seems perfectly reasonable > to do something with the final argument too, like the above. > > This would allow one to implement, for example, foreach_reverse as a > library function instead of a language keyword: > > void foreach_reverse(I, R)(R range, void delegate(I) dg) > { > ... > dg(idx); > ... > } > > // Gets translated to: > // foreach_reverse(range, (uint i) => /* body */); > foreach_reverse (uint i; range) { > ... // body > } > > // And you can use UFCS too: > range.foreach_reverse(uint i) { > ... // body > } Exactly, that's what it is for. Perhaps supporting an alias parameter would be good as well, since those are inlined: void foo (alias dg) (); foo { // body } Translated to: foo!({ // body }); > I'm not holding my breath on this one, though. It's a rather big change > and ultimately is just syntactic sugar. Maybe it can go on the list of > features for D3... ;-) I've brought this up before. If I recall correctly, it didn't was that much resistance as one could think. Although this was before we had the lambda syntax. -- /Jacob Carlborg |
January 07, 2014 Re: Is it possible to handle 'magic' property assignments a'la PHP? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Tue, Jan 07, 2014 at 09:18:48PM +0100, Jacob Carlborg wrote: > On 2014-01-07 16:58, H. S. Teoh wrote: > > >Y'know, I've always wanted "trailing delegate syntax": > > > > func(x, y, z; p, q, r) { > > // body > > } > > > >gets translated into: > > > > func(p, q, r, (x, y, z) => /* body */); > > > >Since we already have UFCS, which translates a leading fragment into > >the first argument (x.func(y) --> func(x,y)), it seems perfectly > >reasonable to do something with the final argument too, like the > >above. > > > >This would allow one to implement, for example, foreach_reverse as a library function instead of a language keyword: > > > > void foreach_reverse(I, R)(R range, void delegate(I) dg) > > { > > ... > > dg(idx); > > ... > > } > > > > // Gets translated to: > > // foreach_reverse(range, (uint i) => /* body */); > > foreach_reverse (uint i; range) { > > ... // body > > } > > > > // And you can use UFCS too: > > range.foreach_reverse(uint i) { > > ... // body > > } > > Exactly, that's what it is for. Perhaps supporting an alias parameter would be good as well, since those are inlined: > > void foo (alias dg) (); > > foo { > // body > } > > Translated to: > > foo!({ > // body > }); > > >I'm not holding my breath on this one, though. It's a rather big change and ultimately is just syntactic sugar. Maybe it can go on the list of features for D3... ;-) > > I've brought this up before. If I recall correctly, it didn't was that much resistance as one could think. Although this was before we had the lambda syntax. [...] 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 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 } // 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); } EXTENDED EXAMPLE: void for_every_other(alias loopBody, R)(R range) if (is(typeof(loopBody(size_t.init, ElementType!R.init)))) { size_t i=0; while (!range.empty) { loopBody(i, range.front); range.popFront(); if (!range.empty) { range.popFront(); i += 2; } } } // Prints: // --- // 0: "a" // 2: "c" // 4: "e" // --- for_every_other (i, j; ["a", "b", "c", "d", "e", "f"]) { writefln("%s: %s", i, j); } T -- Error: Keyboard not attached. Press F1 to continue. -- Yoon Ha Lee, CONLANG |
Copyright © 1999-2021 by the D Language Foundation