digitalmars.D - property
- Adam D. Ruppe (87/87) Aug 04 2012 So the existing -property in the compiler as absolutely
- Adam D. Ruppe (10/10) Aug 04 2012 I should add: if a function is not marked @property, it should
- bearophile (5/8) Aug 04 2012 I think I'd like functions not marked with @property to require
- Adam D. Ruppe (7/9) Aug 04 2012 You have the -property switch for breaking piles of perfectly
- Jonathan M Davis (8/21) Aug 04 2012 And I think that the only thing that the -property switch currently gets...
- bearophile (9/13) Aug 04 2012 The -property switch is present since lot of time, and I think
- Jonathan M Davis (7/14) Aug 04 2012 I'd be very surprised if all that many people compile with -property. I'...
- Adam D. Ruppe (111/113) Aug 05 2012 Indeed. Sometimes I try it just to see what happens, and always
- Dmitry Olshansky (12/28) Aug 05 2012 +1
- Simen Kjaeraas (5/13) Aug 05 2012 Yeah. I seem to do that every single time I want to give an example.
- bearophile (6/12) Aug 05 2012 All my large amount of D2 code gives no warning with -property.
- Adam D. Ruppe (19/22) Aug 05 2012 octal actually works because it isn't a function.
- bearophile (7/8) Aug 05 2012 I understand. The kind of programs I write enjoy run-time errors
- Kapps (19/36) Aug 05 2012 I completely agree, particularl with the UFCS part. UFCS is
- =?ISO-8859-1?Q?Jos=E9_Armando_Garc=EDa_Sancio?= (21/54) Aug 06 2012 Just a small comment. I have been following this thread a little and
- Timon Gehr (6/52) Aug 07 2012 String lambdas would quite certainly have been left out.
- =?ISO-8859-1?Q?Jos=E9_Armando_Garc=EDa_Sancio?= (20/85) Aug 07 2012 e
- Jacob Carlborg (5/12) Aug 07 2012 I'm not entirely sure but I think using an alias-parameter the delegate
- Timon Gehr (12/92) Aug 07 2012 It is also a matter of execution speed and GC pressure. None of the D
- =?ISO-8859-1?Q?Jos=E9_Armando_Garc=EDa_Sancio?= (12/106) Aug 07 2012 to
- Timon Gehr (23/130) Aug 07 2012 The reason it works in C++ for transform, for_each etc. is because
- =?ISO-8859-1?Q?Jos=E9_Armando_Garc=EDa_Sancio?= (8/32) Aug 07 2012 :
- Brad Anderson (12/73) Aug 06 2012 me
- Brad Anderson (3/43) Aug 07 2012 https://github.com/D-Programming-Language/phobos/pull/744
- =?ISO-8859-1?Q?Jos=E9_Armando_Garc=EDa_Sancio?= (11/88) Aug 06 2012 ge
- Jonathan M Davis (5/12) Aug 04 2012 I wholeheartedly agree, but it's a divisive subject. Some of us feel ver...
- deadalnix (12/45) Aug 04 2012 Note that something more is wrong.
- Adam D. Ruppe (2/3) Aug 04 2012 I think you're right about that too...
- Adam D. Ruppe (22/22) Aug 04 2012 I think I've cracked the getters...
- Jacob Carlborg (14/42) Aug 04 2012 I don't think that's correct behavior. I think the correct behavior
- Jacob Carlborg (15/20) Aug 04 2012 I wouldn't actually mind a way to do this, perhaps something like this:
- Jonathan M Davis (21/43) Aug 04 2012 That would be kind of cool, though I would have suggested that putting
- Jacob Carlborg (23/42) Aug 05 2012 I see two reasons:
- Jacob Carlborg (9/28) Aug 05 2012 A few more reasons:
- Adam D. Ruppe (54/66) Aug 04 2012 Yes, I agree in general, but if a getter returns a ref, you should
- Jacob Carlborg (7/52) Aug 05 2012 Doesn't this already work?
- Adam D. Ruppe (9/11) Aug 05 2012 Yes, but it is in my test file to make sure it still works,
- Jacob Carlborg (5/7) Aug 05 2012 Hehe, yes, of course. No pressure :)
- Adam D. Ruppe (24/28) Aug 04 2012 I did this and now I think this thing is almost done
- Adam D. Ruppe (10/10) Aug 04 2012 OK, I just compiled one of my work apps with the hacked up dmd.
- Jonathan M Davis (3/17) Aug 04 2012 If you can get properties working properly that quickly, that's fantasti...
- Adam D. Ruppe (12/14) Aug 04 2012 I did just realize I missed something.... but I'm convinced the
- Jacob Carlborg (4/13) Aug 05 2012 Awesome :)
- Jacob Carlborg (6/28) Aug 05 2012 BTW, how will this interact with overloaded operators and similar more
- Adam D. Ruppe (7/10) Aug 05 2012 I'm not sure yet... stuff like this is one reason why it didn't
- Michael (5/36) Aug 06 2012 It would be cool
- Chad J (71/71) Aug 04 2012 There was a very long discussion on this before that lead me to write th...
- Adam D. Ruppe (12/14) Aug 04 2012 I'll have to read it... my thing right now works, as far as I can
- Chad J (3/17) Aug 04 2012 Best of luck, and thank you for thinking about this and getting the ball...
- Jonathan M Davis (8/10) Aug 06 2012 No. Both the string syntax and the new lambda syntax are here to stay. =
So the existing -property in the compiler as absolutely worthless. It is semantically wrong. property void function() func() { return { assert(0, "success"); }; } void main() { func(); // should assert 0 success, doesn't auto dele = &func; dele(); // should assert 0 success, doesn't } Does the same thing with and without -property, and it is wrong both ways. Now, let's talk about doing it right. First, I think the entire getter design in the compiler is counter productive. It looks like it is part of the AssignExp... but you want getters to work in a lot of places, not just AssignExp. It looks to me that it actually belongs in the resolveProperties function in expression.c, or maybe even somewhere else since I tried this and it didn't quite work. I think this is operating on a whole line, not just the individual pieces. But regardless, it definitely belongs on a lower level than it is. See, if you ask me, every single mention of a function name that is marked property needs to be rewritten. This might break setters, but we'll cross that bridge when we come to it. When we look back at the test code: func(); // should assert 0 success, doesn't auto dele = &func; These two lines both currently refer to the getter function itself. We want the getter function to be completely invisible to all other code. This should be rewritten kinda like if this were in the code: #define func (func()) This would also fix things like func += 10; if func returned a ref int. === property ref int func() { static int a; return a; } void main() { // all of these should work; func should look just like an int to the outside world int a = func; int* b = &func; func += 10; } === callexp.d(19): Error: cannot implicitly convert expression (& func) of type int function() property ref to int* Let's try running our "macro" over it void main() { int a = (func()); int* b = &(func()); (func()) += 10; } What ACTUALLY happens right now is that works. Indeed, you HAVE to use the () right now to make it work! What SHOULD happen: callexp.d(18): Error: function expected before (), not func() of type int callexp.d(20): Error: function expected before (), not func() of type int Or something like that. Since property ref int func() is supposed to be interchangable for a plain int func;, no special enforcement of property syntax is required: it is illegal to call an int like a function, and func is an int as far as the outside world is concerned. This is how the property syntax is enforced: by the compiler's existing type checks. No additional code should be there to check syntax. So, I have two questions: 1) Do we all agree that properties should be interchangeable for plain variables of the return value's type in all contexts? That is, if I can make this work with a pull request, is that going to be acceptable? 2) Does anyone who knows the compiler better want to give me some hints on the implementation? I'm still pretty sure the resolveProperties function is too far into it, but func on its own is just a void* to the function I believe at this point so... yeah that is complicating things. Perhaps *that* is what needs to change. I'm also open to ideas on setters, but right now getter is what I want to focus on. If we have to rewrite a getter call on the left hand side of an assign exp into a setter call, we can figure that out later. Hell, it might even just work. But one thing at a time.
Aug 04 2012
I should add: if a function is not marked property, it should not change at all: it should be callable with and without parens, including sometimes referring to the wrong thing, exactly like it is now. I come to fix code, not to break it. Rewriting references to property function names should fix all property related issues without breaking any existing code (except that which explicitly specified property but depended on the wrong semantics, code which is arguably already broken, just like any other bug fix can do.)
Aug 04 2012
Adam D. Ruppe:I should add: if a function is not marked property, it should not change at all: it should be callable with and without parens,I think I'd like functions not marked with property to require the (). Bye, bearophile
Aug 04 2012
On Sunday, 5 August 2012 at 02:17:18 UTC, bearophile wrote:I think I'd like functions not marked with property to require the ().You have the -property switch for breaking piles of perfectly good code while enabling no new functionality. What I'm doing is completely independent of -property: I'm making properties actually work. And I'm almost there... I just got the struct members working but introduced a regression where dmd assert fails.
Aug 04 2012
On Sunday, August 05, 2012 04:25:26 Adam D. Ruppe wrote:On Sunday, 5 August 2012 at 02:17:18 UTC, bearophile wrote:And I think that the only thing that the -property switch currently gets _right_ is complaining about non-property functions getting called with parens. It's very buggy. Regardless, there are indeed two general issues here: 1. Make property work in general. 2. Make -property work correctly. - Jonathan M DavisI think I'd like functions not marked with property to require the ().You have the -property switch for breaking piles of perfectly good code while enabling no new functionality. What I'm doing is completely independent of -property: I'm making properties actually work. And I'm almost there... I just got the struct members working but introduced a regression where dmd assert fails.
Aug 04 2012
Adam D. Ruppe:You have the -property switch for breaking piles of perfectly good code while enabling no new functionality.The -property switch is present since lot of time, and I think most people that write D2 code compile their libraries with -property. So I don't think it breaks lot of D2 code today.What I'm doing is completely independent of -property: I'm making properties actually work.I understand. Don't rush things, even if your design takes few days we are dealing with those problems since years, so few more days are not a problem. Bye, bearophile
Aug 04 2012
On Sunday, August 05, 2012 05:59:34 bearophile wrote:Adam D. Ruppe:I'd be very surprised if all that many people compile with -property. I'm pretty sure that there are a lot of people (the majority?) who don't even compile with -w or -wi. Obviously, some people do, but from what I've seen, I'd guess that most people compile with the bare minimum flags required, and - property is _very_ buggy anyway. - Jonathan M DavisYou have the -property switch for breaking piles of perfectly good code while enabling no new functionality.The -property switch is present since lot of time, and I think most people that write D2 code compile their libraries with -property. So I don't think it breaks lot of D2 code today.
Aug 04 2012
On Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:I'd be very surprised if all that many people compile with -property.Indeed. Sometimes I try it just to see what happens, and always the same results: it doesn't solve problems and complains about code. Some examples of things that break: import std.algorithm; foreach(i; [1,2,3].map!"a+1") { } prophate.d(5): Error: not a property [1,2,3].map!("a+1") Of course, this is relatively new, using ufcs in 2.059, so the breakage probably isn't too bad, but I'm not the only one who writes it this way - I've seen a number of reddit and newsgroup comments do this too, especially when chaining it. Another thing I do is I have a template function called getDocument in a lot of my code. It takes the document name as a template param, because in a lot of cases, I want to build the doc at compile time. auto document = getDocument!"about-me"; Is that a function or a property? I think it is a function, it does a lot work. But, the arguments are there already... do we really need to say getDocument!"about-me"() just to appease a compiler switch? (This function also can take some runtime params, but it has defaults so param less calling works as well.) What about std.conv? This works fine in all old code - its functions either naturally require parens (such as to!(int)("10"), gotta have at least the outer set, or octal!"555" - it is an enum, so gotta not use them).... but with UFCS, that's actually out the window now: int i = "10".to!int; prophate.d(4): Error: not a property "10".to!(int) Now, I've never actually written this. With map!(), I do that in the real world, but not with this. Still, I could imagine someone who might. If we had the strictness before 2.059, I could live with it. Just add the () (though, then queue the people complaining about syntatic noise!). But, now we're several months past that. I say that ship has sailed. The big breakage for me is something I have been doing for years though, and that's using my dom.d with chaining: import arsd.dom; // in one place I might use: auto ele = Element.make("span", "Hello").className("hello").setAttribute("foo", "bar"); // but in another I say: ele.className = "something"; Now, many of my newer functions obviate this kind of thing; Element.make now offers overloads for inner text, inner html, and common attributes. There's now an addClass() so it isn't all dependent on className. But, there's still hundreds of lines of me using the older functions like this, and every so often, it still comes up. What happens with -property? prophate.d(7): Error: not a property ele.className arsd/domconvenience.d(49): Error: not a property className arsd/domconvenience.d(81): Error: not a property n.strip arsd/domconvenience.d(81): Error: not a property className arsd/domconvenience.d(88): Error: not a property className arsd/domconvenience.d(218): Error: not a property e.innerHTML arsd/dom.d(201): Error: not a property e.innerText arsd/dom.d(212): Error: not a property e.innerText arsd/dom.d(217): Error: not a property e.innerText arsd/dom.d(232): Error: not a property e.innerText arsd/dom.d(234): Error: not a property e.className arsd/dom.d(242): Error: not a property m.innerHTML arsd/dom.d(506): Error: not a property name.toLower arsd/dom.d(508): Error: not a property value.strip arsd/dom.d(1162): Error: not a property child.innerText arsd/dom.d(1634): Error: not a property innerText arsd/dom.d(1831): Error: not a property e.innerText arsd/dom.d(1859): Error: not a property child.innerText arsd/dom.d(1913): Error: not a property e.innerText arsd/dom.d(2135): Error: not a property this.captionElement().innerText arsd/dom.d(2140): Error: not a property this.captionElement().innerText wooo, but only the first line is this specific example. You can also see in here strip() and toLower() on which is just me being lax: auto v = value.strip.toLower(); for example. Adding the inner parens would be annoying but it wouldn't require changing the form of the code like changing the dual use ones. ....huh, my example here actually does work if I set property, but still use it as a function. Buggy switch. But I know I've tried this before and had one set of usages break with property and another break without it. Maybe it was innerHTML, which can also be overloaded to take an Appender argument. Yeah, then I get this: arsd/dom.d(982): Error: cannot overload both property and non-property functions There's just no winning without redoing a LOT of code, changing names, changing some expressions into statements since the chaining is out, duplicating functionality across two functions when one could do... It was at that point that I decided it'd be better to put my effort into killing -property than trying to "fix" my code to appease its idiotic demands. And now the UFCS map, filter, etc. chains and whatnot are just icing on the cake. Bearophile, I've seen you complain about the mess of parenthesis in std.algorithm before. With ufcs and template arguments, you can be rid of many of them. It is actually pretty beautiful, even to me. Do you really want to break that now? My position right now is property has a strict syntax out of necessity. Stuff without property should work the way it does now - thus minimizing broken code to that which already opted-in to property (which generally does it right anyway), while keeping the status quo on the rest. It can turn out ugly, I'll agree, but it can be beautiful too and just plain isn't worth the code breakage either way.
Aug 05 2012
On 05-Aug-12 18:32, Adam D. Ruppe wrote:On Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:+1 [snip]I'd be very surprised if all that many people compile with -property.Indeed. Sometimes I try it just to see what happens, and always the same results: it doesn't solve problems and complains about code.And now the UFCS map, filter, etc. chains and whatnot are just icing on the cake. Bearophile, I've seen you complain about the mess of parenthesis in std.algorithm before. With ufcs and template arguments, you can be rid of many of them. It is actually pretty beautiful, even to me. Do you really want to break that now? My position right now is property has a strict syntax out of necessity. Stuff without property should work the way it does now - thus minimizing broken code to that which already opted-in to property (which generally does it right anyway), while keeping the status quo on the rest. It can turn out ugly, I'll agree, but it can be beautiful too and just plain isn't worth the code breakage either way.Well in the end I think strict property enforcement was meant to solve some corner cases (e.g. returning delegates from, and taking address of no-arg functions). But then it promptly killed at least one cool idiom (chaining & assignment in one name). Then once UFCS was finally working property spoiled it (e.g. your algorithm examples). So I'm with you - let non- property work as before, and property ones to be god damn properly enforced. -- Dmitry Olshansky
Aug 05 2012
On Sun, 05 Aug 2012 16:32:49 +0200, Adam D. Ruppe <destructionator gmail.com> wrote:import std.algorithm; foreach(i; [1,2,3].map!"a+1") { } prophate.d(5): Error: not a property [1,2,3].map!("a+1") Of course, this is relatively new, using ufcs in 2.059, so the breakage probably isn't too bad, but I'm not the only one who writes it this way - I've seen a number of reddit and newsgroup comments do this too, especially when chaining it.Yeah. I seem to do that every single time I want to give an example. -- Simen
Aug 05 2012
Adam D. Ruppe:octal!"555" - it is an enum, so gotta not use them).... but with UFCS, that's actually out the window now:What about turning octal into a propety to fix this problem?There's just no winning without redoing a LOT of code, changing names, changing some expressions into statements since the chaining is out, duplicating functionality across two functions when one could do...All my large amount of D2 code gives no warning with -property. Maybe you should fix your code. Bye, bearophile
Aug 05 2012
On Sunday, 5 August 2012 at 15:45:37 UTC, bearophile wrote:What about turning octal into a propety to fix this problem?octal actually works because it isn't a function. But in general, changing non-properties to properties just for syntax is backward anyway. Whether something is a property or not isn't a question of parenthesis. I think it was a mistake to conflate "property" with "parenthesis-less syntax" in the first place, since they aren't really the same thing. A getX/setX pair in C++ is conceptually a property, but uses a different syntax. A method call in Ruby is still a method call, despite being able to write it without parens. Something should be marked property because it fits the conceptual definition, not because you want to leave parens out. That's also why I don't like -property's implementation: it focuses purely on the syntax, without worrying about the concept. If you get the concept right, the syntax will fit on its own - for example, a property returning an int shouldn't be callable with () because calling an int like a function is nonsense regardless.All my large amount of D2 code gives no warning with -property. Maybe you should fix your code.Maybe you should pay my mortgage.
Aug 05 2012
Adam D. Ruppe:Maybe you should pay my mortgage.I understand. The kind of programs I write enjoy run-time errors raised on overflow on integral values operations. Recently I opened a silly thread about this in D learn. Adding those to D will help me pay my bills and better keep my mind. Bye, bearophile
Aug 05 2012
On Sunday, 5 August 2012 at 14:32:50 UTC, Adam D. Ruppe wrote:On Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:I completely agree, particularl with the UFCS part. UFCS is designed to get rid of the horrible mess of (), and now we want to arbitrarily force a () anyways? Seems like it defeats the purpose. To me, when comparing range.filter!"a > 2".map!"a*a".countUntil(3) to range.filter!"a > 2"().map!"a*a"().countUntil(3) Those extra paranthesis just don't do anything, they don't give extra meaning, they don't accomplish anything useful but distract from the actual expression. Most importantly though, with the focus on avoiding breaking code, why are we putting in -property which has the *sole* purpose of breaking existing code. And a whole lot of it at that. Never mind that a huge number of people strongly dislike the idea of enforcing paranthesis in the first place. It's not even about whether I agree with enforcing it, it's that I strongly disagree with breaking code for no benefit besides what some people will arbitrarily think is cleaner code, and others will not.I'd be very surprised if all that many people compile with -property.Indeed. Sometimes I try it just to see what happens, and always the same results: it doesn't solve problems and complains about code. Some examples of things that break: import std.algorithm; foreach(i; [1,2,3].map!"a+1") { } prophate.d(5): Error: not a property [1,2,3].map!("a+1") Of course, this is relatively new, using ufcs in 2.059, so the breakage probably isn't too bad, but I'm not the only one who writes it this way - I've seen a number of reddit and newsgroup comments do this too, especially when chaining it. [snip]
Aug 05 2012
On Sun, Aug 5, 2012 at 2:32 PM, Kapps <opantm2+spam gmail.com> wrote:On Sunday, 5 August 2012 at 14:32:50 UTC, Adam D. Ruppe wrote:Just a small comment. I have been following this thread a little and was somewhat surprise that the argument against enforcing parenthesis on non-properties is that a call like [1,2,3].map!"a+1" would look ugly as [1,2,3].map!"a+1"(). To me that is a issue of the std.algorithm module and not so much of the language. Personally I am not a huge fan of using strings as a way to pass a function into a high-order function. I suspect that this string stuff became popular because D didn't have lambda declarations and type inference when the module was designed and implemented. I wonder if the module signatures would look different if you designed it to use the current features of D. To be honest, when first saw 'some_array.map!"a+1"()' a few years back when I first learned about D my knee jerk reaction was: "from where in the world is 'a' coming from?". I remember I had to read std/algorithm.d and whatever module implements unary "string" functions to figure out what was going on. Anyways, I digress. Part of me looks forward to the day that I can use D reliably another part of my wants to just wait for Rust to hopefully get it "right". Thanks, -JoseOn Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:I completely agree, particularl with the UFCS part. UFCS is designed to get rid of the horrible mess of (), and now we want to arbitrarily force a () anyways? Seems like it defeats the purpose. To me, when comparing range.filter!"a > 2".map!"a*a".countUntil(3) to range.filter!"a > 2"().map!"a*a"().countUntil(3) Those extra paranthesis just don't do anything, they don't give extra meaning, they don't accomplish anything useful but distract from the actual expression.I'd be very surprised if all that many people compile with -property.Indeed. Sometimes I try it just to see what happens, and always the same results: it doesn't solve problems and complains about code. Some examples of things that break: import std.algorithm; foreach(i; [1,2,3].map!"a+1") { } prophate.d(5): Error: not a property [1,2,3].map!("a+1") Of course, this is relatively new, using ufcs in 2.059, so the breakage probably isn't too bad, but I'm not the only one who writes it this way - I've seen a number of reddit and newsgroup comments do this too, especially when chaining it. [snip]
Aug 06 2012
On 08/07/2012 07:59 AM, José Armando García Sancio wrote:On Sun, Aug 5, 2012 at 2:32 PM, Kapps<opantm2+spam gmail.com> wrote:String lambdas would quite certainly have been left out. Anyway, string lambdas are unrelated to the discussion of std.algorithm idioms in this context. [1,2,3].map!(a=>a+1) [1,2,3].map!(a=>a+1)()On Sunday, 5 August 2012 at 14:32:50 UTC, Adam D. Ruppe wrote:Just a small comment. I have been following this thread a little and was somewhat surprise that the argument against enforcing parenthesis on non-properties is that a call like [1,2,3].map!"a+1" would look ugly as [1,2,3].map!"a+1"(). To me that is a issue of the std.algorithm module and not so much of the language. Personally I am not a huge fan of using strings as a way to pass a function into a high-order function. I suspect that this string stuff became popular because D didn't have lambda declarations and type inference when the module was designed and implemented.On Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:I completely agree, particularl with the UFCS part. UFCS is designed to get rid of the horrible mess of (), and now we want to arbitrarily force a () anyways? Seems like it defeats the purpose. To me, when comparing range.filter!"a> 2".map!"a*a".countUntil(3) to range.filter!"a> 2"().map!"a*a"().countUntil(3) Those extra paranthesis just don't do anything, they don't give extra meaning, they don't accomplish anything useful but distract from the actual expression.I'd be very surprised if all that many people compile with -property.Indeed. Sometimes I try it just to see what happens, and always the same results: it doesn't solve problems and complains about code. Some examples of things that break: import std.algorithm; foreach(i; [1,2,3].map!"a+1") { } prophate.d(5): Error: not a property [1,2,3].map!("a+1") Of course, this is relatively new, using ufcs in 2.059, so the breakage probably isn't too bad, but I'm not the only one who writes it this way - I've seen a number of reddit and newsgroup comments do this too, especially when chaining it. [snip]
Aug 07 2012
On Tue, Aug 7, 2012 at 10:39 AM, Timon Gehr <timon.gehr gmx.ch> wrote:On 08/07/2012 07:59 AM, Jos=E9 Armando Garc=EDa Sancio wrote:meOn Sun, Aug 5, 2012 at 2:32 PM, Kapps<opantm2+spam gmail.com> wrote:On Sunday, 5 August 2012 at 14:32:50 UTC, Adam D. Ruppe wrote:On Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:I'd be very surprised if all that many people compile with -property.Indeed. Sometimes I try it just to see what happens, and always the sa=eresults: it doesn't solve problems and complains about code. Some examples of things that break: import std.algorithm; foreach(i; [1,2,3].map!"a+1") { } prophate.d(5): Error: not a property [1,2,3].map!("a+1") Of course, this is relatively new, using ufcs in 2.059, so the breakag=yprobably isn't too bad, but I'm not the only one who writes it this wa=()- I've seen a number of reddit and newsgroup comments do this too, especially when chaining it. [snip]I completely agree, particularl with the UFCS part. UFCS is designed to get rid of the horrible mess of (), and now we want to arbitrarily force a =Yep. The "problem" is not string lambda but that the mapping function is passed a template argument (which you need for string lambda to work). I guess that this is nice because you can alias the template or pass multiple lambdas (a little obscure but okay). If the lambda function was passed as a runtime parameter and not a template parameter can just do: [1, 2, 3].map(a=3D>a+1) If this was the case we wouldn't be talking about this non-property vs property with regard to map. I other words the map signature could look as follow (pseudo-code): Range!T map(T, U)(Range!U range, T delegate(U)); Thanks, -Jose P.S. You can still alias the map using a closure that binds the delegate but I digress.String lambdas would quite certainly have been left out. Anyway, string lambdas are unrelated to the discussion of std.algorithm idioms in this context. [1,2,3].map!(a=3D>a+1) [1,2,3].map!(a=3D>a+1)()anyways? Seems like it defeats the purpose. To me, when comparing range.filter!"a> 2".map!"a*a".countUntil(3) to range.filter!"a> 2"().map!"a*a"().countUntil(3) Those extra paranthesis just don't do anything, they don't give extra meaning, they don't accomplish anything useful but distract from the actual expression.Just a small comment. I have been following this thread a little and was somewhat surprise that the argument against enforcing parenthesis on non-properties is that a call like [1,2,3].map!"a+1" would look ugly as [1,2,3].map!"a+1"(). To me that is a issue of the std.algorithm module and not so much of the language. Personally I am not a huge fan of using strings as a way to pass a function into a high-order function. I suspect that this string stuff became popular because D didn't have lambda declarations and type inference when the module was designed and implemented.
Aug 07 2012
On 2012-08-07 20:37, José Armando García Sancio wrote:Yep. The "problem" is not string lambda but that the mapping function is passed a template argument (which you need for string lambda to work). I guess that this is nice because you can alias the template or pass multiple lambdas (a little obscure but okay). If the lambda function was passed as a runtime parameter and not a template parameter can just do: [1, 2, 3].map(a=>a+1)I'm not entirely sure but I think using an alias-parameter the delegate will be inlined. Delegates are in general not inlined. -- /Jacob Carlborg
Aug 07 2012
On 08/07/2012 08:37 PM, José Armando García Sancio wrote:On Tue, Aug 7, 2012 at 10:39 AM, Timon Gehr<timon.gehr gmx.ch> wrote:It is also a matter of execution speed and GC pressure. None of the D compilers is able to inline delegate parameters at least as well as alias template parameters afaik. Furthermore, only the current form can _guarantee_ that no hidden GC allocations take place due to parameter passing to map.On 08/07/2012 07:59 AM, José Armando García Sancio wrote:Yep. The "problem" is not string lambda but that the mapping function is passed a template argument (which you need for string lambda to work).On Sun, Aug 5, 2012 at 2:32 PM, Kapps<opantm2+spam gmail.com> wrote:String lambdas would quite certainly have been left out. Anyway, string lambdas are unrelated to the discussion of std.algorithm idioms in this context. [1,2,3].map!(a=>a+1) [1,2,3].map!(a=>a+1)()On Sunday, 5 August 2012 at 14:32:50 UTC, Adam D. Ruppe wrote:Just a small comment. I have been following this thread a little and was somewhat surprise that the argument against enforcing parenthesis on non-properties is that a call like [1,2,3].map!"a+1" would look ugly as [1,2,3].map!"a+1"(). To me that is a issue of the std.algorithm module and not so much of the language. Personally I am not a huge fan of using strings as a way to pass a function into a high-order function. I suspect that this string stuff became popular because D didn't have lambda declarations and type inference when the module was designed and implemented.On Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:I completely agree, particularl with the UFCS part. UFCS is designed to get rid of the horrible mess of (), and now we want to arbitrarily force a () anyways? Seems like it defeats the purpose. To me, when comparing range.filter!"a> 2".map!"a*a".countUntil(3) to range.filter!"a> 2"().map!"a*a"().countUntil(3) Those extra paranthesis just don't do anything, they don't give extra meaning, they don't accomplish anything useful but distract from the actual expression.I'd be very surprised if all that many people compile with -property.Indeed. Sometimes I try it just to see what happens, and always the same results: it doesn't solve problems and complains about code. Some examples of things that break: import std.algorithm; foreach(i; [1,2,3].map!"a+1") { } prophate.d(5): Error: not a property [1,2,3].map!("a+1") Of course, this is relatively new, using ufcs in 2.059, so the breakage probably isn't too bad, but I'm not the only one who writes it this way - I've seen a number of reddit and newsgroup comments do this too, especially when chaining it. [snip]I guess that this is nice because you can alias the template or pass multiple lambdas (a little obscure but okay). If the lambda function was passed as a runtime parameter and not a template parameter can just do: [1, 2, 3].map(a=>a+1)Well, no you cannot, because the current language would not be able to deduce a type for 'a'.If this was the case we wouldn't be talking about this non-property vs property with regard to map.We would be talking about improving IFTI to support cross-parameter type deduction. (and maybe we would constantly be complaining about poor GC performance.) Some programmers who use it now would presumably avoid std.algorithm because of the poor predictability of performance.
Aug 07 2012
On Tue, Aug 7, 2012 at 12:27 PM, Timon Gehr <timon.gehr gmx.ch> wrote:On 08/07/2012 08:37 PM, Jos=E9 Armando Garc=EDa Sancio wrote:y.On Tue, Aug 7, 2012 at 10:39 AM, Timon Gehr<timon.gehr gmx.ch> wrote:On 08/07/2012 07:59 AM, Jos=E9 Armando Garc=EDa Sancio wrote:On Sun, Aug 5, 2012 at 2:32 PM, Kapps<opantm2+spam gmail.com> wrote:On Sunday, 5 August 2012 at 14:32:50 UTC, Adam D. Ruppe wrote:On Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:I'd be very surprised if all that many people compile with -propert=toIndeed. Sometimes I try it just to see what happens, and always the same results: it doesn't solve problems and complains about code. Some examples of things that break: import std.algorithm; foreach(i; [1,2,3].map!"a+1") { } prophate.d(5): Error: not a property [1,2,3].map!("a+1") Of course, this is relatively new, using ufcs in 2.059, so the breakage probably isn't too bad, but I'm not the only one who writes it this way - I've seen a number of reddit and newsgroup comments do this too, especially when chaining it. [snip]I completely agree, particularl with the UFCS part. UFCS is designed =aget rid of the horrible mess of (), and now we want to arbitrarily force =Interesting. I can't speak for the GC and allocation you mention since I never tried to implement this myself but I should point out that C++ STL's algorithm "module" (transform, for_each, etc) works this way. Having said that, if D can't infer the type of lambda parameters (which I thought the current version of D could) and create a function/delegate based on the body then this is a no go. Thanks for you insight. -JoseIt is also a matter of execution speed and GC pressure. None of the D compilers is able to inline delegate parameters at least as well as alias template parameters afaik. Furthermore, only the current form can _guarantee_ that no hidden GC allocations take place due to parameter passing to map.Yep. The "problem" is not string lambda but that the mapping function is passed a template argument (which you need for string lambda to work).String lambdas would quite certainly have been left out. Anyway, string lambdas are unrelated to the discussion of std.algorithm idioms in this context. [1,2,3].map!(a=3D>a+1) [1,2,3].map!(a=3D>a+1)()() anyways? Seems like it defeats the purpose. To me, when comparing range.filter!"a> 2".map!"a*a".countUntil(3) to range.filter!"a> 2"().map!"a*a"().countUntil(3) Those extra paranthesis just don't do anything, they don't give extra meaning, they don't accomplish anything useful but distract from the actual expression.Just a small comment. I have been following this thread a little and was somewhat surprise that the argument against enforcing parenthesis on non-properties is that a call like [1,2,3].map!"a+1" would look ugly as [1,2,3].map!"a+1"(). To me that is a issue of the std.algorithm module and not so much of the language. Personally I am not a huge fan of using strings as a way to pass a function into a high-order function. I suspect that this string stuff became popular because D didn't have lambda declarations and type inference when the module was designed and implemented.
Aug 07 2012
On 08/07/2012 10:52 PM, José Armando García Sancio wrote:On Tue, Aug 7, 2012 at 12:27 PM, Timon Gehr<timon.gehr gmx.ch> wrote:The reason it works in C++ for transform, for_each etc. is because those functions are eager. Allocation-free transform with runtime delegate in D: import std.algorithm, std.range; void transform(IR,OR,I,O)(IR input, OR output, scope O delegate(I) dg) if(is(typeof(input.map!dg.copy(output)))) { input.map!dg.copy(output); } void main(){ int[3] result; int b = 1; [1,2,3].transform(result[], (int a)=>a+b); assert(result[] == [2,3,4]); } Note that parameter type deduction is lost for the delegate. I'd like type deduction to work if the signature of 'transform' is changed to: void transform(IR,OR,I=ElementType!IR,O)(IR input, OR output, scope O delegate(I) dg); [1,2,3].transform(result[], a=>a+b); Lazy map with runtime delegate would have to remember the delegate, therefore it could not be a scope delegate.On 08/07/2012 08:37 PM, José Armando García Sancio wrote:Interesting. I can't speak for the GC and allocation you mention since I never tried to implement this myself but I should point out that C++ STL's algorithm "module" (transform, for_each, etc) works this way. Having said that, if D can't infer the type of lambda parameters (which I thought the current version of D could) and create a function/delegate based on the body then this is a no go. Thanks for you insight. -JoseOn Tue, Aug 7, 2012 at 10:39 AM, Timon Gehr<timon.gehr gmx.ch> wrote:It is also a matter of execution speed and GC pressure. None of the D compilers is able to inline delegate parameters at least as well as alias template parameters afaik. Furthermore, only the current form can _guarantee_ that no hidden GC allocations take place due to parameter passing to map.On 08/07/2012 07:59 AM, José Armando García Sancio wrote:Yep. The "problem" is not string lambda but that the mapping function is passed a template argument (which you need for string lambda to work).On Sun, Aug 5, 2012 at 2:32 PM, Kapps<opantm2+spam gmail.com> wrote:String lambdas would quite certainly have been left out. Anyway, string lambdas are unrelated to the discussion of std.algorithm idioms in this context. [1,2,3].map!(a=>a+1) [1,2,3].map!(a=>a+1)()On Sunday, 5 August 2012 at 14:32:50 UTC, Adam D. Ruppe wrote:Just a small comment. I have been following this thread a little and was somewhat surprise that the argument against enforcing parenthesis on non-properties is that a call like [1,2,3].map!"a+1" would look ugly as [1,2,3].map!"a+1"(). To me that is a issue of the std.algorithm module and not so much of the language. Personally I am not a huge fan of using strings as a way to pass a function into a high-order function. I suspect that this string stuff became popular because D didn't have lambda declarations and type inference when the module was designed and implemented.On Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:I completely agree, particularl with the UFCS part. UFCS is designed to get rid of the horrible mess of (), and now we want to arbitrarily force a () anyways? Seems like it defeats the purpose. To me, when comparing range.filter!"a> 2".map!"a*a".countUntil(3) to range.filter!"a> 2"().map!"a*a"().countUntil(3) Those extra paranthesis just don't do anything, they don't give extra meaning, they don't accomplish anything useful but distract from the actual expression.I'd be very surprised if all that many people compile with -property.Indeed. Sometimes I try it just to see what happens, and always the same results: it doesn't solve problems and complains about code. Some examples of things that break: import std.algorithm; foreach(i; [1,2,3].map!"a+1") { } prophate.d(5): Error: not a property [1,2,3].map!("a+1") Of course, this is relatively new, using ufcs in 2.059, so the breakage probably isn't too bad, but I'm not the only one who writes it this way - I've seen a number of reddit and newsgroup comments do this too, especially when chaining it. [snip]
Aug 07 2012
On Tue, Aug 7, 2012 at 1:52 PM, Jos=E9 Armando Garc=EDa Sancio <jsancio gmail.com> wrote:On Tue, Aug 7, 2012 at 12:27 PM, Timon Gehr <timon.gehr gmx.ch> wrote::On 08/07/2012 08:37 PM, Jos=E9 Armando Garc=EDa Sancio wrote:On Tue, Aug 7, 2012 at 10:39 AM, Timon Gehr<timon.gehr gmx.ch> wrote:On 08/07/2012 07:59 AM, Jos=E9 Armando Garc=EDa Sancio wrote:On Sun, Aug 5, 2012 at 2:32 PM, Kapps<opantm2+spam gmail.com> wrote=Just incase it is not clear. I have zero interest in changing or promoting that we change the signature of the std.algorithm module. This is more of a selfish module design exercise on my part. Thanks, -JoseInteresting. I can't speak for the GC and allocation you mention since I never tried to implement this myself but I should point out that C++ STL's algorithm "module" (transform, for_each, etc) works this way. Having said that, if D can't infer the type of lambda parameters (which I thought the current version of D could) and create a function/delegate based on the body then this is a no go. Thanks for you insight. -JoseOn Sunday, 5 August 2012 at 14:32:50 UTC, Adam D. Ruppe wrote:On Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:
Aug 07 2012
On Mon, Aug 6, 2012 at 11:59 PM, Jos=E9 Armando Garc=EDa Sancio < jsancio gmail.com> wrote:On Sun, Aug 5, 2012 at 2:32 PM, Kapps <opantm2+spam gmail.com> wrote:meOn Sunday, 5 August 2012 at 14:32:50 UTC, Adam D. Ruppe wrote:On Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:I'd be very surprised if all that many people compile with -property.Indeed. Sometimes I try it just to see what happens, and always the sa=eresults: it doesn't solve problems and complains about code. Some examples of things that break: import std.algorithm; foreach(i; [1,2,3].map!"a+1") { } prophate.d(5): Error: not a property [1,2,3].map!("a+1") Of course, this is relatively new, using ufcs in 2.059, so the breakag=yprobably isn't too bad, but I'm not the only one who writes it this wa=-()especiallyI've seen a number of reddit and newsgroup comments do this too,getwhen chaining it. [snip]I completely agree, particularl with the UFCS part. UFCS is designed torid of the horrible mess of (), and now we want to arbitrarily force a =There was a pull to switch std.algorithm over to the new lambda syntax (by me). It caused the dmd unit tests to fail though. There is also an issue with intermodule visibility of nested structs that popped up and prevented the every function from being switched over. I should probably recreate the pull request so one of the compiler guys can take a look. BAanyways? Seems like it defeats the purpose. To me, when comparing range.filter!"a > 2".map!"a*a".countUntil(3) to range.filter!"a > 2"().map!"a*a"().countUntil(3) Those extra paranthesis just don't do anything, they don't give extra meaning, they don't accomplish anything useful but distract from theactualexpression.Just a small comment. I have been following this thread a little and was somewhat surprise that the argument against enforcing parenthesis on non-properties is that a call like [1,2,3].map!"a+1" would look ugly as [1,2,3].map!"a+1"(). To me that is a issue of the std.algorithm module and not so much of the language. Personally I am not a huge fan of using strings as a way to pass a function into a high-order function. I suspect that this string stuff became popular because D didn't have lambda declarations and type inference when the module was designed and implemented. I wonder if the module signatures would look different if you designed it to use the current features of D. To be honest, when first saw 'some_array.map!"a+1"()' a few years back when I first learned about D my knee jerk reaction was: "from where in the world is 'a' coming from?". I remember I had to read std/algorithm.d and whatever module implements unary "string" functions to figure out what was going on. Anyways, I digress. Part of me looks forward to the day that I can use D reliably another part of my wants to just wait for Rust to hopefully get it "right". Thanks, -Jose
Aug 06 2012
On Tuesday, 7 August 2012 at 06:31:46 UTC, Brad Anderson wrote:On Mon, Aug 6, 2012 at 11:59 PM, José Armando GarcÃa Sancio < jsancio gmail.com> wrote:[snip]https://github.com/D-Programming-Language/phobos/pull/744Personally I am not a huge fan of using strings as a way to pass a function into a high-order function. I suspect that this string stuff became popular because D didn't have lambda declarations and type inference when the module was designed and implemented. I wonder if the module signatures would look different if you designed it to use the current features of D. To be honest, when first saw 'some_array.map!"a+1"()' a few years back when I first learned about D my knee jerk reaction was: "from where in the world is 'a' coming from?". I remember I had to read std/algorithm.d and whatever module implements unary "string" functions to figure out what was going on. Anyways, I digress. Part of me looks forward to the day that I can use D reliably another part of my wants to just wait for Rust to hopefully get it "right". Thanks, -JoseThere was a pull to switch std.algorithm over to the new lambda syntax (by me). It caused the dmd unit tests to fail though. There is also an issue with intermodule visibility of nested structs that popped up and prevented the every function from being switched over. I should probably recreate the pull request so one of the compiler guys can take a look. BA
Aug 07 2012
On Mon, Aug 6, 2012 at 11:31 PM, Brad Anderson <eco gnuk.net> wrote:On Mon, Aug 6, 2012 at 11:59 PM, Jos=E9 Armando Garc=EDa Sancio <jsancio gmail.com> wrote:.On Sun, Aug 5, 2012 at 2:32 PM, Kapps <opantm2+spam gmail.com> wrote:On Sunday, 5 August 2012 at 14:32:50 UTC, Adam D. Ruppe wrote:On Sunday, 5 August 2012 at 04:12:23 UTC, Jonathan M Davis wrote:I'd be very surprised if all that many people compile with -property=geIndeed. Sometimes I try it just to see what happens, and always the same results: it doesn't solve problems and complains about code. Some examples of things that break: import std.algorithm; foreach(i; [1,2,3].map!"a+1") { } prophate.d(5): Error: not a property [1,2,3].map!("a+1") Of course, this is relatively new, using ufcs in 2.059, so the breaka=ayprobably isn't too bad, but I'm not the only one who writes it this w=o- I've seen a number of reddit and newsgroup comments do this too, especially when chaining it. [snip]I completely agree, particularl with the UFCS part. UFCS is designed t=yThere was a pull to switch std.algorithm over to the new lambda syntax (b=get rid of the horrible mess of (), and now we want to arbitrarily force a () anyways? Seems like it defeats the purpose. To me, when comparing range.filter!"a > 2".map!"a*a".countUntil(3) to range.filter!"a > 2"().map!"a*a"().countUntil(3) Those extra paranthesis just don't do anything, they don't give extra meaning, they don't accomplish anything useful but distract from the actual expression.Just a small comment. I have been following this thread a little and was somewhat surprise that the argument against enforcing parenthesis on non-properties is that a call like [1,2,3].map!"a+1" would look ugly as [1,2,3].map!"a+1"(). To me that is a issue of the std.algorithm module and not so much of the language. Personally I am not a huge fan of using strings as a way to pass a function into a high-order function. I suspect that this string stuff became popular because D didn't have lambda declarations and type inference when the module was designed and implemented. I wonder if the module signatures would look different if you designed it to use the current features of D. To be honest, when first saw 'some_array.map!"a+1"()' a few years back when I first learned about D my knee jerk reaction was: "from where in the world is 'a' coming from?". I remember I had to read std/algorithm.d and whatever module implements unary "string" functions to figure out what was going on. Anyways, I digress. Part of me looks forward to the day that I can use D reliably another part of my wants to just wait for Rust to hopefully get it "right". Thanks, -Joseme). It caused the dmd unit tests to fail though. There is also an issu=ewith intermodule visibility of nested structs that popped up and prevente=dthe every function from being switched over. I should probably recreate =thepull request so one of the compiler guys can take a look. BAWow. That would be nice! I would like to see such a change though I assume that such a change would break a lot of code. No?
Aug 06 2012
On Sunday, August 05, 2012 04:17:13 bearophile wrote:Adam D. Ruppe:I wholeheartedly agree, but it's a divisive subject. Some of us feel very strongly that functions not marked with property should require parens, and others feel very strongly that they should be optional. - Jonathan M DavisI should add: if a function is not marked property, it should not change at all: it should be callable with and without parens,I think I'd like functions not marked with property to require the ().
Aug 04 2012
Le 04/08/2012 19:13, Adam D. Ruppe a écrit :So the existing -property in the compiler as absolutely worthless. It is semantically wrong. property void function() func() { return { assert(0, "success"); }; } void main() { func(); // should assert 0 success, doesn't auto dele = &func; dele(); // should assert 0 success, doesn't } Does the same thing with and without -property, and it is wrong both ways.Note that something more is wrong. func(); // Do something auto dele = &func; dele(); // Expected to do the same thing, even if we passed throw & in the middle. The whole thing is f***ed up IMO. (and I've made some work on SDC on the subject, the & is really convoluted to implement).When we look back at the test code: func(); // should assert 0 success, doesn't auto dele = &func;auto dele = func;These two lines both currently refer to the getter function itself. We want the getter function to be completely invisible to all other code. This should be rewritten kinda like if this were in the code: #define func (func()) This would also fix things like func += 10; if func returned a ref int. What SHOULD happen: callexp.d(18): Error: function expected before (), not func() of type int callexp.d(20): Error: function expected before (), not func() of type int+1Or something like that. Since property ref int func() is supposed to be interchangable for a plain int func;, no special enforcement of property syntax is required: it is illegal to call an int like a function, and func is an int as far as the outside world is concerned.+11) Do we all agree that properties should be interchangeable for plain variables of the return value's type in all contexts? That is, if I can make this work with a pull request, is that going to be acceptable?Except for that & thing, 100% agreed.
Aug 04 2012
On Saturday, 4 August 2012 at 17:35:03 UTC, deadalnix wrote:Except for that & thing, 100% agreed.I think you're right about that too...
Aug 04 2012
I think I've cracked the getters... I opened expression.c in DMD and surfed to line 2940 or so. Looks like this: { error("forward reference to %s", toChars()); return new ErrorExp(); } return new VarExp(loc, f, hasOverloads); The function is Expression *DsymbolExp::semantic(Scope *sc) Instead of return new VarExp, I made it: VarExp* varexp = new VarExp(loc, f, hasOverloads); TypeFunction* tf = (TypeFunction *)f->type; if(tf->isproperty) { CallExp* ce = new CallExp(loc, varexp); ce->semantic(sc); return ce; } else { return varexp; } And now my test functions work... the question is, did I break a lot of other stuff? idk, but this is a big move forward.
Aug 04 2012
On 2012-08-04 19:13, Adam D. Ruppe wrote:This would also fix things like func += 10; if func returned a ref int. === property ref int func() { static int a; return a; } void main() { // all of these should work; func should look just like an int to the outside world int a = func; int* b = &func; func += 10; } === callexp.d(19): Error: cannot implicitly convert expression (& func) of type int function() property ref to int*I don't think that's correct behavior. I think the correct behavior would be to have a property rewrite, something like this: foo += 10; Is rewritten as: auto __tmp = foo; foo = __tmp + 10;Or something like that. Since property ref int func() is supposed to be interchangable for a plain int func;, no special enforcement of property syntax is required: it is illegal to call an int like a function, and func is an int as far as the outside world is concerned. This is how the property syntax is enforced: by the compiler's existing type checks. No additional code should be there to check syntax. So, I have two questions: 1) Do we all agree that properties should be interchangeable for plain variables of the return value's type in all contexts? That is, if I can make this work with a pull request, is that going to be acceptable?I think that you should always be able to replace a variable with a property. The other way around I'm not so sure. The problem is with methods in classes. Since a method will be virtual by default you can't just replace a property with a variable. That could potentially break subclasses that override the property. -- /Jacob Carlborg
Aug 04 2012
On 2012-08-04 21:08, Jacob Carlborg wrote:I think that you should always be able to replace a variable with a property. The other way around I'm not so sure. The problem is with methods in classes. Since a method will be virtual by default you can't just replace a property with a variable. That could potentially break subclasses that override the property.I wouldn't actually mind a way to do this, perhaps something like this: class Foo { property int bar: } Would be the same as: class Foo { private int bar_: property int bar () { return bar_; } property int bar (int value) { return bar_ = value; } } -- /Jacob Carlborg
Aug 04 2012
On Saturday, August 04, 2012 21:11:47 Jacob Carlborg wrote:On 2012-08-04 21:08, Jacob Carlborg wrote:That would be kind of cool, though I would have suggested that putting property on a variable would make it so that you couldn't do anything with it that you couldn't do with a property (e.g. taking the address of a variable will break when it's switched to a property, and property on the variable could prevent that). But maybe your proposal is better - though I'm not sure how much I'd end up using it, because if you wanted to actually use the member variable, you'd get into naming issues. You proposed bar_ here, but I'd have gone with _bar, whereas some would have suggested m_bar, and regardless, there's no way to indicate the name with this syntax, so you'd have to either just know how the compiler names such variables or statically disallow using the property through anything other than the proprty functions. And if all the property does is get and set with _nothing_ else, then how is that any better than a public member variable, assuming that switching between a variable and a property is seemless like it's supposed to be? So, I think that I'd still prefer the approach of making it so that marking variables property makes it so that you can only use them in ways that you can use a property function, since it gives you the same result without needing to actually create any functions or come up with naming schemes for implicit member variables or whatnot. - Jonathan M DavisI think that you should always be able to replace a variable with a property. The other way around I'm not so sure. The problem is with methods in classes. Since a method will be virtual by default you can't just replace a property with a variable. That could potentially break subclasses that override the property.I wouldn't actually mind a way to do this, perhaps something like this: class Foo { property int bar: } Would be the same as: class Foo { private int bar_: property int bar () { return bar_; } property int bar (int value) { return bar_ = value; } }1
Aug 04 2012
On 2012-08-04 21:28, Jonathan M Davis wrote:That would be kind of cool, though I would have suggested that putting property on a variable would make it so that you couldn't do anything with it that you couldn't do with a property (e.g. taking the address of a variable will break when it's switched to a property, and property on the variable could prevent that). But maybe your proposal is better - though I'm not sure how much I'd end up using it, because if you wanted to actually use the member variable, you'd get into naming issues. You proposed bar_ here, but I'd have gone with _bar, whereas some would have suggested m_bar, and regardless, there's no way to indicate the name with this syntax, so you'd have to either just know how the compiler names such variables or statically disallow using the property through anything other than the proprty functions. And if all the property does is get and set with _nothing_ else, then how is that any better than a public member variable, assuming that switching between a variable and a property is seemless like it's supposed to be? So, I think that I'd still prefer the approach of making it so that marking variables property makes it so that you can only use them in ways that you can use a property function, since it gives you the same result without needing to actually create any functions or come up with naming schemes for implicit member variables or whatnot.I see two reasons: 1. The generated methods will be virtual 2. I'm thinking that it would be possible to override either the getter or setter. Meaning you would get one for free class Foo { property int bar: property int bar (int value) { validate(value); return bar_ = value; } } In the above code, only a getter will be generated. About the name of generate instance variable, we could add syntax making it possible to change the name: class Foo { property(name=m_bar) int bar: } -- /Jacob Carlborg
Aug 05 2012
On 2012-08-04 21:28, Jonathan M Davis wrote:That would be kind of cool, though I would have suggested that putting property on a variable would make it so that you couldn't do anything with it that you couldn't do with a property (e.g. taking the address of a variable will break when it's switched to a property, and property on the variable could prevent that). But maybe your proposal is better - though I'm not sure how much I'd end up using it, because if you wanted to actually use the member variable, you'd get into naming issues. You proposed bar_ here, but I'd have gone with _bar, whereas some would have suggested m_bar, and regardless, there's no way to indicate the name with this syntax, so you'd have to either just know how the compiler names such variables or statically disallow using the property through anything other than the proprty functions. And if all the property does is get and set with _nothing_ else, then how is that any better than a public member variable, assuming that switching between a variable and a property is seemless like it's supposed to be? So, I think that I'd still prefer the approach of making it so that marking variables property makes it so that you can only use them in ways that you can use a property function, since it gives you the same result without needing to actually create any functions or come up with naming schemes for implicit member variables or whatnot.A few more reasons: 3. Binary compatibility 4. Read only fields. I quite often want to have read only fields and basically the only way to that is by using a getter property method. In D1 I could sometimes avoid this by declaring the instance variable as const, but that doesn't work in D2 -- /Jacob Carlborg
Aug 05 2012
On Saturday, 4 August 2012 at 19:08:58 UTC, Jacob Carlborg wrote:I don't think that's correct behavior. I think the correct behavior would be to have a property rewrite, something like this:Yes, I agree in general, but if a getter returns a ref, you should be able to write to it... I think anyway, but it is an lvalue anyway. What I just added to my hacked compiler is this: ===== else if(e1->op == TOKcall) { // for property work, if there is a setter, we should revert to the older style // handling. If not, we can keep it as a CallExp CallExp* ce = (CallExp*) e1; Expression* temp_e1 = ce->e1; if((temp_e1->op == TOKvar && temp_e1->type->toBasetype()->ty == Tfunction)) { // this is potentially a setter.... but not necessarily fd = ((VarExp *)temp_e1)->var->isFuncDeclaration(); ethis = NULL; assert(fd); FuncDeclaration *f = fd; Expressions a; a.push(e2); fd = f->overloadResolve(loc, ethis, &a, 1); if (fd && fd->type) { e1 = temp_e1; goto Lsetter; } } ===== To line 10320 - right above where the old style setter code is. It isn't perfect yet because it doesn't ensure we are dealing with a property, but it is closer. The idea is: if we have a setter function, we should try to use it, just like dmd does today. If not, we'll leave the call there and see what happens. (If it returns ref, it will work, otherwise, it errors saying the property is not an lvalue.) So far this is passing my simple test for assignment, but not yet the op assigns. int a; property int funcprop() { return a; } // setter property int funcprop(int s) { return a = s + 10; } funcprop = 10; // works, funcprop == 20 now funcprop += 10; // currently does NOT workIs rewritten as: auto __tmp = foo; foo = __tmp + 10;I think this is exactly what we have to do to work in all cases. I'm gonna take a look at it next... then it is time to test this patch and with a little luck, we can finally put the property debate to rest.I think that you should always be able to replace a variable with a property. The other way around I'm not so sure. The problem is with methods in classes. Since a method will be virtual by default you can't just replace a property with a variable. That could potentially break subclasses that override the property.True. I think all the other uses should just work though.
Aug 04 2012
On 2012-08-04 21:25, Adam D. Ruppe wrote:Yes, I agree in general, but if a getter returns a ref, you should be able to write to it... I think anyway, but it is an lvalue anyway.Or we could disallow getters returning by reference.What I just added to my hacked compiler is this: ===== else if(e1->op == TOKcall) { // for property work, if there is a setter, we should revert to the older style // handling. If not, we can keep it as a CallExp CallExp* ce = (CallExp*) e1; Expression* temp_e1 = ce->e1; if((temp_e1->op == TOKvar && temp_e1->type->toBasetype()->ty == Tfunction)) { // this is potentially a setter.... but not necessarily fd = ((VarExp *)temp_e1)->var->isFuncDeclaration(); ethis = NULL; assert(fd); FuncDeclaration *f = fd; Expressions a; a.push(e2); fd = f->overloadResolve(loc, ethis, &a, 1); if (fd && fd->type) { e1 = temp_e1; goto Lsetter; } } ===== To line 10320 - right above where the old style setter code is. It isn't perfect yet because it doesn't ensure we are dealing with a property, but it is closer. The idea is: if we have a setter function, we should try to use it, just like dmd does today. If not, we'll leave the call there and see what happens. (If it returns ref, it will work, otherwise, it errors saying the property is not an lvalue.) So far this is passing my simple test for assignment, but not yet the op assigns. int a; property int funcprop() { return a; } // setter property int funcprop(int s) { return a = s + 10; } funcprop = 10; // works, funcprop == 20 nowDoesn't this already work?True. I think all the other uses should just work though.Yes. Have a look at this for a workaround: http://forum.dlang.org/thread/gknbobkfhmfszshqenng forum.dlang.org#post-jvjs5j:248ov:241:40digitalmars.com -- /Jacob Carlborg
Aug 05 2012
On Sunday, 5 August 2012 at 12:14:41 UTC, Jacob Carlborg wrote:Doesn't this already work?Yes, but it is in my test file to make sure it still works, without any additional pointless function calls. Right now the basics all work, but member template function that happen to be getters can break - this is the assertion failure I saw last night. I think my fix to implicit this calls broke it, ugh. And then I need to check the operator overloading.Yes. Have a look at this for a workaround:I saw it, but one step at a time for now...
Aug 05 2012
On 2012-08-05 15:51, Adam D. Ruppe wrote:And then I need to check the operator overloading.I see.I saw it, but one step at a time for now...Hehe, yes, of course. No pressure :) -- /Jacob Carlborg
Aug 05 2012
On Saturday, 4 August 2012 at 19:08:58 UTC, Jacob Carlborg wrote:foo += 10; Is rewritten as: auto __tmp = foo; foo = __tmp + 10;I did this and now I think this thing is almost done === int a; property int funcprop() { writeln("calling the getter and getting ", a); return a; } property int funcprop(int s) { writeln("calling the setter with ", s); return a = s; } void main() { funcprop = 40; funcprop += 10; } === run: calling the setter with 40 calling the getter and getting 40 calling the setter with 50 Looks right to me. Now I just have to check for the property tag on some of these rewrites and then clean it up and test for a pull request.
Aug 04 2012
OK, I just compiled one of my work apps with the hacked up dmd. It caught me using properties as functions in a few places, which I had to fix by removing the parenthesis from some places, and the property from a few other places (the functions weren't really properties, I just marked them as such for the syntax...) But hey if it compiles this thing with only a few, very minor changes, I think we're in business. We should be able to close those gazillion ancient property bugs once and for all, with minimal code breakage. I'll push it up to github later tonight for additional review.
Aug 04 2012
On Saturday, August 04, 2012 23:35:47 Adam D. Ruppe wrote:OK, I just compiled one of my work apps with the hacked up dmd. It caught me using properties as functions in a few places, which I had to fix by removing the parenthesis from some places, and the property from a few other places (the functions weren't really properties, I just marked them as such for the syntax...) But hey if it compiles this thing with only a few, very minor changes, I think we're in business. We should be able to close those gazillion ancient property bugs once and for all, with minimal code breakage. I'll push it up to github later tonight for additional review.If you can get properties working properly that quickly, that's fantastic. - Jonathan M Davis
Aug 04 2012
On Saturday, 4 August 2012 at 21:47:44 UTC, Jonathan M Davis wrote:If you can get properties working properly that quickly, that's fantastic.I did just realize I missed something.... but I'm convinced the problem before is we were going at it at the wrong time, doing the property rewrites too late, meaning it had to be duplicated a lot and was hard to check fully. My approach here is to rewrite the properties almost immediately into function calls instead of leaving them as just function references until the last minute. (And then in a couple places, they need to be turned back into references so you can look up the setter, but I say better to only need two special cases than twenty.)
Aug 04 2012
On 2012-08-04 23:35, Adam D. Ruppe wrote:OK, I just compiled one of my work apps with the hacked up dmd. It caught me using properties as functions in a few places, which I had to fix by removing the parenthesis from some places, and the property from a few other places (the functions weren't really properties, I just marked them as such for the syntax...) But hey if it compiles this thing with only a few, very minor changes, I think we're in business. We should be able to close those gazillion ancient property bugs once and for all, with minimal code breakage. I'll push it up to github later tonight for additional review.Awesome :) -- /Jacob Carlborg
Aug 05 2012
On 2012-08-04 22:53, Adam D. Ruppe wrote:I did this and now I think this thing is almost done === int a; property int funcprop() { writeln("calling the getter and getting ", a); return a; } property int funcprop(int s) { writeln("calling the setter with ", s); return a = s; } void main() { funcprop = 40; funcprop += 10; } === run: calling the setter with 40 calling the getter and getting 40 calling the setter with 50 Looks right to me. Now I just have to check for the property tag on some of these rewrites and then clean it up and test for a pull request.BTW, how will this interact with overloaded operators and similar more advanced features? Say that I have a getter that returns a struct/class which overloads the += operator. -- /Jacob Carlborg
Aug 05 2012
On Sunday, 5 August 2012 at 12:18:52 UTC, Jacob Carlborg wrote:BTW, how will this interact with overloaded operators and similar more advanced features? Say that I have a getter that returns a struct/class which overloads the += operator.I'm not sure yet... stuff like this is one reason why it didn't work out right last night. (I have it working in about 90% of cases, but it is interaction with those last advanced features that always keep the D bugzilla active.) With the rewrite right now, it does getter -> opOpAssign -> setter, which isn't quite right...
Aug 05 2012
On Saturday, 4 August 2012 at 20:53:53 UTC, Adam D. Ruppe wrote:On Saturday, 4 August 2012 at 19:08:58 UTC, Jacob Carlborg wrote:It would be cool http://forum.dlang.org/thread/xcbweciovapinaicxgbn forum.dlang.org and http://d.puremagic.com/issues/show_bug.cgi?id=8006foo += 10; Is rewritten as: auto __tmp = foo; foo = __tmp + 10;I did this and now I think this thing is almost done === int a; property int funcprop() { writeln("calling the getter and getting ", a); return a; } property int funcprop(int s) { writeln("calling the setter with ", s); return a = s; } void main() { funcprop = 40; funcprop += 10; } === run: calling the setter with 40 calling the getter and getting 40 calling the setter with 50 Looks right to me. Now I just have to check for the property tag on some of these rewrites and then clean it up and test for a pull request.
Aug 06 2012
There was a very long discussion on this before that lead me to write this: http://www.prowiki.org/wiki4d/wiki.cgi?DocComments/Property I should draw attention to the tables near the bottom. It is really too bad that variables in D allow the taking of addresses by default. If things were non-addressable by default, then they could always be promoted to properly-implemented properties. Addressabilitiy could be added explicitly by authors that are confident that they will never need to turn their public fields into properties. Too late for all of that now. I tried to get DMD to do property rewriting in a vaguely general sense. I think it's still very worthwhile to attempt it. It didn't work for me because this was in the days of SVN and I tend to get my free time in 1-3 hour chunks. By the time I had more free time I'd spend it all merging/updating my code to the latest revision. I also spent a lot of my time learning how DMD's semantic analysis works. It's pretty tangled (sorry, Walter). So yeah, I didn't get to spend much time actually working on the property rewrite due to confusion and backtracking. I realized that while I really wanted the feature, I wasn't having fun, nor did I have any free time to program at all. (Implementing the recursive logic for such a rewrite is really easy! Dealing with DMDs architectural corner cases... (was) not so easy.) It'd probably be good to be minimal about it. We might not be able to do property rewriting in a %100 awesome way without breaking backwards compatibility. It'll still be worth it to get the property rewriting that doesn't break backwards compatibility. Example: struct Bar { private Foo m_a; property Foo a() { return m_a; } } struct Foo { private int qux; Foo opBinary(string op : "+")(Foo other) { Foo result; result.qux = this.qux + other.qux return result; } } void main() { Bar a; Foo b; // Error: attempt to write to a non-writable property a.a b = a.a + b; } To make the property rewrite bulletproof, we have to assume that (a.f + b) will modify a.a because a.a.opBinary!("+") is non-const. We should then compile-time-error because the property a.a does not have a setter. However, in current code, this would not give a compile-time error. Instead it would just work, because the caller and callee implicitly assume that the opBinary call is const, even if it's not marked as such. There is probably a significant amount of code that would no longer compile because of this. The answer would be to mark all such functions as const, but I'm not sure that Walter & Co would be fine with that. It's OK though. If Walter & Co don't want to break various calls to non-const functions at the end of expressions containing properties, then we can let that slide and only focus on the more likely cases like using += on a property field that returns a value type like an int (array.length += 1 is the classic case, with its own special-cased solution and everything). It'd be extremely useful and possibly remove a lot of potential sources of bugs/headaches. Anyhow, that's a lot of my background info on this subject. I do hope someone else tackles this. They will probably be more successful than I. If not, I might still try it someday if the pull request might get accepted.
Aug 04 2012
On Saturday, 4 August 2012 at 22:19:17 UTC, Chad J wrote:There was a very long discussion on this before that lead me to write this:I'll have to read it... my thing right now works, as far as I can tell, perfectly on free function properties. But member properties are different and I haven't gotten them to work without massive breakage yet. (I forgot all about them until just an hour ago.) For some reason, rewriting the members breaks random things like opCall too. The good is the free function change doesn't actually break anything... the bad is member properties are the more interesting ones and if they don't work, this isn't cool.... But it doesn't look like I'll be done with this today after all :( I still have a lot of stuff I was supposed to be doing today!
Aug 04 2012
On 08/04/2012 06:50 PM, Adam D. Ruppe wrote:On Saturday, 4 August 2012 at 22:19:17 UTC, Chad J wrote:Best of luck, and thank you for thinking about this and getting the ball rolling!There was a very long discussion on this before that lead me to write this:I'll have to read it... my thing right now works, as far as I can tell, perfectly on free function properties. But member properties are different and I haven't gotten them to work without massive breakage yet. (I forgot all about them until just an hour ago.) For some reason, rewriting the members breaks random things like opCall too. The good is the free function change doesn't actually break anything... the bad is member properties are the more interesting ones and if they don't work, this isn't cool.... But it doesn't look like I'll be done with this today after all :( I still have a lot of stuff I was supposed to be doing today!
Aug 04 2012
On Monday, August 06, 2012 23:44:21 Jos=C3=A9 Armando Garc=C3=ADa Sanci= o wrote:Wow. That would be nice! I would like to see such a change though I assume that such a change would break a lot of code. No?No. Both the string syntax and the new lambda syntax are here to stay. = Both=20 work now, and both will continue to work. The pull request was switchin= g over=20 most of the examples, not changing the functionality. - Jonathan M Davis
Aug 06 2012