digitalmars.D - DIP23 draft: Fixing properties redux
- Andrei Alexandrescu (23/23) Feb 03 2013 Walter and I have had a discussion on how to finalize properties.
- Gor Gyolchanyan (29/52) Feb 03 2013 I always wondered if there's a good way to incorporate opOpAssign family...
- Gor Gyolchanyan (6/71) Feb 03 2013 Sorry, forgot the @property.
- deadalnix (9/17) Feb 03 2013 I don't understand.
- Jonathan M Davis (35/36) Feb 03 2013 Overall, it looks good. It sounds like it's basically arguing for fully
- deadalnix (5/14) Feb 03 2013 Couldn't an alias make it ?
- Andrei Alexandrescu (12/29) Feb 03 2013 First off, defining a top-level property ought indeed to have an air of
- David Nadlinger (8/10) Feb 03 2013 Here are some more test cases to think about:
- deadalnix (7/17) Feb 03 2013 I wanted to avoid the topic as it is basically solved for
- monarch_dodra (6/9) Feb 03 2013 Will we keep the optional -property (or similar) for those of us
- Dmitry Olshansky (5/15) Feb 03 2013 Using verbs for actions and nouns for querying data and not being
- Andrei Alexandrescu (7/17) Feb 03 2013 This is a judgment call as reasonable people may disagree on it. Walter
- monarch_dodra (6/27) Feb 03 2013 Thank you for the answers. I didn't follow all 500 posts in the
- Johannes Pfau (38/48) Feb 03 2013 "If a function returns a reference, then assignment through the
- Andrei Alexandrescu (38/74) Feb 03 2013 (As a note, this is the current behavior.)
- kenji hara (6/16) Feb 03 2013 I have thought about the problem, and filed an enhancement.
- Andrei Alexandrescu (3/21) Feb 03 2013 Now that an overhaul is on the table, that warrants a second look.
- Steven Schveighoffer (21/70) Feb 03 2013 This sounds good. It might be a bit confusing, but nice in the fact tha...
- Steven Schveighoffer (8/14) Feb 03 2013 Hm... I actually am changing my mind on this, you should be able to do:
- Andrei Alexandrescu (10/21) Feb 03 2013 Yah, this is a good rule of thumb for generic code.
- Johannes Pfau (15/35) Feb 03 2013 I didn't think of it as a call without parentheses but it indeed makes
- Andrei Alexandrescu (5/19) Feb 03 2013 For now I disallow 0-parameter top level properties. This is a good
- Steven Schveighoffer (23/31) Feb 03 2013 I think Johannes' argument applies to non-global properties.
- Timon Gehr (6/16) Feb 03 2013 That is horrible! The entire language construct is necessarily a bit of
- Walter Bright (1/1) Feb 03 2013 I'm glad Johannes brought up all these cases. They all need to go into t...
- Jacob Carlborg (4/9) Feb 04 2013 Is that part of the proposal or not?
- Jonathan M Davis (4/14) Feb 04 2013 It is now, though I don't think that it was intially. It's in the "Apply...
- Chad Joan (17/35) Feb 04 2013 I disagree with this. I think that allowing address-of on getters is
- Steven Schveighoffer (34/36) Feb 03 2013 I agree with everything in this. This looks exactly like what I wanted ...
- kenji hara (4/7) Feb 03 2013 [snip]
- Andrei Alexandrescu (9/16) Feb 03 2013 Then we can't make this work:
- Steven Schveighoffer (7/26) Feb 03 2013 ref T front(T[] array) { return array[0]; }
- Timon Gehr (6/35) Feb 03 2013 different unittest:
- Steven Schveighoffer (4/40) Feb 03 2013 OK, so that is not good. I think the current DIP23 idea should be
- Steven Schveighoffer (8/16) Feb 03 2013 I thought of one other problem with this proposal. You can no longer ge...
- kenji hara (8/28) Feb 03 2013 On the contrary with you, I was read that we no longer get an address of
- Timon Gehr (2/17) Feb 03 2013 The DIP actually misses to address this case.
- Steven Schveighoffer (22/58) Feb 03 2013 You are right, it does not specify this, I was somewhat mistaken.
- deadalnix (5/8) Feb 03 2013 If you want a function, then just don't annotate with @property.
- Steven Schveighoffer (5/11) Feb 03 2013 That is not the point of properties. The point of properties is to have...
- TommiT (6/16) Feb 03 2013 That is not the point of properties. The point of setter and
- kenji hara (13/30) Feb 03 2013 [snip]
- Steven Schveighoffer (9/20) Feb 03 2013 That looks better than mine, it takes a bit to understand it :) It can ...
- Andrei Alexandrescu (4/6) Feb 03 2013 Yes, __traits is a nice hatch if we discover we find we can't do
- Timon Gehr (2/8) Feb 03 2013 __traits is a lot cleaner than assigning meaning to parentheses.
- Timon Gehr (3/22) Feb 03 2013 T delegate() f = &a.prop -> auto f = ()=>a.prop;
- Steven Schveighoffer (5/7) Feb 03 2013 I don't like this solution. You are creating a dummy delegate function,...
- Timon Gehr (2/9) Feb 03 2013 The spec could be updated to allow/mandate eta-reduction where applicabl...
- deadalnix (5/13) Feb 03 2013 Unless you escape the delegate, it should allocate on the heap.
- Artur Skawina (9/15) Feb 03 2013 Not really, it just needs to be specced properly. There's already a simi...
- deadalnix (3/7) Feb 03 2013 This isn't a problem.
- Andrei Alexandrescu (3/21) Feb 03 2013 In the proposal &a.b gets the delegate of a property.
- deadalnix (3/4) Feb 03 2013 :facepalm:
- Timon Gehr (2/6) Feb 03 2013 +1.
- Jacob Carlborg (6/8) Feb 03 2013 What about:
- Jonathan M Davis (8/18) Feb 03 2013 I take it that you didn't read the DIP. At the very beginning of its sec...
- Jacob Carlborg (4/10) Feb 03 2013 Right, I guess I missed that.
- Johannes Pfau (6/25) Feb 03 2013 There's a example on the page though which contradicts this:
- TommiT (7/15) Feb 03 2013 That example has nothing to do with properties. It's just:
- Johannes Pfau (6/26) Feb 03 2013 OK, but then 'In order to use the assignment operator "="
- Andrei Alexandrescu (4/29) Feb 03 2013 This introduces no contradiction. It's simple assignment to the result
- Andrei Alexandrescu (4/11) Feb 03 2013 No because writeln is not a property. For non-properties there's no
- Johannes Pfau (11/28) Feb 03 2013 Then this should be removed in the proposal:
- Andrei Alexandrescu (3/31) Feb 03 2013 No. That's not a lowering.
- kenji hara (121/123) Feb 03 2013 Awesome!!
- Andrei Alexandrescu (58/176) Feb 03 2013 Yah. There is still some inconsistency, but I think there's no way to be...
- Andrej Mitrovic (14/16) Feb 03 2013 I have an idea. The DIP says that @property cannot return a @property
- Andrei Alexandrescu (10/11) Feb 03 2013 [snip]
- Andrej Mitrovic (2/7) Feb 03 2013 So, thoughts on this?
- Timon Gehr (9/12) Feb 03 2013 Looks good. Two things:
- Andrei Alexandrescu (5/18) Feb 03 2013 I updated the doc to clarify that one-parameter properties are ALWAYS
- SomeDude (4/7) Feb 03 2013 Should we add also non ambiguous ? I think everyone should agree
- FG (12/13) Feb 03 2013 Very reasonable in the majority of the proposal.
- kenji hara (6/20) Feb 03 2013 Two arguments @property function would be declared only in module level,
- FG (4/8) Feb 03 2013 With such constraints two argument property functions are fine, as long ...
- Andrei Alexandrescu (4/17) Feb 03 2013 Two-argument @properties are always setters.
- TommiT (20/24) Feb 03 2013 What happens here?
- Steven Schveighoffer (7/30) Feb 03 2013 I would expect it to call S.prop, not the global prop. If not, that
- FG (6/24) Feb 03 2013 This is an interesting problem.
- Andrei Alexandrescu (3/26) Feb 03 2013 The member is chosen.
- TommiT (45/78) Feb 03 2013 What happens in these examples?
- Andrei Alexandrescu (4/22) Feb 03 2013 This is a matter of visibility. The presence of a member precludes any
- TommiT (21/24) Feb 03 2013 Just to be perfectly clear, it must be that this wouldn't compile
- Andrei Alexandrescu (3/26) Feb 03 2013 Nope.
- Steven Schveighoffer (7/37) Feb 03 2013 He means "Nope it wouldn't compile" in case that was confusing ;)
- eles (15/25) Feb 03 2013 This syntax sugar only helps in chained-UFCS calling. Why
- Timon Gehr (8/21) Feb 03 2013 Nope.
- Timon Gehr (14/18) Feb 03 2013 (No, it is not.)
- H. S. Teoh (11/14) Feb 03 2013 [...]
- Andrei Alexandrescu (7/7) Feb 03 2013 On 2/3/13 3:16 AM, Andrei Alexandrescu wrote:
- H. S. Teoh (7/16) Feb 03 2013 [...]
- Jonathan M Davis (5/14) Feb 03 2013 Technically, the bit about having exactly one or exactly two parameters ...
- Jacob Carlborg (5/8) Feb 04 2013 I don't know if the text has been update since you read it but it says:
- David Nadlinger (19/20) Feb 03 2013 One does not, the strange special case for taking the address of
- David Nadlinger (5/15) Feb 03 2013 As another data point, Walter wrote a while ago himself: »I'm
- deadalnix (11/30) Feb 03 2013 The problem we are dealing with here isn't complex. It is made
- Timon Gehr (11/46) Feb 03 2013 It is not even made complex. It is quite obvious how things should work....
- David Nadlinger (13/50) Feb 03 2013 Not sure I'm following – you are arguing that the whole endeavor
- Andrei Alexandrescu (4/7) Feb 03 2013 I don't think it's a hack at all. Think it over, and compare it with the...
- David Nadlinger (8/16) Feb 03 2013 I've done that. What about *you* thinking it over? :P
- deadalnix (3/11) Feb 03 2013 Going from complete crap to bearable don't make bearable good.
- Timon Gehr (2/12) Feb 04 2013 In what way is this bearable?
- deadalnix (3/20) Feb 04 2013 The proposal is a big improvement over current behavior. Still it
- Timon Gehr (4/10) Feb 04 2013 I am intimately familiar with today's language semantics as I am writing...
- Andrei Alexandrescu (3/11) Feb 04 2013 I think it's because it's a matter in which reasonable people may disagr...
- Andrej Mitrovic (6/7) Feb 04 2013 Well, Walter seemed to agree with us before:
- deadalnix (4/17) Feb 03 2013 My point is that we try to pack fundamentally different concept
- Andrei Alexandrescu (9/25) Feb 03 2013 Andrej's proposal is nice, but I think you're wrong about this. We're
- David Nadlinger (8/21) Feb 03 2013 Then I'm eager to hear your explanation. Parentheses in an
- David Nadlinger (30/37) Feb 03 2013 Actually, let me illustrate this point a bit further, sorry for
- BLM768 (5/14) Feb 03 2013 I like this solution; it follows the Principle of Least Surprise
- Andrei Alexandrescu (4/19) Feb 03 2013 This is a good point, and __traits make all possible syntactic confusion...
- Jonathan M Davis (22/66) Feb 03 2013 mean
- Andrei Alexandrescu (8/10) Feb 03 2013 I think there's some misunderstanding here. Parens change the nature of
- deadalnix (4/14) Feb 03 2013 Weird behaviors of C++ are a very good reason to have D in the
- Timon Gehr (22/32) Feb 04 2013 In D? No way.
- Andrei Alexandrescu (18/43) Feb 03 2013 Well this is going to sound bad, but you either use reason or intuition....
- kenji hara (20/31) Feb 03 2013 letely different
- Andrei Alexandrescu (15/31) Feb 04 2013 Couldn't AddressOf use "&(" + exp + ")"?
- Timon Gehr (14/29) Feb 04 2013 No! &fun and &(fun) are the same thing. Functions that get their address...
- deadalnix (9/35) Feb 04 2013 Scala don't really agree. fun is the function pointer. It is
- Timon Gehr (16/51) Feb 04 2013 Of course Scala agrees.
- Andrei Alexandrescu (13/28) Feb 04 2013 The problem with (3) is that it creates a rule that gives different
- kenji hara (10/22) Feb 04 2013 Yes. It's enough. I wanted to explain that "we should treat
- Timon Gehr (5/28) Feb 04 2013 It is not an interesting point. It is not necessary anyway.
- kenji hara (11/16) Feb 04 2013 Because, "property" is one of D-specific feature.
- Timon Gehr (6/21) Feb 04 2013 Property symbols are not to be treated like function symbols
- kenji hara (5/39) Feb 04 2013 I have thought in long term that, in D, "proerty" is just a syntactic
- Andrej Mitrovic (11/16) Feb 04 2013 Fantastic, more special casing. I don't think you guys realize what a
- Dmitry Olshansky (5/12) Feb 04 2013 Unary & is not overloadable, precisely due to confusing mess it can
- Andrej Mitrovic (5/7) Feb 04 2013 Right I overlooked that, but this new rule will introduce a confusing
- kenji hara (13/31) Feb 04 2013 Address operator cannot be overloaded.
- Walter Bright (9/19) Feb 04 2013 The only time it is valid to take the address of a function's return val...
- Steven Schveighoffer (5/28) Feb 05 2013 I'd agree with you if we could have ref variables. In some cases, takin...
- Andrei Alexandrescu (20/49) Feb 05 2013 Walter and I reviewed the discussion and had a long talk. We are very
- bearophile (5/7) Feb 05 2013 Maybe some people want to allocate many small class instances on
- Steven Schveighoffer (11/25) Feb 05 2013 What about structs that live on the heap? e.g. a struct element of an
- H. S. Teoh (7/22) Feb 05 2013 [...]
- Andrei Alexandrescu (4/23) Feb 05 2013 Yah, apparently that's not sufficient. We must make sure pointers don't
- Andrei Alexandrescu (6/32) Feb 05 2013 Yah, time to start enforcing it more seriously. But we want to ban some
- Steven Schveighoffer (7/16) Feb 05 2013 The mechanism to avoid it seems overly extravagant (and prone to low
- Andrei Alexandrescu (6/22) Feb 05 2013 As I said, there are various solutions. I wrote one that's reasonably
- Timon Gehr (2/5) Feb 05 2013 Well, that is completely unnecessary.
- Jonathan M Davis (6/8) Feb 05 2013 Goodness no. It's pointer arithmetic which is disallowed. Pointers thems...
- Steven Schveighoffer (12/23) Feb 05 2013 Well, it would seem setting all kinds of extra rules on ref (in addition...
- Jonathan M Davis (15/41) Feb 05 2013 That may end up happening, but the issues with ref may boil over into so...
- Steven Schveighoffer (36/41) Feb 05 2013 Back to the problem I stated, how does one do this:
- Andrei Alexandrescu (10/50) Feb 05 2013 You define the function in situ.
- Steven Schveighoffer (4/10) Feb 05 2013 I look forward to reading it.
- Timon Gehr (3/11) Feb 05 2013 Given a noticeable tendency of your latest design proposals, I guess it
- (3/17) Feb 05 2013 What is the noticeable tendency of my latest design proposals?
- Andrei Alexandrescu (3/22) Feb 05 2013 That was me on the misconfigured phone.
- Timon Gehr (2/23) Feb 05 2013 They were mostly about banning stuff.
- Steven Schveighoffer (6/11) Feb 05 2013 Thinking about this some more, would this be allowed:
- Andrei Alexandrescu (3/13) Feb 05 2013 We hope to be able to disallow it.
- Zach the Mystic (13/19) Feb 05 2013 I hope it at least considers my proposal with regard to 'out'
- Andrei Alexandrescu (5/24) Feb 05 2013 I'm sorry, I didn't know of that proposal. Generally we're aiming for
- Zach the Mystic (8/31) Feb 05 2013 It's not a new syntax, just new semantics. Also, the reason for
- Andrei Alexandrescu (20/46) Feb 05 2013 Just to make sure: this is about
- Zach the Mystic (5/27) Feb 05 2013 Okay. But I just want to be clear that you are saying what I am
- Andrei Alexandrescu (21/24) Feb 05 2013 Depends on how you look at it.
- Jonathan M Davis (23/30) Feb 05 2013 Another thing to consider is that it's fairly common for people to come ...
- Zach the Mystic (9/64) Feb 05 2013 Well, Jonathan M Davis, I had posted a second response to
- Zach the Mystic (46/69) Feb 05 2013 My proposal changes exactly one existing semantic, which is that
- TommiT (8/13) Feb 05 2013 Did you consider using Rust's idea of 'Named lifetimes' in order
- Andrei Alexandrescu (4/15) Feb 05 2013 Thanks, I'll give that a read. We're very careful at this point about
- Max Samukha (6/9) Feb 05 2013 Please, no.
- Simen Kjaeraas (11/20) Feb 05 2013 @system T* addressOf(T)(ref T obj)
- deadalnix (4/15) Feb 03 2013 Yes, that is why, ideally, you want to close the gap as much as
- monarch_dodra (15/38) Feb 03 2013 It was my understanding that once a function is declared a
- Andrei Alexandrescu (5/18) Feb 04 2013 Well I at least haven't forgotten. Generally in D we don't want to 100%
- Steven Schveighoffer (19/39) Feb 04 2013 Basically any time you have a use case for creating a delegate that
- Tove (5/9) Feb 04 2013 I was going to submit the same suggestion, but didn't find time
- Andrei Alexandrescu (5/8) Feb 04 2013 That's an interesting idea. I'm a bit weary about it though. At least
- Steven Schveighoffer (8/16) Feb 05 2013 Did you mean wary?
- deadalnix (3/5) Feb 04 2013 The address taking of ?
- Andrej Mitrovic (46/47) Feb 04 2013 The problem is you cannot replace a field with a @property function
- kenji hara (11/51) Feb 04 2013 As an essential question, how often occurs rewriting fields to property?
- ixid (4/10) Feb 05 2013 As a beginner D user this seems like a far better solution, it's
- kenji hara (16/22) Feb 03 2013 the implicit this parameter if at all. The ONE-parameter version is ALWA...
- Timon Gehr (3/27) Feb 03 2013 Probably. (static essentially means module-level, but in a potentially
- TommiT (8/27) Feb 03 2013 I disagree. Static properties can be allowed because they're not
- Johannes Pfau (5/34) Feb 03 2013 "getter property of int type"
- Timon Gehr (3/32) Feb 04 2013 You are right.
- Andrei Alexandrescu (3/26) Feb 03 2013 Yes. No static properties.
- Jonathan M Davis (5/6) Feb 03 2013 So, properties such as Duration.max would simply be normal functions cal...
- Steven Schveighoffer (8/42) Feb 03 2013 Hm... can't see the reason why. Static properties play no part in UFCS ...
- Jonathan M Davis (31/32) Feb 03 2013 Another thing to consider would be to allow putting @property on a varia...
- TommiT (10/19) Feb 03 2013 If we consider a variable marked as @property as a variable whose
- Daniel Kozak (4/4) Feb 04 2013 From DIP:
- Chad Joan (40/63) Feb 04 2013 This would be a huge step up from the current properties. Thank you for...
- Rob T (23/48) Feb 04 2013 IMO the concept of emulating a field with a function is proving
- Andrei Alexandrescu (5/7) Feb 04 2013 An idea that departs considerably from the current status in D has a
- Jonathan M Davis (23/40) Feb 04 2013 There's also the issue a variable being able to be passed by ref, which ...
- Andrei Alexandrescu (4/6) Feb 04 2013 I think this is quite powerful. The way we can do this is by making
- Jonathan M Davis (18/23) Feb 04 2013 Yes. There are things that propery functions need to emulate from normal...
- Jacob Carlborg (6/12) Feb 05 2013 They need to be lowered to methods. Otherwise you cannot switch from a
- Chad Joan (8/15) Feb 04 2013 I agree with Jonathan.
- Andrei Alexandrescu (5/22) Feb 04 2013 The purpose is to replace members with properties, not to change one's
- Chad Joan (38/63) Feb 04 2013 Why not allow one to change their mind back and forth?
- Jonathan M Davis (31/55) Feb 04 2013 One of the main purposes generally given for having properties is so tha...
- Jacob Carlborg (5/34) Feb 05 2013 I fully agree. But they do need to be lowered to methods, see:
- Jacob Carlborg (7/36) Feb 05 2013 BTW, if it does get lowered to methods, do we want to be able to access
- Jonathan M Davis (10/12) Feb 05 2013 No, because the variable would presumably end up with a compiler-chosen ...
- Dmitry Olshansky (4/54) Feb 05 2013 I like the general idea. But to access variable one can still use
- Jacob Carlborg (5/8) Feb 05 2013 As long as accessing it via tupleof works it would be fine. A serializer...
- Chad Joan (79/94) Feb 04 2013 Related:
- Jacob Carlborg (6/10) Feb 05 2013 Why not? That will just require needless boilerplate code, wrappers just...
- Zach the Mystic (4/29) Feb 04 2013 http://forum.dlang.org/thread/ririagrqecshjljcdubd@forum.dlang.org
- Dmitry Olshansky (25/30) Feb 05 2013 This is the primary real-world proble to solve.
- Andrei Alexandrescu (9/19) Feb 05 2013 The problem with this approach is feature creep - there will always be
- Chad Joan (17/37) Feb 05 2013 Rare? What? No. Where is your data?
- Chad Joan (48/68) Feb 05 2013 Hmmm. This statement that unchecked public members are rare makes me
- Dicebot (4/8) Feb 05 2013 Well, Andrei background is easy to check:
- Chad Joan (7/14) Feb 05 2013 I know I know ;)
- Dmitry Olshansky (6/25) Feb 05 2013 Thinking more of it with proper properties it would be doable with a
- Jonathan M Davis (20/40) Feb 05 2013 Being able to initially use a public variable and then swap it out later...
- kenji hara (34/66) Feb 05 2013 I fully agree with Andrei.
- Robert (10/15) Feb 06 2013 It is not feature creep, it is properties done right. If not done this
- Zach the Mystic (9/45) Feb 05 2013 I'm not really sure which part of my article you are addressing
- Dmitry Olshansky (5/7) Feb 05 2013 Sorry, I posted reply to the wrong post.
- Zach the Mystic (4/11) Feb 05 2013 I hope this doesn't end up being the primary reason people
- Jonathan M Davis (19/38) Feb 05 2013 You misunderstand. We don't _want_ taking the address to work. We _want_...
- Andrej Mitrovic (22/24) Feb 05 2013 What Jonathan means is this:
- Tove (17/44) Feb 10 2013 It is also possible to first start with setters/getters and then
- Martin Nowak (9/11) Dec 13 2013 Could someone summarize the curent state and update the wiki pages
Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 We got input from DIP21 (which we didn't want to clobber, hence the new DIP) and the recent discussion. The proposal probably won't be accepted in its current form because it breaks some code. We hope to bring it to good shape with everyone's help. In brief: * Optional parens stay. * Just mentioning a function or method without parens does NOT automatically take its address. (This is a change from the current behavior.) * Read properties (using property) work as expected with the mention that they may NOT be called with the parens. Any parens would apply to the returned value. * Write properties (using property) may only be used in the assignment form (no function-style call allowed). It is understood that the current proposal is just a draft and there must be quite a few corner cases it doesn't discuss. We also understand it's impossible to reconcile all viewpoints and please all tastes. Our hope is to get to a point where the rules are self-consistent, meaningful, and complete. Destroy. Andrei
Feb 03 2013
I always wondered if there's a good way to incorporate opOpAssign family of operators with the write property syntax. Currently, using anything but the direct assignment fails, so even if eventually the support for defining specific opOpAssign for properties won't be implemented, at least the automatic rewrite of them would be nice: struct A { public: int i() { return _i; } int i(int i_) { return _i = i_; } private: int _i; } unittest { A a; a.i += 2; // a.i(a.i() + 2); } On Sun, Feb 3, 2013 at 12:16 PM, Andrei Alexandrescu < SeeWebsiteForEmail erdani.org> wrote:Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 We got input from DIP21 (which we didn't want to clobber, hence the new DIP) and the recent discussion. The proposal probably won't be accepted in its current form because it breaks some code. We hope to bring it to good shape with everyone's help. In brief: * Optional parens stay. * Just mentioning a function or method without parens does NOT automatically take its address. (This is a change from the current behavior.) * Read properties (using property) work as expected with the mention that they may NOT be called with the parens. Any parens would apply to the returned value. * Write properties (using property) may only be used in the assignment form (no function-style call allowed). It is understood that the current proposal is just a draft and there must be quite a few corner cases it doesn't discuss. We also understand it's impossible to reconcile all viewpoints and please all tastes. Our hope is to get to a point where the rules are self-consistent, meaningful, and complete. Destroy. Andrei-- Bye, Gor Gyolchanyan.
Feb 03 2013
Sorry, forgot the property. On Sun, Feb 3, 2013 at 12:27 PM, Gor Gyolchanyan < gor.f.gyolchanyan gmail.com> wrote:I always wondered if there's a good way to incorporate opOpAssign family of operators with the write property syntax. Currently, using anything but the direct assignment fails, so even if eventually the support for defining specific opOpAssign for properties won't be implemented, at least the automatic rewrite of them would be nice: struct A { public: int i() { return _i; } int i(int i_) { return _i = i_; } private: int _i; } unittest { A a; a.i += 2; // a.i(a.i() + 2); } On Sun, Feb 3, 2013 at 12:16 PM, Andrei Alexandrescu < SeeWebsiteForEmail erdani.org> wrote:-- Bye, Gor Gyolchanyan.Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 We got input from DIP21 (which we didn't want to clobber, hence the new DIP) and the recent discussion. The proposal probably won't be accepted in its current form because it breaks some code. We hope to bring it to good shape with everyone's help. In brief: * Optional parens stay. * Just mentioning a function or method without parens does NOT automatically take its address. (This is a change from the current behavior.) * Read properties (using property) work as expected with the mention that they may NOT be called with the parens. Any parens would apply to the returned value. * Write properties (using property) may only be used in the assignment form (no function-style call allowed). It is understood that the current proposal is just a draft and there must be quite a few corner cases it doesn't discuss. We also understand it's impossible to reconcile all viewpoints and please all tastes. Our hope is to get to a point where the rules are self-consistent, meaningful, and complete. Destroy. Andrei-- Bye, Gor Gyolchanyan.
Feb 03 2013
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:* Just mentioning a function or method without parens does NOT automatically take its address. (This is a change from the current behavior.)I don't understand.* Read properties (using property) work as expected with the mention that they may NOT be called with the parens. Any parens would apply to the returned value.Great !* Write properties (using property) may only be used in the assignment form (no function-style call allowed).Awesome. Two things now : - free functions annotated properties with one argument ? (are they setter ? getters ? both ?) - order of evaluation.
Feb 03 2013
On Sunday, February 03, 2013 03:16:08 Andrei Alexandrescu wrote:Destroy.Overall, it looks good. It sounds like it's basically arguing for fully implementing property as intended save for the fact that parenless function calls on normal functions are allowed. And that's pretty much what I've been arguing for during all of this latest property debate. However, one issue that I'm concerned about with regards to properties which hasn't really been discussed much and which doesn't have a whole lot to do with how they're declared (but rather the syntax of how they're used) is how to handle symbol clashes. For instance, if you have the free function auto prop(int[] arr) {...} in module a.b.c, and you have auto prop(int[] arr) {...} in module a.d.e, how do you deal with code that does import a.b.c; import a.d.e; auto var = arr.prop; Syntactically, there's no way to indicate which of the two functions you mean. It's a problem that only occurs with free functions and UFCS (since with member functions, the member function wins in any conflict with a free function, and member functions on the same type can't be in different modules), but it's definitely something that can happen. And we really should come up with a fix for it. The best that I can think of at the moment is something like auto var = arr.a.b.c.prop; where you're trying to use a.b.c.prop, but I don't know if that's a good syntax or not. It could certainly cause problems if arr were a user-defined type with a property called arr, so maybe adding parens would help auto var = arr.(a.b.c).prop; but that's still a bit ugly. I don't know if there's a good way that _isn't_ ugly though. I suppose that we could get away with arguing that symbol renaming would be required alias a.b.c.prop myprop; auto var = arr.myprop; but I don't know that that's a great solution either. AFAIK though, it's the only way that we have to deal with the problem right now. - Jonathan M Davis
Feb 03 2013
On Sunday, 3 February 2013 at 08:51:58 UTC, Jonathan M Davis wrote:auto prop(int[] arr) {...} in module a.b.c, and you have auto prop(int[] arr) {...} in module a.d.e, how do you deal with code that does import a.b.c; import a.d.e; auto var = arr.prop; Syntactically, there's no way to indicate which of the two functions you mean.Couldn't an alias make it ? alias propFromA = a.b.c.prop; auto var = arr.propFromA;
Feb 03 2013
On 2/3/13 3:50 AM, Jonathan M Davis wrote:On Sunday, February 03, 2013 03:16:08 Andrei Alexandrescu wrote:First off, defining a top-level property ought indeed to have an air of definitive-ness, so this is good. It also illustrates that defining top-level properties should be rare. To fix this, no need to add syntax: import a.b.c; import a.b.c : prop1 = prop; import a.d.e; import a.d.e : prop2 = prop; auto v1 = arr.prop1; // goes to a.b.c.prop auto v2 = arr.prop2; // gies to a.d.e.prop AndreiDestroy.Overall, it looks good. It sounds like it's basically arguing for fully implementing property as intended save for the fact that parenless function calls on normal functions are allowed. And that's pretty much what I've been arguing for during all of this latest property debate. However, one issue that I'm concerned about with regards to properties which hasn't really been discussed much and which doesn't have a whole lot to do with how they're declared (but rather the syntax of how they're used) is how to handle symbol clashes. For instance, if you have the free function auto prop(int[] arr) {...} in module a.b.c, and you have auto prop(int[] arr) {...} in module a.d.e, how do you deal with code that does import a.b.c; import a.d.e; auto var = arr.prop;
Feb 03 2013
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:It is understood that the current proposal is just a draft and there must be quite a few corner cases it doesn't discuss.Here are some more test cases to think about: http://wiki.dlang.org/Property_Discussion_Wrap-up#Unified_test_suite Specifically, for ref-returning function, I assume the &-operator is meant to return the address of the callable for non- property function, but the address of the returned value for properties? David
Feb 03 2013
On Sunday, 3 February 2013 at 09:04:59 UTC, David Nadlinger wrote:On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:I wanted to avoid the topic as it is basically solved for properties. Andrei, is that possible to split the DIP in 2 : one for properties and one for other functions. It seems that the property part is agreed by most people, but the other one raise more questions.It is understood that the current proposal is just a draft and there must be quite a few corner cases it doesn't discuss.Here are some more test cases to think about: http://wiki.dlang.org/Property_Discussion_Wrap-up#Unified_test_suite Specifically, for ref-returning function, I assume the &-operator is meant to return the address of the callable for non- property function, but the address of the returned value for properties?
Feb 03 2013
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:In brief: * Optional parens stay. AndreiWill we keep the optional -property (or similar) for those of us that *want* enforced parens, even with UFCS? Did a sensible reasons actually ever come up for allowing optional parens on non-UFCS?
Feb 03 2013
03-Feb-2013 13:11, monarch_dodra пишет:On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:Using verbs for actions and nouns for querying data and not being thrilled with useless parens everywhere? But let's not discus this again. -- Dmitry OlshanskyIn brief: * Optional parens stay. AndreiWill we keep the optional -property (or similar) for those of us that *want* enforced parens, even with UFCS? Did a sensible reasons actually ever come up for allowing optional parens on non-UFCS?
Feb 03 2013
On 2/3/13 4:11 AM, monarch_dodra wrote:On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:No. Thanks for the reminder - I updated the DIP.In brief: * Optional parens stay. AndreiWill we keep the optional -property (or similar) for those of us that *want* enforced parens, even with UFCS?Did a sensible reasons actually ever come up for allowing optional parens on non-UFCS?This is a judgment call as reasonable people may disagree on it. Walter and I both believe optional parens are a good thing for D. At this point, we don't think one more pass through the pros and cons would change our opinion. Andrei
Feb 03 2013
On Sunday, 3 February 2013 at 14:40:30 UTC, Andrei Alexandrescu wrote:On 2/3/13 4:11 AM, monarch_dodra wrote:Thank you for the answers. I didn't follow all 500 posts in the other thread, so it was really just to have more vision on the DIP. I don't want to try to change anybody's opinion. Just trying to get a clear status on where we currently stand.On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:No. Thanks for the reminder - I updated the DIP.In brief: * Optional parens stay. AndreiWill we keep the optional -property (or similar) for those of us that *want* enforced parens, even with UFCS?Did a sensible reasons actually ever come up for allowing optional parens on non-UFCS?This is a judgment call as reasonable people may disagree on it. Walter and I both believe optional parens are a good thing for D. At this point, we don't think one more pass through the pros and cons would change our opinion. Andrei
Feb 03 2013
Am Sun, 03 Feb 2013 03:16:08 -0500 schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:It is understood that the current proposal is just a draft and there must be quite a few corner cases it doesn't discuss. We also understand it's impossible to reconcile all viewpoints and please all tastes. Our hope is to get to a point where the rules are self-consistent, meaningful, and complete. Destroy. Andrei"If a function returns a reference, then assignment through the paren-less call should work: " This is the only part where I would disagree. Why is this special rule necessary if we have full property support? I think this would still allow too many false positives. One important aspect that this proposal doesn't cover yet is whether we want to allow "semantic rewriting" for properties: ---- Struct a; a.property++; //would this be legal? ---- for other corner cases this list is a good start: http://wiki.dlang.org/Property_Discussion_Wrap-up#Implementation_concerns * Can we get a reference to the property? What does &x.property mean? * How can we get the getter / setter functions? Do we need to get those? * What is the type of the property? Return type, setter function type or getter function type? How to get the other types? * What does x.property++ do? ([http://www.prowiki.org/wiki4d/wiki.cgi?DocComments/Property#Semanticrewritingofproperties Semantic rewriting]) * Is returning ref values from the getter OK? * Is taking ref values in the setter OK? * Should all properties be nothrow? pure? getter const? ** Probably better as a rule for style guide. * Are UFCS properties possible? How do they work exactly? * How do you disambiguate property functions when they're free functions which conflict? ** Normal UFCS functions can be force called by using their fully qualified name. That's not possible for properties if function call syntax is disallowed? * How many parameters are allowed for property functions? ** Are default parameters allowed? ** Especially consider the example about __FILE__ and __LINE__ * Are templated properties allowed? ** The access syntax for properties doesn't allow providing types
Feb 03 2013
On 2/3/13 5:14 AM, Johannes Pfau wrote:"If a function returns a reference, then assignment through the paren-less call should work: " This is the only part where I would disagree. Why is this special rule necessary if we have full property support? I think this would still allow too many false positives.(As a note, this is the current behavior.) The way I see it is this is a natural consequence of optional parens. The name of a function without a "&" prepended or a "()" after it will invoke the function, and that's that.One important aspect that this proposal doesn't cover yet is whether we want to allow "semantic rewriting" for properties: ---- Struct a; a.property++; //would this be legal? ----It's dangerous to get too clever about that. Anyhow, such rewrites are possible: ++a.p ----> { auto v = a.p; ++v; a.p = v; return v; }() a.p++ ----> { auto v = a.p; ++a.p; return v; }() and so on.for other corner cases this list is a good start: http://wiki.dlang.org/Property_Discussion_Wrap-up#Implementation_concerns * Can we get a reference to the property? What does &x.property mean?We need to add this to the proposal. There are two schools of thought here: 1. Make properties emulate regular variables as much as possible. In that case &a.p is the same as &(a.p), i.e. it applies to the returned value. (One counter-argument here is that properties should seldom return a reference because that breaks encapsulation.) 2. Allow people to do whatever they need to do without much aggravation. In that case &a.p obeys the normal rules of taking a method's address, and &(a.p) applies to the returned value. I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to Walter.* How can we get the getter / setter functions? Do we need to get those?Per (2) above there is no need for special provisions.* What is the type of the property? Return type, setter function type or getter function type? How to get the other types?typeof(r.front) is the return type of the property, typeof(&(r.front)) is the type of a pointer to the return type of the property where applicable, and typeof(&r.front) is the (possibly ambiguous) address of the method. (To disambiguate one would use the appropriate receiver type.)* What does x.property++ do? ([http://www.prowiki.org/wiki4d/wiki.cgi?DocComments/Property#Semanticrewritingofproperties Semantic rewriting])Added to http://wiki.dlang.org/DIP23.* Is returning ref values from the getter OK?I see no reason to disallow it at the language level.* Is taking ref values in the setter OK?How do you mean that?* Should all properties be nothrow? pure? getter const? ** Probably better as a rule for style guide.No restriction at language level.* Are UFCS properties possible? How do they work exactly? * How do you disambiguate property functions when they're free functions which conflict?I think it would be best to simply disallow parameterless module-level properties. // at top level property int foo(); // error property int goo(int); // fine, assume a getter for int** Normal UFCS functions can be force called by using their fully qualified name. That's not possible for properties if function call syntax is disallowed?Correct. Writing property buys the writer into a constrained universe.* How many parameters are allowed for property functions?One or two at top level, zero or one at member level.** Are default parameters allowed? ** Especially consider the example about __FILE__ and __LINE__I'd say no. Just keep it simple and focused on the goal.* Are templated properties allowed? ** The access syntax for properties doesn't allow providing typesNo. Templated member variables are not allowed either. Andrei
Feb 03 2013
2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>We need to add this to the proposal. There are two schools of thought here: 1. Make properties emulate regular variables as much as possible. In that case &a.p is the same as &(a.p), i.e. it applies to the returned value. (One counter-argument here is that properties should seldom return a reference because that breaks encapsulation.) 2. Allow people to do whatever they need to do without much aggravation. In that case &a.p obeys the normal rules of taking a method's address, and &(a.p) applies to the returned value. I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to Walter.I have thought about the problem, and filed an enhancement. http://d.puremagic.com/issues/show_bug.cgi?id=9062 But, Walter disagreed against it. http://d.puremagic.com/issues/show_bug.cgi?id=9062#c13 Kenji Hara
Feb 03 2013
On 2/3/13 11:28 AM, kenji hara wrote:2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org <mailto:SeeWebsiteForEmail erdani.org>> We need to add this to the proposal. There are two schools of thought here: 1. Make properties emulate regular variables as much as possible. In that case &a.p is the same as &(a.p), i.e. it applies to the returned value. (One counter-argument here is that properties should seldom return a reference because that breaks encapsulation.) 2. Allow people to do whatever they need to do without much aggravation. In that case &a.p obeys the normal rules of taking a method's address, and &(a.p) applies to the returned value. I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to Walter. I have thought about the problem, and filed an enhancement. http://d.puremagic.com/issues/show_bug.cgi?id=9062 But, Walter disagreed against it. http://d.puremagic.com/issues/show_bug.cgi?id=9062#c13 Kenji HaraNow that an overhaul is on the table, that warrants a second look. Andrei
Feb 03 2013
On Sun, 03 Feb 2013 11:11:05 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 2/3/13 5:14 AM, Johannes Pfau wrote:This sounds good. It might be a bit confusing, but nice in the fact that &(a.b) always means address of whatever b returns, whether it is a field or property."If a function returns a reference, then assignment through the paren-less call should work: " This is the only part where I would disagree. Why is this special rule necessary if we have full property support? I think this would still allow too many false positives.(As a note, this is the current behavior.) The way I see it is this is a natural consequence of optional parens. The name of a function without a "&" prepended or a "()" after it will invoke the function, and that's that.One important aspect that this proposal doesn't cover yet is whether we want to allow "semantic rewriting" for properties: ---- Struct a; a.property++; //would this be legal? ----It's dangerous to get too clever about that. Anyhow, such rewrites are possible: ++a.p ----> { auto v = a.p; ++v; a.p = v; return v; }() a.p++ ----> { auto v = a.p; ++a.p; return v; }() and so on.for other corner cases this list is a good start: http://wiki.dlang.org/Property_Discussion_Wrap-up#Implementation_concerns * Can we get a reference to the property? What does &x.property mean?We need to add this to the proposal. There are two schools of thought here: 1. Make properties emulate regular variables as much as possible. In that case &a.p is the same as &(a.p), i.e. it applies to the returned value. (One counter-argument here is that properties should seldom return a reference because that breaks encapsulation.) 2. Allow people to do whatever they need to do without much aggravation. In that case &a.p obeys the normal rules of taking a method's address, and &(a.p) applies to the returned value. I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to Walter.I think this is a possible solution, and I can live with that, I'm fairly certain that some people use global properties currently, so they will not be too happy. But having to set global properties using a function call (global getters can simply be paren-less functions) isn't horrible.* Are UFCS properties possible? How do they work exactly? * How do you disambiguate property functions when they're free functions which conflict?I think it would be best to simply disallow parameterless module-level properties. // at top level property int foo(); // error property int goo(int); // fine, assume a getter for intWait, what? I don't like this idea. Why should this not be allowed: property void x(T)(T t) {_x = to!(typeof(_x))(t);} As for templates that return a templated type, it should be allowed, although the calling syntax would have to be for the explicit template call, since you can't do IFTI on return values. In other words: template x(T) { property T x(){return to!(T)(_x);} } // could be shortened to normal property T x(T)() auto xcopy = obj.x!(string).x; Certainly, we need templated getters and setters at module levels: property T front(T)(T[] r) { return r[0];} -Steve* Are templated properties allowed? ** The access syntax for properties doesn't allow providing typesNo. Templated member variables are not allowed either.
Feb 03 2013
On Sun, 03 Feb 2013 11:28:52 -0500, Steven Schveighoffer <schveiguy yahoo.com> wrote:As for templates that return a templated type, it should be allowed, although the calling syntax would have to be for the explicit template call, since you can't do IFTI on return values. In other words: template x(T) { property T x(){return to!(T)(_x);} } // could be shortened to normal property T x(T)() auto xcopy = obj.x!(string).x;Hm... I actually am changing my mind on this, you should be able to do: auto xcopy = obj.x!(string); For the simple reason that if property is omitted, this would work (simple lack of parens). It makes no sense to make properties not have this ability. -Steve
Feb 03 2013
On 2/3/13 11:28 AM, Steven Schveighoffer wrote:This sounds good. It might be a bit confusing, but nice in the fact that &(a.b) always means address of whatever b returns, whether it is a field or property.Yah, this is a good rule of thumb for generic code. Note that there's a subtlety in the expression "&expr.name". This is not precedence, just use of punctuation to express a unit. Attempting to decompose it by inserting parens yields different things altogether: &(expr.name) and (&expr).name are not mere redirections of precedence.Yah, let's see how this restriction pans out.property int foo(); // error property int goo(int); // fine, assume a getter for intI think this is a possible solution, and I can live with that, I'm fairly certain that some people use global properties currently, so they will not be too happy.Yah, I misspoke. Properties can be templated subject to the other restrictions. AndreiNo. Templated member variables are not allowed either.Wait, what? I don't like this idea. Why should this not be allowed: property void x(T)(T t) {_x = to!(typeof(_x))(t);}
Feb 03 2013
Am Sun, 03 Feb 2013 11:11:05 -0500 schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:On 2/3/13 5:14 AM, Johannes Pfau wrote:I didn't think of it as a call without parentheses but it indeed makes sense."If a function returns a reference, then assignment through the paren-less call should work: " This is the only part where I would disagree. Why is this special rule necessary if we have full property support? I think this would still allow too many false positives.(As a note, this is the current behavior.) The way I see it is this is a natural consequence of optional parens. The name of a function without a "&" prepended or a "()" after it will invoke the function, and that's that.You have to consider cases though where you have both a setter and a getter returning a 'ref value'. property ref int value(); property void value(int new); * Is it valid to define both at the same time? * Which one is used for assignment etc?* Is returning ref values from the getter OK?I see no reason to disallow it at the language level.property int value(ref int new); IIRC that was just meant to complement the "is returning ref OK". Usually nothing bad can happen. Although the ref parameter could be converted into a pointer with some nasty tricks it's probably not the job of the language to prevent that.* Is taking ref values in the setter OK?How do you mean that?
Feb 03 2013
On 2/3/13 11:34 AM, Johannes Pfau wrote:You have to consider cases though where you have both a setter and a getter returning a 'ref value'. property ref int value(); property void value(int new);For now I disallow 0-parameter top level properties. This is a good argument for keeping things that way.* Is it valid to define both at the same time? * Which one is used for assignment etc?Yah, there should be no restrictions there. Andreiproperty int value(ref int new); IIRC that was just meant to complement the "is returning ref OK". Usually nothing bad can happen. Although the ref parameter could be converted into a pointer with some nasty tricks it's probably not the job of the language to prevent that.* Is taking ref values in the setter OK?How do you mean that?
Feb 03 2013
On Sun, 03 Feb 2013 14:42:17 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 2/3/13 11:34 AM, Johannes Pfau wrote:I think Johannes' argument applies to non-global properties. struct X { private int _val; property ref int value() { return _val;} property void value(int newv) { _val = newv; writeln("in setter!");} } So should setting 'value' call the specific setter, or call the getter and just write it? My vote would be to call the setter, since it wouldn't exist if the user didn't want to hook that call. However, it certainly begs the question, why would anyone return ref if they want to hook setting? One could always do this: void foo(ref int v) {v = 5;} X x; foo(x.value); I think it's still too early to make any assumptions at this point. Someone may find a good reason for that, and it's certainly just easier to allow code that is already valid than it is to come up with a reason to have an error. -SteveYou have to consider cases though where you have both a setter and a getter returning a 'ref value'. property ref int value(); property void value(int new);For now I disallow 0-parameter top level properties. This is a good argument for keeping things that way.
Feb 03 2013
On 02/03/2013 05:11 PM, Andrei Alexandrescu wrote:... 2. Allow people to do whatever they need to do without much aggravation. In that case &a.p obeys the normal rules of taking a method's address, and &(a.p) applies to the returned value. I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to Walter.That is horrible! The entire language construct is necessarily a bit of a patchwork, but there is no reason to aggravate this gratuitously....Ditto.* Are templated properties allowed? ** The access syntax for properties doesn't allow providing typesNo.Templated member variables are not allowed either.(Actually they are silently rewritten to static member variables. I do not like that.)
Feb 03 2013
I'm glad Johannes brought up all these cases. They all need to go into the DIP.
Feb 03 2013
On 2013-02-03 17:11, Andrei Alexandrescu wrote:It's dangerous to get too clever about that. Anyhow, such rewrites are possible: ++a.p ----> { auto v = a.p; ++v; a.p = v; return v; }() a.p++ ----> { auto v = a.p; ++a.p; return v; }() and so on.Is that part of the proposal or not? -- /Jacob Carlborg
Feb 04 2013
On Monday, February 04, 2013 09:22:56 Jacob Carlborg wrote:On 2013-02-03 17:11, Andrei Alexandrescu wrote:It is now, though I don't think that it was intially. It's in the "Applying operators" section. - Jonathan M DavisIt's dangerous to get too clever about that. Anyhow, such rewrites are possible: ++a.p ----> { auto v = a.p; ++v; a.p = v; return v; }() a.p++ ----> { auto v = a.p; ++a.p; return v; }() and so on.Is that part of the proposal or not?
Feb 04 2013
On 02/03/2013 11:11 AM, Andrei Alexandrescu wrote:On 2/3/13 5:14 AM, Johannes Pfau wrote:I disagree with this. I think that allowing address-of on getters is potentially a big source of trouble. I've felt that getters should be forbidden from returning lvalues. So returning ref from a getter is not OK, but const ref should be fine. Anyone who wants to make the property behave like a reference should define an appropriate setter for it. There are a couple reasons for this: - It would be nice to allow variables/fields to have property as an annotation. This would forbid address-of to allow seamless transition into fully-implemented property functions later. To make the roundtrip possible, the property functions should also disallow address-of. - Allowing mutation of a getter's expression can create unwanted ambiguities when attempting to apply property rewrites. Without an lvalue getter it becomes unambiguous: any side-effectful operation on a property (that isn't direct assignment, or something requiring a read) will call both its getter and setter....for other corner cases this list is a good start: http://wiki.dlang.org/Property_Discussion_Wrap-up#Implementation_concerns * Can we get a reference to the property? What does &x.property mean?We need to add this to the proposal. There are two schools of thought here: 1. Make properties emulate regular variables as much as possible. In that case &a.p is the same as &(a.p), i.e. it applies to the returned value. (One counter-argument here is that properties should seldom return a reference because that breaks encapsulation.) 2. Allow people to do whatever they need to do without much aggravation. In that case &a.p obeys the normal rules of taking a method's address, and &(a.p) applies to the returned value. I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to Walter....Andrei
Feb 04 2013
On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties: property int foo(int x) {return x * 5;} could be interpreted as: foo = 2; // not correct (for this example) int x = 2.foo; // correct Note that: property int foo(); property void foo(int x, int y); are both unambiguous. ================== I have a possible suggestion to fix this within your proposal: property on single-arg free functions ONLY enables a setter mode, it does not work as a UFCS getter. Therefore, if you wish to write a UFCS getter, omit the property designation. int foo(int x) {return x * 5;} foo = 2; // illegal int x = 2.foo; // OK, sets x to 10 int x = foo(2); // same as above property int foo(int x) {_foo = x;} foo = 2; // OK, sets _foo to 2 int x = 2.foo; // illegal int x = foo(2); // illegal I know this is not a complete solution, and can be confusing, but we have little options at this point, given existing code. Also note that we already have a way to specify a getter property on a user-defined type, UFCS isn't entirely necessary for that. This will break SOME declarations, but removing property should result in compiling code I think. -Steve
Feb 03 2013
2013/2/3 Steven Schveighoffer <schveiguy yahoo.com>I have a possible suggestion to fix this within your proposal: property on single-arg free functions ONLY enables a setter mode, it does not work as a UFCS getter.[snip]I was thinking the exact same thing. Kenji Hara
Feb 03 2013
On 2/3/13 7:40 AM, kenji hara wrote:2013/2/3 Steven Schveighoffer <schveiguy yahoo.com <mailto:schveiguy yahoo.com>> I have a possible suggestion to fix this within your proposal: property on single-arg free functions ONLY enables a setter mode, it does not work as a UFCS getter. [snip] I was thinking the exact same thing.Then we can't make this work: property ref T front(T[] array) { return array[0]; } unittest { auto a = [ 1, 2, 3]; auto b = a.front; } Andrei
Feb 03 2013
On Sun, 03 Feb 2013 12:36:10 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 2/3/13 7:40 AM, kenji hara wrote:ref T front(T[] array) { return array[0]; } // same unittest But I also can agree with the idea you currently have to make UFCS properties require a 'this' initial parameter. -Steve2013/2/3 Steven Schveighoffer <schveiguy yahoo.com <mailto:schveiguy yahoo.com>> I have a possible suggestion to fix this within your proposal: property on single-arg free functions ONLY enables a setter mode, it does not work as a UFCS getter. [snip] I was thinking the exact same thing.Then we can't make this work: property ref T front(T[] array) { return array[0]; } unittest { auto a = [ 1, 2, 3]; auto b = a.front; }
Feb 03 2013
On 02/03/2013 06:47 PM, Steven Schveighoffer wrote:On Sun, 03 Feb 2013 12:36:10 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:different unittest: unittest{ auto a = [()=>2, ()=>3, ()=>4]; assert(a.front()==2); }On 2/3/13 7:40 AM, kenji hara wrote:ref T front(T[] array) { return array[0]; } // same unittest2013/2/3 Steven Schveighoffer <schveiguy yahoo.com <mailto:schveiguy yahoo.com>> I have a possible suggestion to fix this within your proposal: property on single-arg free functions ONLY enables a setter mode, it does not work as a UFCS getter. [snip] I was thinking the exact same thing.Then we can't make this work: property ref T front(T[] array) { return array[0]; } unittest { auto a = [ 1, 2, 3]; auto b = a.front; }But I also can agree with the idea you currently have to make UFCS properties require a 'this' initial parameter. -Steve
Feb 03 2013
On Sun, 03 Feb 2013 12:58:21 -0500, Timon Gehr <timon.gehr gmx.ch> wrote:On 02/03/2013 06:47 PM, Steven Schveighoffer wrote:OK, so that is not good. I think the current DIP23 idea should be sufficient, no global properties. -SteveOn Sun, 03 Feb 2013 12:36:10 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:different unittest: unittest{ auto a = [()=>2, ()=>3, ()=>4]; assert(a.front()==2); }On 2/3/13 7:40 AM, kenji hara wrote:ref T front(T[] array) { return array[0]; } // same unittest2013/2/3 Steven Schveighoffer <schveiguy yahoo.com <mailto:schveiguy yahoo.com>> I have a possible suggestion to fix this within your proposal: property on single-arg free functions ONLY enables a setter mode, it does not work as a UFCS getter. [snip] I was thinking the exact same thing.Then we can't make this work: property ref T front(T[] array) { return array[0]; } unittest { auto a = [ 1, 2, 3]; auto b = a.front; }
Feb 03 2013
On Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now). I think we should provide a __traits accessor for this. Otherwise, there is no way to port said code to the new style. -SteveWalter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties:
Feb 03 2013
2013/2/3 Steven Schveighoffer <schveiguy yahoo.com>On Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer < schveiguy yahoo.com> wrote: On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu <On the contrary with you, I was read that we no longer get an address of ref returned value by address-op. property ref int foo(); static assert(is(typeof(&foo) == ref int function())); // typeof does not return int* If I am correct, there is no need for special enhancement like __traits. Kenji HaraSeeWebsiteForEmail erdani.org**> wrote: Walter and I have had a discussion on how to finalize properties.I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now). I think we should provide a __traits accessor for this. Otherwise, there is no way to port said code to the new style.http://wiki.dlang.org/DIP23I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties:
Feb 03 2013
On 02/03/2013 02:00 PM, kenji hara wrote:2013/2/3 Steven Schveighoffer <schveiguy yahoo.com <mailto:schveiguy yahoo.com>> ... I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now). I think we should provide a __traits accessor for this. Otherwise, there is no way to port said code to the new style. On the contrary with you, I was read that we no longer get an address of ref returned value by address-op. property ref int foo(); static assert(is(typeof(&foo) == ref int function())); // typeof does not return int* If I am correct, there is no need for special enhancement like __traits.The DIP actually misses to address this case.
Feb 03 2013
On Sun, 03 Feb 2013 08:00:32 -0500, kenji hara <k.hara.pg gmail.com> wrote:2013/2/3 Steven Schveighoffer <schveiguy yahoo.com>You are right, it does not specify this, I was somewhat mistaken. But the spirit of the proposal seems to suggest that for all intents and purposes, a property's type is the type of it's return value. For the most part, taking the address of an rvalue is an error anyway, so it makes sense to make this type of function return a delegate with the & operator. However, in the case of ref returns for properties, I think it may be too limiting if it is impossible to get the address of a ref return: property ref int foo(); int *x = &foo; // error returns delegate? int *y = &foo(); // error, using parens illegal? Somewhat glaring here is that you can't make ref local variables. I suppose in this case, the such a function could have property removed on it, but that is little help to the user of such a function who has no control over the API. A potential workaround could be a la Timon's suggestion: ref int foowrap() { return foo;} int *x = &foowrap(); Let's go with the current proposal, and I will address the __traits mechanism separately. -SteveOn Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer < schveiguy yahoo.com> wrote: On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu <On the contrary with you, I was read that we no longer get an address of ref returned value by address-op. property ref int foo(); static assert(is(typeof(&foo) == ref int function())); // typeof does not return int* If I am correct, there is no need for special enhancement like __traits.SeeWebsiteForEmail erdani.org**> wrote: Walter and I have had a discussion on how to finalize properties.I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now). I think we should provide a __traits accessor for this. Otherwise, there is no way to port said code to the new style.http://wiki.dlang.org/DIP23I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties:
Feb 03 2013
On Sunday, 3 February 2013 at 15:16:30 UTC, Steven Schveighoffer wrote:But the spirit of the proposal seems to suggest that for all intents and purposes, a property's type is the type of it's return value.If you want a function, then just don't annotate with property. The whole point of property is that it doesn't behave like a function.
Feb 03 2013
On Sun, 03 Feb 2013 10:31:31 -0500, deadalnix <deadalnix gmail.com> wrote:On Sunday, 3 February 2013 at 15:16:30 UTC, Steven Schveighoffer wrote:That is not the point of properties. The point of properties is to have hooks for field setting and getting. They necessarily behave like functions. -SteveBut the spirit of the proposal seems to suggest that for all intents and purposes, a property's type is the type of it's return value.If you want a function, then just don't annotate with property. The whole point of property is that it doesn't behave like a function.
Feb 03 2013
On Sunday, 3 February 2013 at 16:03:50 UTC, Steven Schveighoffer wrote:On Sun, 03 Feb 2013 10:31:31 -0500, deadalnix <deadalnix gmail.com> wrote:That is not the point of properties. The point of setter and getter methods is to have hooks for field setting and getting. The point or properties is to have clearer semantics than what regular setter and getter methods would have.If you want a function, then just don't annotate with property. The whole point of property is that it doesn't behave like a function.That is not the point of properties. The point of properties is to have hooks for field setting and getting. They necessarily behave like functions. -Steve
Feb 03 2013
2013/2/4 Steven Schveighoffer <schveiguy yahoo.com>On Sun, 03 Feb 2013 08:00:32 -0500, kenji hara <k.hara.pg gmail.com> wrote:[snip] It is already satisfied. Inside typeof, all use of property makes its return type. I think the case of getting address of ref value returned from a property is much rare. If you really want to do it, we can write short workaround. A potential workaround could be a la Timon's suggestion:On the contrary with you, I was read that we no longer get an address of ref returned value by address-op. property ref int foo(); static assert(is(typeof(&foo) == ref int function())); // typeof does not return int* If I am correct, there is no need for special enhancement like __traits.You are right, it does not specify this, I was somewhat mistaken. But the spirit of the proposal seems to suggest that for all intents and purposes, a property's type is the type of it's return value.ref int foowrap() { return foo;} int *x = &foowrap();One liner version: int* x = ((ref x) => &x)(foo); Let's go with the current proposal, and I will address the __traitsmechanism separately.It seems to me that is an overkill. Kenji Hara
Feb 03 2013
On Sun, 03 Feb 2013 10:56:50 -0500, kenji hara <k.hara.pg gmail.com> wrote:2013/2/4 Steven Schveighoffer <schveiguy yahoo.com>That looks better than mine, it takes a bit to understand it :) It can be written into a global function: T *addressOf(T)(ref T t) {return &t;} I think this should actually work: int *x = foo.addressOf;ref int foowrap() { return foo;} int *x = &foowrap();One liner version: int* x = ((ref x) => &x)(foo);I have other ideas for such a feature, which map into something I've wished for a long time. You will see. -SteveLet's go with the current proposal, and I will address the __traits mechanism separately.It seems to me that is an overkill.
Feb 03 2013
On 2/3/13 10:16 AM, Steven Schveighoffer wrote:Let's go with the current proposal, and I will address the __traits mechanism separately.Yes, __traits is a nice hatch if we discover we find we can't do something. Hopefully we won't find any, or just one. Andrei
Feb 03 2013
On 02/03/2013 06:44 PM, Andrei Alexandrescu wrote:On 2/3/13 10:16 AM, Steven Schveighoffer wrote:__traits is a lot cleaner than assigning meaning to parentheses.Let's go with the current proposal, and I will address the __traits mechanism separately.Yes, __traits is a nice hatch if we discover we find we can't do something. Hopefully we won't find any, or just one. Andrei
Feb 03 2013
On 02/03/2013 01:49 PM, Steven Schveighoffer wrote:On Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer <schveiguy yahoo.com> wrote:T delegate() f = &a.prop -> auto f = ()=>a.prop; T delegate(T) f = &a.prop -> auto f = (T x)=>a.prop=x;On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now). I think we should provide a __traits accessor for this. Otherwise, there is no way to port said code to the new style. -SteveWalter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties:
Feb 03 2013
On Sun, 03 Feb 2013 08:04:10 -0500, Timon Gehr <timon.gehr gmx.ch> wrote:T delegate() f = &a.prop -> auto f = ()=>a.prop; T delegate(T) f = &a.prop -> auto f = (T x)=>a.prop=x;I don't like this solution. You are creating a dummy delegate function, and moving the stack frame into the heap, just so you can get a delegate to an already existing function. -Steve
Feb 03 2013
On 02/03/2013 04:04 PM, Steven Schveighoffer wrote:On Sun, 03 Feb 2013 08:04:10 -0500, Timon Gehr <timon.gehr gmx.ch> wrote:The spec could be updated to allow/mandate eta-reduction where applicable.T delegate() f = &a.prop -> auto f = ()=>a.prop; T delegate(T) f = &a.prop -> auto f = (T x)=>a.prop=x;I don't like this solution. You are creating a dummy delegate function, and moving the stack frame into the heap, just so you can get a delegate to an already existing function. -Steve
Feb 03 2013
On Sunday, 3 February 2013 at 15:04:15 UTC, Steven Schveighoffer wrote:On Sun, 03 Feb 2013 08:04:10 -0500, Timon Gehr <timon.gehr gmx.ch> wrote:Unless you escape the delegate, it should allocate on the heap. And any inlining compiler should remove the delegate completely anyway.T delegate() f = &a.prop -> auto f = ()=>a.prop; T delegate(T) f = &a.prop -> auto f = (T x)=>a.prop=x;I don't like this solution. You are creating a dummy delegate function, and moving the stack frame into the heap, just so you can get a delegate to an already existing function. -Steve
Feb 03 2013
On 02/03/13 16:04, Steven Schveighoffer wrote:On Sun, 03 Feb 2013 08:04:10 -0500, Timon Gehr <timon.gehr gmx.ch> wrote:Not really, it just needs to be specced properly. There's already a similar issue with lazy args, and the natural solution is the same. A trivial "{ return any_kind_of_hidden_delegate; }" lambda is functionally equivalent to a "cast(delegate)any_kind_of_hidden_delegate" expression. The "optimization" just needs to be mandated, so that you can rely on the "real" delegate being forwarded (ie the .funcptr should be the real one and such lambda shouldn't trigger heap allocation). arturT delegate() f = &a.prop -> auto f = ()=>a.prop; T delegate(T) f = &a.prop -> auto f = (T x)=>a.prop=x;I don't like this solution. You are creating a dummy delegate function, and moving the stack frame into the heap, just so you can get a delegate to an already existing function.
Feb 03 2013
On Sunday, 3 February 2013 at 12:49:00 UTC, Steven Schveighoffer wrote:I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now).This isn't a problem.
Feb 03 2013
On 2/3/13 7:49 AM, Steven Schveighoffer wrote:On Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer <schveiguy yahoo.com> wrote:In the proposal &a.b gets the delegate of a property. AndreiOn Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now). I think we should provide a __traits accessor for this. Otherwise, there is no way to port said code to the new style.Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties:
Feb 03 2013
On Sunday, 3 February 2013 at 17:37:03 UTC, Andrei Alexandrescu wrote:In the proposal &a.b gets the delegate of a property.:facepalm:
Feb 03 2013
On 02/03/2013 06:38 PM, deadalnix wrote:On Sunday, 3 February 2013 at 17:37:03 UTC, Andrei Alexandrescu wrote:+1.In the proposal &a.b gets the delegate of a property.:facepalm:
Feb 03 2013
On 2013-02-03 09:16, Andrei Alexandrescu wrote:Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23What about: writeln = "asd"; Allowed or not? -- /Jacob Carlborg
Feb 03 2013
On Sunday, February 03, 2013 13:34:14 Jacob Carlborg wrote:On 2013-02-03 09:16, Andrei Alexandrescu wrote:I take it that you didn't read the DIP. At the very beginning of its section on "Write properties:" ----------- In order to use the assignment operator "=" property-style, the property annotation MUST be used. ----------- - Jonathan M DavisWalter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23What about: writeln = "asd"; Allowed or not?
Feb 03 2013
On 2013-02-03 13:40, Jonathan M Davis wrote:I take it that you didn't read the DIP. At the very beginning of its section on "Write properties:" ----------- In order to use the assignment operator "=" property-style, the property annotation MUST be used. -----------Right, I guess I missed that. -- /Jacob Carlborg
Feb 03 2013
Am Sun, 03 Feb 2013 04:40:44 -0800 schrieb Jonathan M Davis <jmdavisProg gmx.com>:On Sunday, February 03, 2013 13:34:14 Jacob Carlborg wrote:There's a example on the page though which contradicts this: static int x; ref int fun1() { return x; } fun1 = 42;On 2013-02-03 09:16, Andrei Alexandrescu wrote:I take it that you didn't read the DIP. At the very beginning of its section on "Write properties:" ----------- In order to use the assignment operator "=" property-style, the property annotation MUST be used. -----------Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23What about: writeln = "asd"; Allowed or not?
Feb 03 2013
On Sunday, 3 February 2013 at 15:48:00 UTC, Johannes Pfau wrote:That example has nothing to do with properties. It's just: static int x; ref int fun1() { return x; } fun1() = 42; ...except that the empty parens were omitted (which is allowed there).----------- In order to use the assignment operator "=" property-style, the property annotation MUST be used. -----------There's a example on the page though which contradicts this: static int x; ref int fun1() { return x; } fun1 = 42;
Feb 03 2013
Am Sun, 03 Feb 2013 17:01:59 +0100 schrieb "TommiT" <tommitissari hotmail.com>:On Sunday, 3 February 2013 at 15:48:00 UTC, Johannes Pfau wrote:OK, but then 'In order to use the assignment operator "=" property-style, the property annotation MUST be used.' is wrong or a least misleading. IMHO "fun1 = 42;" is using "=" 'property style'. But if you think of it as a parentheses-less call that indeed makes sense.That example has nothing to do with properties. It's just: static int x; ref int fun1() { return x; } fun1() = 42; ...except that the empty parens were omitted (which is allowed there).----------- In order to use the assignment operator "=" property-style, the property annotation MUST be used. -----------There's a example on the page though which contradicts this: static int x; ref int fun1() { return x; } fun1 = 42;
Feb 03 2013
On 2/3/13 10:48 AM, Johannes Pfau wrote:Am Sun, 03 Feb 2013 04:40:44 -0800 schrieb Jonathan M Davis<jmdavisProg gmx.com>:This introduces no contradiction. It's simple assignment to the result of fun1. AndreiOn Sunday, February 03, 2013 13:34:14 Jacob Carlborg wrote:There's a example on the page though which contradicts this: static int x; ref int fun1() { return x; } fun1 = 42;On 2013-02-03 09:16, Andrei Alexandrescu wrote:I take it that you didn't read the DIP. At the very beginning of its section on "Write properties:" ----------- In order to use the assignment operator "=" property-style, the property annotation MUST be used. -----------Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23What about: writeln = "asd"; Allowed or not?
Feb 03 2013
On 2/3/13 7:34 AM, Jacob Carlborg wrote:On 2013-02-03 09:16, Andrei Alexandrescu wrote:No because writeln is not a property. For non-properties there's no lowering of assignment. AndreiWalter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23What about: writeln = "asd"; Allowed or not?
Feb 03 2013
Am Sun, 03 Feb 2013 10:37:45 -0500 schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:On 2/3/13 7:34 AM, Jacob Carlborg wrote:Then this should be removed in the proposal: If a function returns a reference, then assignment through the paren-less call should work: unittest { static int x; ref int fun1() { return x; } fun1 = 42; }On 2013-02-03 09:16, Andrei Alexandrescu wrote:No because writeln is not a property. For non-properties there's no lowering of assignment. AndreiWalter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23What about: writeln = "asd"; Allowed or not?
Feb 03 2013
On 2/3/13 10:49 AM, Johannes Pfau wrote:Am Sun, 03 Feb 2013 10:37:45 -0500 schrieb Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>:No. That's not a lowering. AndreiOn 2/3/13 7:34 AM, Jacob Carlborg wrote:Then this should be removed in the proposal: If a function returns a reference, then assignment through the paren-less call should work: unittest { static int x; ref int fun1() { return x; } fun1 = 42; }On 2013-02-03 09:16, Andrei Alexandrescu wrote:No because writeln is not a property. For non-properties there's no lowering of assignment. AndreiWalter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23What about: writeln = "asd"; Allowed or not?
Feb 03 2013
2013/2/3 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23Awesome!! After reading it, I thought that there is some consistent rules. 1. When a function is annotated with property, it cannot be called with parenthesis syntax. 2. 0-arg functions which not annotated with property can be called without parentheses. 3. Ref return getter can make "auxiliary setter", if formal getter is missing. 4. `typeof(exp)` never returns "function type". In other words, the actual type of `exp` and `typeof(exp)` should be same. 5. Both `&prop` and `&func` should return function pointer / delegate object 6. UFCS CAN NOT call global setter by getter syntax. I think that 4 to 6 are important points of this DIP. Based on the rules, I could write an exhaustive test case. alias Type = int; unittest { struct S { property Type foo(); // formal getter property void bar(Type); // formal setter property ref Type baz(); // ref return getter == auxiliary setter } S s; static assert( __traits(compiles, { s.foo; })); static assert(!__traits(compiles, { s.foo(); })); static assert(is(typeof(s.foo) == Type)); static assert(is(typeof(&s.foo) == Type delegate())); static assert( __traits(compiles, { s.bar = 1; })); static assert(!__traits(compiles, { s.bar(1); })); static assert(is(typeof(s.bar)) == false); static assert(is(typeof(&s.bar) == void delegate(Type))); static assert( __traits(compiles, { s.baz; })); static assert(!__traits(compiles, { s.baz(); })); static assert( __traits(compiles, { s.baz = 1; })); static assert(is(typeof(s.baz) == Type)); static assert(is(typeof(&s.foo) == ref Type delegate())); } unittest { struct S { Type foo(); // 0-arg function void bar(Type n); // 1-arg function ref Type baz(); // 0-arg ref return function } S s; static assert( __traits(compiles, { s.foo; })); static assert( __traits(compiles, { s.foo(); })); static assert(is(typeof(s.foo) == Type)); static assert(is(typeof(&s.foo) == Type delegate())); static assert(!__traits(compiles, { s.bar = 1; })); static assert( __traits(compiles, { s.bar(1); })); static assert(is(typeof(s.bar)) == false); static assert(is(typeof(&s.bar) == void delegate(Type))); static assert( __traits(compiles, { s.baz; })); static assert( __traits(compiles, { s.baz = 1; })); static assert( __traits(compiles, { s.baz(); })); static assert(is(typeof(s.baz) == Type)); static assert(is(typeof(&s.baz) == ref Type delegate())); } property Type foo(); property void bar(Type); property ref Type baz(); unittest { static assert( __traits(compiles, { foo; })); static assert(!__traits(compiles, { foo(); })); static assert(is(typeof(foo) == Type)); static assert(is(typeof(&foo) == Type function())); static assert( __traits(compiles, { bar = 1; })); static assert(!__traits(compiles, { bar(1); })); static assert(is(typeof(bar)) == false); static assert(is(typeof(&bar) == Type function())); static assert( __traits(compiles, { baz; })); static assert(!__traits(compiles, { baz(); })); static assert( __traits(compiles, { baz = 1; })); static assert(!__traits(compiles, { baz() = 1; })); static assert(is(typeof(baz) == Type)); static assert(is(typeof(&baz) == ref Type function())); } property Type foh(Type); property void bah(Type n, Type m); property ref Type bas(Type); Type hoo(Type); void var(Type, Type); ref Type vaz(Type); unittest { static assert( __traits(compiles, { foh = 1; }) && !__traits(compiles, { hoo = 1; })); static assert(!__traits(compiles, { foh(1); }) && __traits(compiles, { hoo(1); })); static assert(!__traits(compiles, { 1.foh; }) && __traits(compiles, { 1.hoo; })); static assert(!__traits(compiles, { 1.foh(); }) && __traits(compiles, { 1.hoo(); })); static assert(!__traits(compiles, { bah(1, 2); }) && __traits(compiles, { var(1, 2); })); static assert( __traits(compiles, { 1.bah = 2; }) && !__traits(compiles, { 1.var = 2; })); static assert(!__traits(compiles, { 1.bah(2); }) && __traits(compiles, { 1.var(2); })); static assert( __traits(compiles, { bas = 1; }) && !__traits(compiles, { vaz = 1; })); static assert(!__traits(compiles, { bas(1); }) && __traits(compiles, { vaz(1); })); static assert(!__traits(compiles, { bas(1) = 2; }) && __traits(compiles, { vaz(1) = 2; })); static assert(!__traits(compiles, { 1.bas; }) && __traits(compiles, { 1.vaz; })); static assert(!__traits(compiles, { 1.bas = 2; }) && __traits(compiles, { 1.vaz = 2; })); static assert(!__traits(compiles, { 1.bas(); }) && __traits(compiles, { 1.vaz(); })); static assert(!__traits(compiles, { 1.bas() = 2; }) && __traits(compiles, { 1.vaz() = 2; })); } Is this correct? Kenji Hara
Feb 03 2013
On 2/3/13 7:37 AM, kenji hara wrote:1. When a function is annotated with property, it cannot be called with parenthesis syntax. 2. 0-arg functions which not annotated with property can be called without parentheses. 3. Ref return getter can make "auxiliary setter", if formal getter is missing. 4. `typeof(exp)` never returns "function type". In other words, the actual type of `exp` and `typeof(exp)` should be same. 5. Both `&prop` and `&func` should return function pointer / delegate object 6. UFCS CAN NOT call global setter by getter syntax.Yah. There is still some inconsistency, but I think there's no way to be 100% consistent. For properties &a.prop is not the same as &(a.prop), which is unlike other expressions.I think that 4 to 6 are important points of this DIP. Based on the rules, I could write an exhaustive test case.I'll insert comments inline.alias Type = int; unittest { struct S { property Type foo(); // formal getter property void bar(Type); // formal setter property ref Type baz(); // ref return getter == auxiliary setter } S s; static assert( __traits(compiles, { s.foo; })); static assert(!__traits(compiles, { s.foo(); })); static assert(is(typeof(s.foo) == Type)); static assert(is(typeof(&s.foo) == Type delegate()));Yes, great. You may want to also add: static assert(!__traits(compiles, { auto p = &(s.foo); })); because that would apply & to the Type rvalue returned by s.foo.static assert( __traits(compiles, { s.bar = 1; })); static assert(!__traits(compiles, { s.bar(1); })); static assert(is(typeof(s.bar)) == false); static assert(is(typeof(&s.bar) == void delegate(Type)));Yes. Also: static assert(is(typeof(s.bar = 1) == void));static assert( __traits(compiles, { s.baz; })); static assert(!__traits(compiles, { s.baz(); })); static assert( __traits(compiles, { s.baz = 1; })); static assert(is(typeof(s.baz) == Type)); static assert(is(typeof(&s.foo) == ref Type delegate()));Yes, assuming you meant "baz" on the last line, too.} unittest { struct S { Type foo(); // 0-arg function void bar(Type n); // 1-arg function ref Type baz(); // 0-arg ref return function } S s; static assert( __traits(compiles, { s.foo; })); static assert( __traits(compiles, { s.foo(); })); static assert(is(typeof(s.foo) == Type)); static assert(is(typeof(&s.foo) == Type delegate()));Correct. Also add: static assert(!is(typeof(&(s.foo))));static assert(!__traits(compiles, { s.bar = 1; })); static assert( __traits(compiles, { s.bar(1); })); static assert(is(typeof(s.bar)) == false); static assert(is(typeof(&s.bar) == void delegate(Type)));Correct. Also: static assert(!is(typeof(&(s.bar)))); because the expression s.bar is meaningless. (This is NEW BEHAVIOR.) The basic idea here is to disallow expressions that can't be typed.static assert( __traits(compiles, { s.baz; })); static assert( __traits(compiles, { s.baz = 1; })); static assert( __traits(compiles, { s.baz(); })); static assert(is(typeof(s.baz) == Type)); static assert(is(typeof(&s.baz) == ref Type delegate())); }Correct. Also: static assert(is(typeof(&(s.baz)) == Type*));property Type foo();I'm not sure we should allow this at module level. (And there is no way to write a corresponding setter.)property void bar(Type); property ref Type baz();I think we should disallow this as well.unittest { static assert( __traits(compiles, { foo; })); static assert(!__traits(compiles, { foo(); })); static assert(is(typeof(foo) == Type)); static assert(is(typeof(&foo) == Type function()));If we disallow top-level global properties neither of these will compile. If we do allow them, then the asserts would pass.static assert( __traits(compiles, { bar = 1; })); static assert(!__traits(compiles, { bar(1); })); static assert(is(typeof(bar)) == false); static assert(is(typeof(&bar) == Type function()));Nope, all of these are getters for int. The following should compile instead: static assert( __traits(compiles, { 1.bar; })); static assert(!__traits(compiles, { bar(1); })); static assert(is(typeof(bar)) == false); static assert(is(typeof(&bar) == void function(int)));static assert( __traits(compiles, { baz; })); static assert(!__traits(compiles, { baz(); })); static assert( __traits(compiles, { baz = 1; })); static assert(!__traits(compiles, { baz() = 1; })); static assert(is(typeof(baz) == Type)); static assert(is(typeof(&baz) == ref Type function()));If we allow top-level properties with 0 parameters, these should inded compile.} property Type foh(Type);This is always a getter for Type returning a Type.property void bah(Type n, Type m);This is always a setter having Type on the left-hand side and Type on the right-hand side.property ref Type bas(Type);This is always a getter for Type.Type hoo(Type); void var(Type, Type); ref Type vaz(Type); unittest { static assert( __traits(compiles, { foh = 1; }) && !__traits(compiles, { hoo = 1; }));No, replace with: static assert( __traits(compiles, { 1.foh; }) && !__traits(compiles, { hoo = 1; }));static assert(!__traits(compiles, { foh(1); }) && __traits(compiles, { hoo(1); }));Correct.static assert(!__traits(compiles, { 1.foh; }) && __traits(compiles, { 1.hoo; }));Incorrect, foh is a getter for Type so the first should work. static assert(__traits(compiles, { 1.foh; }) && __traits(compiles, { 1.hoo; }));static assert(!__traits(compiles, { 1.foh(); }) && __traits(compiles, { 1.hoo(); }));This is identical to the one above.static assert(!__traits(compiles, { bah(1, 2); }) && __traits(compiles, { var(1, 2); }));Correct.static assert( __traits(compiles, { 1.bah = 2; }) && !__traits(compiles, { 1.var = 2; }));Correct.static assert(!__traits(compiles, { 1.bah(2); }) && __traits(compiles, { 1.var(2); }));First expression fails.static assert( __traits(compiles, { bas = 1; }) && !__traits(compiles, { vaz = 1; }));Both branches fail.static assert(!__traits(compiles, { bas(1); }) && __traits(compiles, { vaz(1); }));Correct.static assert(!__traits(compiles, { bas(1) = 2; }) && __traits(compiles, { vaz(1) = 2; }));Correct.static assert(!__traits(compiles, { 1.bas; }) && __traits(compiles, { 1.vaz; }));The first branch fails because 1.bas is legit.static assert(!__traits(compiles, { 1.bas = 2; }) && __traits(compiles, { 1.vaz = 2; }));First branch fails because 1.bas is legit and yields a ref int. Second branch passes.static assert(!__traits(compiles, { 1.bas(); }) && __traits(compiles, { 1.vaz(); }));Correct.static assert(!__traits(compiles, { 1.bas() = 2; }) && __traits(compiles, { 1.vaz() = 2; })); }Correct.Is this correct?As noted above, I might have missed some. I will update the doc with a copy of your unittests. Thanks! Andrei
Feb 03 2013
On 2/3/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:For properties &a.prop is not the same as &(a.prop), which is unlike other expressions.I have an idea. The DIP says that property cannot return a property function. Therefore we could introduce a new built-in property (pardon the pun) that only property functions have, ala: a.prop.addrOf Similar to how we have .funcPtr for other types. This field would only exist for propery functions and therefore it's never ambiguous on whether it applies to the function or to the function call (it *has* to apply to the function since it cannot return a property. So instead of having behavior based on whether there are any parens involved, you would have: &a.prop; // address of return value &(a.prop) // ditto a.prop.addrOf // address of property function
Feb 03 2013
On 2/3/13 12:34 PM, Andrei Alexandrescu wrote:On 2/3/13 7:37 AM, kenji hara wrote:[snip] Copied your unittests with changes and explanations: http://wiki.dlang.org/DIP23#unittest. Please take a look and let me know of what you think! For now I conservatively disallow top-level properties with 0 parameters. I think we can allow them later if there's a strong need. Top-level properties with 1 argument are always getters. We need a bunch more with unittests that return callable entities. Andrei
Feb 03 2013
On 2/3/13, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:So instead of having behavior based on whether there are any parens involved, you would have: &a.prop; // address of return value &(a.prop) // ditto a.prop.addrOf // address of property functionSo, thoughts on this?
Feb 03 2013
On 02/03/2013 09:16 AM, Andrei Alexandrescu wrote:Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 ...Looks good. Two things: What about eg: property T front(T)(T[] arr){ return arr[0]; } And: "Avoid embarrassing situations such as expressions with unexpressible types or no-op address-of operator (as is the case with C functions)." The DIP does not fix the first issue. pragma(msg, typeof(*(int x)=>x)); // pure nothrow safe int(int x)
Feb 03 2013
On 2/3/13 7:59 AM, Timon Gehr wrote:On 02/03/2013 09:16 AM, Andrei Alexandrescu wrote:I updated the doc to clarify that one-parameter properties are ALWAYS getters and two-parameter properties are ALWAYS setters.Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 ...Looks good. Two things: What about eg: property T front(T)(T[] arr){ return arr[0]; }And: "Avoid embarrassing situations such as expressions with unexpressible types or no-op address-of operator (as is the case with C functions)." The DIP does not fix the first issue. pragma(msg, typeof(*(int x)=>x)); // pure nothrow safe int(int x)I see. I think dereferencing a function or delegate type should never work. Andrei
Feb 03 2013
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:We also understand it's impossible to reconcile all viewpoints and please all tastes. Our hope is to get to a point where the rules are self-consistent, meaningful, and complete.Should we add also non ambiguous ? I think everyone should agree upon your last paragraph.
Feb 03 2013
On 2013-02-03 09:16, Andrei Alexandrescu wrote:Walter and I have had a discussion on how to finalize properties.Very reasonable in the majority of the proposal. I can't, however, get my head around 2-arg property functions: int a_; property void a(int v, bool rev=false) { a_ = rev ? -v : v; } a = 10; // fine 10.a = true; // this feels backwards, true is just an extra flag The boolean flag is optional and making it the rhs of the assignment suggests it is the value which will be set. On the other hand switching argument positions, resulting in true.a = 10 also feels very strange. I'd say: allow only 0 or 1 argument in properties. If you need more arguments, write a normal function for it.
Feb 03 2013
2013/2/3 FG <home fgda.pl>On 2013-02-03 09:16, Andrei Alexandrescu wrote:Two arguments property function would be declared only in module level, and just be called with UFCS. I think that functions annotated with property must not have default parameters. As you show, it would introduce not little ambiguity. Kenji HaraWalter and I have had a discussion on how to finalize properties.Very reasonable in the majority of the proposal. I can't, however, get my head around 2-arg property functions: int a_; property void a(int v, bool rev=false) { a_ = rev ? -v : v; } a = 10; // fine 10.a = true; // this feels backwards, true is just an extra flag The boolean flag is optional and making it the rhs of the assignment suggests it is the value which will be set. On the other hand switching argument positions, resulting in true.a = 10 also feels very strange. I'd say: allow only 0 or 1 argument in properties. If you need more arguments, write a normal function for it.
Feb 03 2013
On 2013-02-03 14:33, kenji hara wrote:Two arguments property function would be declared only in module level, and just be called with UFCS. I think that functions annotated with property must not have default parameters. As you show, it would introduce not little ambiguity.With such constraints two argument property functions are fine, as long as it is their second argument that is most significant in the assignment. The DIP's 42.fun = 43 is the ideal counter-example of that. :)
Feb 03 2013
On 2/3/13 8:16 AM, FG wrote:On 2013-02-03 09:16, Andrei Alexandrescu wrote:I'd say never allow defaulted arguments with property.Walter and I have had a discussion on how to finalize properties.Very reasonable in the majority of the proposal. I can't, however, get my head around 2-arg property functions: int a_; property void a(int v, bool rev=false) { a_ = rev ? -v : v; }a = 10; // fine 10.a = true; // this feels backwards, true is just an extra flag The boolean flag is optional and making it the rhs of the assignment suggests it is the value which will be set. On the other hand switching argument positions, resulting in true.a = 10 also feels very strange. I'd say: allow only 0 or 1 argument in properties. If you need more arguments, write a normal function for it.Two-argument properties are always setters. Andrei
Feb 03 2013
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 [..]What happens here? struct S { int _n; property ref int prop() { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
Feb 03 2013
On Sun, 03 Feb 2013 10:35:29 -0500, TommiT <tommitissari hotmail.com> wrote:On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:I would expect it to call S.prop, not the global prop. If not, that should be a bug (Kenji, you should add this case to the tests if not already there) With UFCS, you cannot override type-specified methods and properties. -SteveWalter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 [..]What happens here? struct S { int _n; property ref int prop() { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
Feb 03 2013
On 2013-02-03 16:35, TommiT wrote:What happens here? struct S { int _n; property ref int prop() { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }This is an interesting problem. 1) I think setters should outrank getters when there's an assignment. 2) Also actual methods outrank UFCS free functions with same arguments. It's a question which rule has higher precedence. I think no.2 does and then _n becomes 10.
Feb 03 2013
On 2/3/13 10:35 AM, TommiT wrote:On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:The member is chosen. AndreiWalter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 [..]What happens here? struct S { int _n; property ref int prop() { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
Feb 03 2013
On Sunday, 3 February 2013 at 17:46:00 UTC, Andrei Alexandrescu wrote:On 2/3/13 10:35 AM, TommiT wrote:What happens in these examples? Example 1: struct S { int _n; property ref const(int) prop() const { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; } -------------------------------------------- Example 2: struct T { int _n; disable void opAssign(T rhs) { } } struct S { T _t; property ref T prop() { return _t; } } property void prop(ref S s, T t) { s._t._n = t._n; } void main() { S s; s.prop = T.init; }On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:The member is chosen. AndreiWalter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 [..]What happens here? struct S { int _n; property ref int prop() { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
Feb 03 2013
On 2/3/13 1:14 PM, TommiT wrote:Example 1: struct S { int _n; property ref const(int) prop() const { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }This is a matter of visibility. The presence of a member precludes any UFCS. Won't compile. Same for the 2nd example. Andrei
Feb 03 2013
On Sunday, 3 February 2013 at 18:28:06 UTC, Andrei Alexandrescu wrote:[..] This is a matter of visibility. The presence of a member precludes any UFCS. Won't compile. Same for the 2nd example.Just to be perfectly clear, it must be that this wouldn't compile either, right? struct S { int _n; property int prop() const { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
Feb 03 2013
On 2/3/13 1:32 PM, TommiT wrote:On Sunday, 3 February 2013 at 18:28:06 UTC, Andrei Alexandrescu wrote:Nope. Andrei[..] This is a matter of visibility. The presence of a member precludes any UFCS. Won't compile. Same for the 2nd example.Just to be perfectly clear, it must be that this wouldn't compile either, right? struct S { int _n; property int prop() const { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
Feb 03 2013
On Sun, 03 Feb 2013 13:42:57 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 2/3/13 1:32 PM, TommiT wrote:He means "Nope it wouldn't compile" in case that was confusing ;) In general, functions must be overloaded within the same visibility level/scope. If there is one overload at a level, ALL overloads must exist at that level, or they are not seen. -SteveOn Sunday, 3 February 2013 at 18:28:06 UTC, Andrei Alexandrescu wrote:Nope.[..] This is a matter of visibility. The presence of a member precludes any UFCS. Won't compile. Same for the 2nd example.Just to be perfectly clear, it must be that this wouldn't compile either, right? struct S { int _n; property int prop() const { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
Feb 03 2013
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:In brief: * Optional parens stay.This syntax sugar only helps in chained-UFCS calling. Why allowing it everywhere, that is even if the function's name is not followed by a dot? like this: Obj1.action1.action2.action3(); It is clearer than Obj1.action1().action2().action3(); and, still, does not allow something like Obj1.action1; requiring an Obj1.action1(); instead.* Just mentioning a function or method without parens does NOT automatically take its address. (This is a change from the current behavior.)If you stick to the above "optional only if followed by a dot"-paradigm, you could maintain the behavior, except in that UFCS-chains, where it doesn't matter anyway what mentioning a function or method without parens returns, since one assumes invocation in this kind of chains.* Read properties (using property) work as expected with the mention that they may NOT be called with the parens. Any parens would apply to the returned value.And if the returned value is a parameterless function, shouldn't that be callable without parens?* Write properties (using property) may only be used in the assignment form (no function-style call allowed).
Feb 03 2013
On 02/03/2013 11:24 PM, eles wrote:On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:Nope. a.map!(a=>2*a);In brief: * Optional parens stay.This syntax sugar only helps in chained-UFCS calling. ......No, it shouldn't. The rewrite is (rightfully) not applicable to expressions of first class function types. The only reason why the implicit calling and property approaches are workable is because the language also supports non first class functions (inherited directly from C).* Read properties (using property) work as expected with the mention that they may NOT be called with the parens. Any parens would apply to the returned value.And if the returned value is a parameterless function, shouldn't that be callable without parens? ...
Feb 03 2013
On 02/03/2013 09:16 AM, Andrei Alexandrescu wrote:... * Just mentioning a function or method without parens does NOT automatically take its address. (This is a change from the current behavior.)(No, it is not.) From the DIP: "This proposal sustains that optional parentheses should stay in. That means, if a function or method may be called without arguments, the trailing parens may be omitted. [...] The same goes about methods: [...] However, that's not the case with function objects, delegate objects, or objects that implement the function call operator. [...]" Should also mention static opCall. The section does not mention what happens with first class callables that are invoked via UFCS. In particular, the validity of eg. the following code (which currently is valid) is not specified: enum foo = (int x)=>x; static assert(2==2.foo);
Feb 03 2013
On Sun, Feb 03, 2013 at 03:16:08AM -0500, Andrei Alexandrescu wrote:Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23[...] +1. I think this proposal (1) addresses the most important issues with the current implementation of property, and (2) is probably one of the simplest ways to fix current issues without introducing too many changes and new features. I vote for this. T -- Having a smoking section in a restaurant is like having a peeing section in a swimming pool. -- Edward Burr
Feb 03 2013
On 2/3/13 3:16 AM, Andrei Alexandrescu wrote: [snip] Some more thinking got me to three simple principles that guide the proposed property design: http://wiki.dlang.org/DIP23#In_a_nutshell I think most, if not all, detailed rules derive from these. Andrei
Feb 03 2013
On Sun, Feb 03, 2013 at 08:30:48PM -0500, Andrei Alexandrescu wrote:On 2/3/13 3:16 AM, Andrei Alexandrescu wrote: [snip] Some more thinking got me to three simple principles that guide the proposed property design: http://wiki.dlang.org/DIP23#In_a_nutshell I think most, if not all, detailed rules derive from these.[...] This is precisely the kind of simplicity we need to resolve this issue. I fully concur. T -- 2+2=4. 2*2=4. 2^2=4. Therefore, +, *, and ^ are the same operation.
Feb 03 2013
On Sunday, February 03, 2013 20:30:48 Andrei Alexandrescu wrote:On 2/3/13 3:16 AM, Andrei Alexandrescu wrote: [snip] Some more thinking got me to three simple principles that guide the proposed property design: http://wiki.dlang.org/DIP23#In_a_nutshell I think most, if not all, detailed rules derive from these.Technically, the bit about having exactly one or exactly two parameters is wrong, unless you're counting the invisible this pointer/reference in that. Member property functions end up with exactly zero or exactly one parameters. - Jonathan M Davis
Feb 03 2013
On 2013-02-04 02:56, Jonathan M Davis wrote:Technically, the bit about having exactly one or exactly two parameters is wrong, unless you're counting the invisible this pointer/reference in that. Member property functions end up with exactly zero or exactly one parameters.I don't know if the text has been update since you read it but it says: "counting the implicit this parameter if at all". -- /Jacob Carlborg
Feb 04 2013
On Monday, 4 February 2013 at 01:30:49 UTC, Andrei Alexandrescu wrote:I think most, if not all, detailed rules derive from these.One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)". There is no way such strange behavior could be explained in a way that is coherent with the rest of the language. I found that when you are working on a complex problem and have a solution that seems to work for everything except a little detail, the best approach often is to step back a bit and have an entirely fresh look at that area again, but now taking the rest of your design as a given. Introducing a rule by which parenthesizing an expression in a way that does not change precedence suddenly causes a difference in behavior certainly wouldn't be among the first ideas coming to my mind this way. David
Feb 03 2013
On Monday, 4 February 2013 at 02:18:08 UTC, David Nadlinger wrote:On Monday, 4 February 2013 at 01:30:49 UTC, Andrei Alexandrescu wrote:As another data point, Walter wrote a while ago himself: »I'm just arguing against the e and (e) solution as (perhaps) causing more ambiguity problems«. DavidI think most, if not all, detailed rules derive from these.One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)". There is no way su<ch strange behavior could be explained in a way that is coherent with the rest of the language.
Feb 03 2013
On Monday, 4 February 2013 at 02:18:08 UTC, David Nadlinger wrote:On Monday, 4 February 2013 at 01:30:49 UTC, Andrei Alexandrescu wrote:The problem we are dealing with here isn't complex. It is made complex artificially. We are trying to make properties behave like fields, but hey in this case I want it to behave like a function . . . oh yeah so in this special case, I have to workaround, ho and here and here as well, oh damn, that is complicated. Same goes when conflating the function with it's return value (which optional () is about).I think most, if not all, detailed rules derive from these.One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)". There is no way such strange behavior could be explained in a way that is coherent with the rest of the language. I found that when you are working on a complex problem and have a solution that seems to work for everything except a little detail, the best approach often is to step back a bit and have an entirely fresh look at that area again, but now taking the rest of your design as a given.Introducing a rule by which parenthesizing an expression in a way that does not change precedence suddenly causes a difference in behavior certainly wouldn't be among the first ideas coming to my mind this way.By trying to make things easy, we miss that the important point is to make them simple.
Feb 03 2013
On 02/04/2013 03:28 AM, deadalnix wrote:On Monday, 4 February 2013 at 02:18:08 UTC, David Nadlinger wrote:It is not even made complex. It is quite obvious how things should work. (and &a vs &(a) is not it.)On Monday, 4 February 2013 at 01:30:49 UTC, Andrei Alexandrescu wrote:The problem we are dealing with here isn't complex. It is made complex artificially.I think most, if not all, detailed rules derive from these.One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)". There is no way such strange behavior could be explained in a way that is coherent with the rest of the language. I found that when you are working on a complex problem and have a solution that seems to work for everything except a little detail, the best approach often is to step back a bit and have an entirely fresh look at that area again, but now taking the rest of your design as a given.We are trying to make properties behave like fields,(Syntactically.)but hey in this case I want it to behave like a function . . .This is the step that must be reconsidered.oh yeah so in this special case, I have to workaround, ho and here and here as well, oh damn, that is complicated. Same goes when conflating the function with it's return value (which optional () is about).Certainly not! & is the syntactic element distinguishing functions from return values, not (). Optional & would be about conflating the function with its return value. (Scala basically does this, but instead of prefix & they use suffix _.)Most of this stuff is simple enough. Have you implemented optional parens already?Introducing a rule by which parenthesizing an expression in a way that does not change precedence suddenly causes a difference in behavior certainly wouldn't be among the first ideas coming to my mind this way.By trying to make things easy, we miss that the important point is to make them simple.
Feb 03 2013
On Monday, 4 February 2013 at 02:28:39 UTC, deadalnix wrote:On Monday, 4 February 2013 at 02:18:08 UTC, David Nadlinger wrote:Not sure I'm following – you are arguing that the whole endeavor is futile as long as we keep parens-less function calls? I actually think that DIP23 is a big step in the right direction, given that parens-less function calls are *very* unlikely to go away. Contrary to some of the previous proposals, it's actually a principled approach, like Adam and others (including me) have asked for. Now it's just a matter of getting the details right.On Monday, 4 February 2013 at 01:30:49 UTC, Andrei Alexandrescu wrote:The problem we are dealing with here isn't complex. It is made complex artificially. We are trying to make properties behave like fields, but hey in this case I want it to behave like a function . . . oh yeah so in this special case, I have to workaround, ho and here and here as well, oh damn, that is complicated. Same goes when conflating the function with it's return value (which optional () is about).I think most, if not all, detailed rules derive from these.One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)". There is no way such strange behavior could be explained in a way that is coherent with the rest of the language. I found that when you are working on a complex problem and have a solution that seems to work for everything except a little detail, the best approach often is to step back a bit and have an entirely fresh look at that area again, but now taking the rest of your design as a given.My point is precisely that. I think there are much simpler solutions than adding some magic properties to a pair of parentheses in the right position, even if it might look like a convenient hack. DavidIntroducing a rule by which parenthesizing an expression in a way that does not change precedence suddenly causes a difference in behavior certainly wouldn't be among the first ideas coming to my mind this way.By trying to make things easy, we miss that the important point is to make them simple.
Feb 03 2013
On 2/3/13 9:58 PM, David Nadlinger wrote:My point is precisely that. I think there are much simpler solutions than adding some magic properties to a pair of parentheses in the right position, even if it might look like a convenient hack.I don't think it's a hack at all. Think it over, and compare it with the language semantics even today. Andrei
Feb 03 2013
On Monday, 4 February 2013 at 03:13:07 UTC, Andrei Alexandrescu wrote:On 2/3/13 9:58 PM, David Nadlinger wrote:I've done that. What about *you* thinking it over? :PMy point is precisely that. I think there are much simpler solutions than adding some magic properties to a pair of parentheses in the right position, even if it might look like a convenient hack.I don't think it's a hack at all. Think it over, […]and compare it with the language semantics even today.I thought we agreed that today's semantics are hopelessly broken. Actually, we might already have some of the &a vs. &(a) stuff, I remember Kenji opening a pull request about that at some point, but don't know if it went in OTOH. David
Feb 03 2013
On Monday, 4 February 2013 at 03:13:07 UTC, Andrei Alexandrescu wrote:On 2/3/13 9:58 PM, David Nadlinger wrote:Going from complete crap to bearable don't make bearable good.My point is precisely that. I think there are much simpler solutions than adding some magic properties to a pair of parentheses in the right position, even if it might look like a convenient hack.I don't think it's a hack at all. Think it over, and compare it with the language semantics even today.
Feb 03 2013
On 02/04/2013 05:21 AM, deadalnix wrote:On Monday, 4 February 2013 at 03:13:07 UTC, Andrei Alexandrescu wrote:In what way is this bearable?On 2/3/13 9:58 PM, David Nadlinger wrote:Going from complete crap to bearable don't make bearable good.My point is precisely that. I think there are much simpler solutions than adding some magic properties to a pair of parentheses in the right position, even if it might look like a convenient hack.I don't think it's a hack at all. Think it over, and compare it with the language semantics even today.
Feb 04 2013
On Monday, 4 February 2013 at 13:12:54 UTC, Timon Gehr wrote:On 02/04/2013 05:21 AM, deadalnix wrote:The proposal is a big improvement over current behavior. Still it has major flaws, like the way & and property interact.On Monday, 4 February 2013 at 03:13:07 UTC, Andrei Alexandrescu wrote:In what way is this bearable?On 2/3/13 9:58 PM, David Nadlinger wrote:Going from complete crap to bearable don't make bearable good.My point is precisely that. I think there are much simpler solutions than adding some magic properties to a pair of parentheses in the right position, even if it might look like a convenient hack.I don't think it's a hack at all. Think it over, and compare it with the language semantics even today.
Feb 04 2013
On 02/04/2013 04:13 AM, Andrei Alexandrescu wrote:On 2/3/13 9:58 PM, David Nadlinger wrote:It is a horrible hack. Why is this not obvious?My point is precisely that. I think there are much simpler solutions than adding some magic properties to a pair of parentheses in the right position, even if it might look like a convenient hack.I don't think it's a hack at all.Think it over, and compare it with the language semantics even today.I am intimately familiar with today's language semantics as I am writing a D compiler front end. Please be more explicit.
Feb 04 2013
On 2/4/13 9:34 AM, Timon Gehr wrote:On 02/04/2013 04:13 AM, Andrei Alexandrescu wrote:I think it's because it's a matter in which reasonable people may disagree. AndreiOn 2/3/13 9:58 PM, David Nadlinger wrote:It is a horrible hack. Why is this not obvious?My point is precisely that. I think there are much simpler solutions than adding some magic properties to a pair of parentheses in the right position, even if it might look like a convenient hack.I don't think it's a hack at all.
Feb 04 2013
On 2/4/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I think it's because it's a matter in which reasonable people may disagree.Well, Walter seemed to agree with us before: d.puremagic.com/issues/show_bug.cgi?id=9062#c13 And even Kenji who likes it seemed to close his pull: https://github.com/D-Programming-Language/dmd/pull/1310#issuecomment-12524998 I don't know what changed their opinions now.
Feb 04 2013
On Monday, 4 February 2013 at 02:58:55 UTC, David Nadlinger wrote:Not sure I'm following – you are arguing that the whole endeavor is futile as long as we keep parens-less function calls? I actually think that DIP23 is a big step in the right direction, given that parens-less function calls are *very* unlikely to go away. Contrary to some of the previous proposals, it's actually a principled approach, like Adam and others (including me) have asked for. Now it's just a matter of getting the details right.My point is that we try to pack fundamentally different concept into one. Which is doomed to produce a three headed monster.My point is precisely that. I think there are much simpler solutions than adding some magic properties to a pair of parentheses in the right position, even if it might look like a convenient hack.Convenient hack is not good design.
Feb 03 2013
On 2/3/13 9:17 PM, David Nadlinger wrote:On Monday, 4 February 2013 at 01:30:49 UTC, Andrei Alexandrescu wrote:Andrej's proposal is nice, but I think you're wrong about this. We're already there - &a.b means something (a delegate) which is not decomposable into smaller parts.I think most, if not all, detailed rules derive from these.One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)".There is no way such strange behavior could be explained in a way that is coherent with the rest of the language.I disagree.I found that when you are working on a complex problem and have a solution that seems to work for everything except a little detail, the best approach often is to step back a bit and have an entirely fresh look at that area again, but now taking the rest of your design as a given.I agree with the general thought.Introducing a rule by which parenthesizing an expression in a way that does not change precedence suddenly causes a difference in behavior certainly wouldn't be among the first ideas coming to my mind this way.I really think you are wrong about this. Parenthesizing has nothing to do with this. &a.b is punctuation that creates an indivizible unit. Andrei
Feb 03 2013
On Monday, 4 February 2013 at 03:11:25 UTC, Andrei Alexandrescu wrote:Then I'm eager to hear your explanation. Parentheses in an expression usually change precedence. Here they do something entirely different.There is no way such strange behavior could be explained in a way that is coherent with the rest of the language.I disagree.a.b already is an indivisible unit, the result of the function call. DavidIntroducing a rule by which parenthesizing an expression in a way that does not change precedence suddenly causes a difference in behavior certainly wouldn't be among the first ideas coming to my mind this way.I really think you are wrong about this. Parenthesizing has nothing to do with this. &a.b is punctuation that creates an indivizible unit.
Feb 03 2013
On Monday, 4 February 2013 at 03:15:51 UTC, David Nadlinger wrote:On Monday, 4 February 2013 at 03:11:25 UTC, Andrei Alexandrescu wrote:Actually, let me illustrate this point a bit further, sorry for the hasty reply. The problem I see is that usually, one can insert grouping pairs of parentheses into an expression according to the operator precedence/associativity rules at will without changing the result. This isn't merely a theoretical exercise, but the way (well, in the form of trees) I tend to reason about source code intuitively. Now, grouping the expression »&a.b« according to the precedence rules yields »&(a.b)« – but in your proposal, they mean completely different things. You could argue that &<expression>.<identifier> is a special construct different from the normal address-of operator. But where do you mentally draw the line? What about &a.b.c <-> &(a.b).c <-> &((a.b).c)? &(a + b).c <-> &((a + b).c)? Again, from an user's perspective the change in behavior seems to be completely at odds with the usual rule in C-family languages that grouping parens can be added without changing the meaning of an expression. Thus, this part of the proposed syntax strikes me as being extremely misleading, which is especially bad because the situation with the two possible meanings is confusing enough to start out with already. And how often do you think you'll find yourself in the situation of needing to get a delegate from a property anyway? Can't we just make » property getter expressions are always equivalent to their return value« a hard (simple!) rule and add something like __traits(propertyGetter, ...) for the rare cases where you really need to get hold of the underlying function? DavidI really think you are wrong about this. Parenthesizing has nothing to do with this. &a.b is punctuation that creates an indivizible unit.a.b already is an indivisible unit, the result of the function call.
Feb 03 2013
On Monday, 4 February 2013 at 04:00:28 UTC, David Nadlinger wrote:On Monday, 4 February 2013 at 03:15:51 UTC, David Nadlinger wrote: And how often do you think you'll find yourself in the situation of needing to get a delegate from a property anyway? Can't we just make » property getter expressions are always equivalent to their return value« a hard (simple!) rule and add something like __traits(propertyGetter, ...) for the rare cases where you really need to get hold of the underlying function? DavidI like this solution; it follows the Principle of Least Surprise quite well. The syntax may be a bit longer, but it's immediately obvious even to a beginning/intermediate D user what's going on without having to worry about too many nuances.
Feb 03 2013
On 2/3/13 11:17 PM, BLM768 wrote:On Monday, 4 February 2013 at 04:00:28 UTC, David Nadlinger wrote:This is a good point, and __traits make all possible syntactic confusion go away. AndreiOn Monday, 4 February 2013 at 03:15:51 UTC, David Nadlinger wrote: And how often do you think you'll find yourself in the situation of needing to get a delegate from a property anyway? Can't we just make » property getter expressions are always equivalent to their return value« a hard (simple!) rule and add something like __traits(propertyGetter, ...) for the rare cases where you really need to get hold of the underlying function? DavidI like this solution; it follows the Principle of Least Surprise quite well. The syntax may be a bit longer, but it's immediately obvious even to a beginning/intermediate D user what's going on without having to worry about too many nuances.
Feb 03 2013
On Monday, February 04, 2013 05:00:21 David Nadlinger wrote:On Monday, 4 February 2013 at 03:15:51 UTC, David Nadlinger wrote:enceOn Monday, 4 February 2013 at 03:11:25 UTC, Andrei Alexandrescu =20 wrote:=20 Actually, let me illustrate this point a bit further, sorry for the hasty reply. =20 The problem I see is that usually, one can insert grouping pairs of parentheses into an expression according to the operator precedence/associativity rules at will without changing the result. This isn't merely a theoretical exercise, but the way (well, in the form of trees) I tend to reason about source code intuitively. =20 Now, grouping the expression =C2=BB&a.b=C2=AB according to the preced=I really think you are wrong about this. Parenthesizing has nothing to do with this. &a.b is punctuation that creates an indivizible unit.=20 a.b already is an indivisible unit, the result of the function call.rules yields =C2=BB&(a.b)=C2=AB =E2=80=93 but in your proposal, they =meancompletely different things. =20 You could argue that &<expression>.<identifier> is a special construct different from the normal address-of operator. But where do you mentally draw the line? What about &a.b.c <-> &(a.b).c <-> &((a.b).c)? &(a + b).c <-> &((a + b).c)? =20 Again, from an user's perspective the change in behavior seems to be completely at odds with the usual rule in C-family languages that grouping parens can be added without changing the meaning of an expression. Thus, this part of the proposed syntax strikes me as being extremely misleading, which is especially bad because the situation with the two possible meanings is confusing enough to start out with already. =20 And how often do you think you'll find yourself in the situation of needing to get a delegate from a property anyway? Can't we just make =C2=BB property getter expressions are always equivalent to=their return value=C2=AB a hard (simple!) rule and add something like=__traits(propertyGetter, ...) for the rare cases where you really need to get hold of the underlying function?I tend to agree that making the parens change the nature of the express= ion is=20 a bad idea. I'm also concerned that making it legal to take the address= of a=20 property function is going to cause serious issues when anyone tries to= =20 actually try and swap between variables and property functions. But the= re's=20 also the issue of it not being terribly common to need the address of a= =20 property function. The biggest concern there would be what happens when= =20 someone takes the address of a variable which then gets turned into a=20= property. It's not going to work, and the way that that it doesn't work= is=20 going to vary depending on what & does on a property function and what = they're=20 trying to assign it to. - Jonathan M Davis
Feb 03 2013
On 2/3/13 11:31 PM, Jonathan M Davis wrote:I tend to agree that making the parens change the nature of the expression is a bad idea.I think there's some misunderstanding here. Parens change the nature of expressions ALL the time. There is a weird rule in C++11 that makes sometimes typeof(expr) and typeof((expr)) mean different things. That is arguably an example to avoid. But introducing parens among parts of an expression is expected to affect meaning. Andrei
Feb 03 2013
On Monday, 4 February 2013 at 05:36:10 UTC, Andrei Alexandrescu wrote:On 2/3/13 11:31 PM, Jonathan M Davis wrote:Weird behaviors of C++ are a very good reason to have D in the first place.I tend to agree that making the parens change the nature of the expression is a bad idea.I think there's some misunderstanding here. Parens change the nature of expressions ALL the time. There is a weird rule in C++11 that makes sometimes typeof(expr) and typeof((expr)) mean different things. That is arguably an example to avoid. But introducing parens among parts of an expression is expected to affect meaning.
Feb 03 2013
On 02/04/2013 06:36 AM, Andrei Alexandrescu wrote:On 2/3/13 11:31 PM, Jonathan M Davis wrote:Agreed.I tend to agree that making the parens change the nature of the expression is a bad idea.I think there's some misunderstanding here.Parens change the nature of expressions ALL the time.In D? No way. Precedence rules are introduced in order to make parens _implicit_. In a language with unary & and binary ., There are two possible interpretations for &a.b: (&a).b &(a.b) In the case of D, &a.b is just a shortcut for &(a.b). How can they denote different things?There is a weird rule in C++11 that makes sometimes typeof(expr) and typeof((expr)) mean different things.There is also the argument-dependent name lookup thing namespace bar{ struct S{} baz; S foo(S x){ return x; } } int main(){ foo(bar::baz); // Koenig lookup finds bar::foo (foo)(bar::baz); // no Koenig lookup, foo undefined } Not examples to follow.That is arguably an example to avoid. But introducing parens among parts of an expression is expected to affect meaning.Sure, but that is not what happens here at all. The parens are introduced around ONE part of the expression.
Feb 04 2013
On 2/3/13 11:00 PM, David Nadlinger wrote:The problem I see is that usually, one can insert grouping pairs of parentheses into an expression according to the operator precedence/associativity rules at will without changing the result. This isn't merely a theoretical exercise, but the way (well, in the form of trees) I tend to reason about source code intuitively.Well this is going to sound bad, but you either use reason or intuition. I don't see how one can reason intuitively.Now, grouping the expression »&a.b« according to the precedence rules yields »&(a.b)« – but in your proposal, they mean completely different things.I agree they mean different things. I'm unclear that's a problem. All your examples stop here, there's no propagation of the issue. To take the address of a property, one writes &obj.prop. To take the address of a property's result, one writes &(obj.prop). And that's that. It all works with typeof.You could argue that &<expression>.<identifier> is a special construct different from the normal address-of operator. But where do you mentally draw the line? What about &a.b.c <-> &(a.b).c <-> &((a.b).c)? &(a + b).c <-> &((a + b).c)?That argument is easily destroyed. In a.b.c, a.b is the expression and c is the property name.Again, from an user's perspective the change in behavior seems to be completely at odds with the usual rule in C-family languages that grouping parens can be added without changing the meaning of an expression.I think we avoid much more bizarre things that way, such that expr and &expr meaning sometimes the same exact thing. Or that we have expressions without a type. And nobody blinks an eye. I just think we're better off.Thus, this part of the proposed syntax strikes me as being extremely misleading, which is especially bad because the situation with the two possible meanings is confusing enough to start out with already. And how often do you think you'll find yourself in the situation of needing to get a delegate from a property anyway? Can't we just make » property getter expressions are always equivalent to their return value« a hard (simple!) rule and add something like __traits(propertyGetter, ...) for the rare cases where you really need to get hold of the underlying function?I don't see where the trouble is. If I thought the trait is necessary, I'd make it part of the proposal. Currently I don't see it as necessary, but I definitely can be convinced. Andrei
Feb 03 2013
2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>On 2/3/13 11:00 PM, David Nadlinger wrote:ce rulesNow, grouping the expression =C2=BB&a.b=C2=AB according to the preceden=letely differentyields =C2=BB&(a.b)=C2=AB =E2=80=93 but in your proposal, they mean comp=rthings.I agree they mean different things. I'm unclear that's a problem. All you=examples stop here, there's no propagation of the issue. To take the address of a property, one writes &obj.prop. To take the address of a property's result, one writes &(obj.prop). And that's that. It all works with typeof.If the expression is generated from string mixin, might have a problem. // This is much simple case. Real example might be more complicated. template AddressOf(string exp) { enum AddressOf =3D "&" ~ exp; } struct S { property int prop() { return 1; } } void main() { S s; assert(s.prop =3D=3D 1); int* p =3D mixin(AddressOf!("s.prop")); // &s.prop returns delegate } I think that parenthesis-dependent syntax is not good. Kenji Hara
Feb 03 2013
On 2/4/13 12:53 AM, kenji hara wrote:If the expression is generated from string mixin, might have a problem. // This is much simple case. Real example might be more complicated. template AddressOf(string exp) { enum AddressOf = "&" ~ exp; } struct S { property int prop() { return 1; } } void main() { S s; assert(s.prop == 1); int* p = mixin(AddressOf!("s.prop")); // &s.prop returns delegate } I think that parenthesis-dependent syntax is not good. Kenji HaraCouldn't AddressOf use "&(" + exp + ")"? I thought more about this. The problem remains even without property, due to optional parens in function invocation. Consider: ref int fun() { ... } auto p1 = &fun; auto p2 = &(fun); auto p3 = &(fun()); What are the types of the three? The optional parens in invocation require some disambiguation. I think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result. I would agree restricting the properties, but requiring a __trait to take the address of a regular function or method seems overkill. Andrei
Feb 04 2013
On 02/04/2013 03:05 PM, Andrei Alexandrescu wrote:... Couldn't AddressOf use "&(" + exp + ")"? I thought more about this. The problem remains even without property, due to optional parens in function invocation. Consider: ref int fun() { ... } auto p1 = &fun; auto p2 = &(fun); auto p3 = &(fun()); What are the types of the three? The optional parens in invocation require some disambiguation.The obvious rule is not to give significance to redundant parentheses.I think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result.No! &fun and &(fun) are the same thing. Functions that get their address taken are not implicitly invoked. (Again, Scala agrees.) The rules are straightforward: A non- property function name 'foo' denotes a function invocation without arguments iff it does not occur in one of the following contexts: 1. foo(...) // explicitly called 2. &foo // address taken 3. ...!(...,foo,...) // template argument (well, that's what DMD currently does) 4. alias ... = foo; // aliasedI would agree restricting the properties, but requiring a __trait to take the address of a regular function or method seems overkill.I have no idea how the conclusion would be reached that this is necessary under any of the discussed schemes.
Feb 04 2013
On Monday, 4 February 2013 at 14:25:10 UTC, Timon Gehr wrote:On 02/04/2013 03:05 PM, Andrei Alexandrescu wrote:Scala don't really agree. fun is the function pointer. It is evaluated if the function pointer is a NOOP, but that's it. Here is scala semantic with D syntax : void bar() {} bar; // execute bar. Is an exception because taking the function pointer is a NOOP. void foo(void function() bar) {} foo(bar); // OK, bar is not evaluated.... Couldn't AddressOf use "&(" + exp + ")"? I thought more about this. The problem remains even without property, due to optional parens in function invocation. Consider: ref int fun() { ... } auto p1 = &fun; auto p2 = &(fun); auto p3 = &(fun()); What are the types of the three? The optional parens in invocation require some disambiguation.The obvious rule is not to give significance to redundant parentheses.I think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result.No! &fun and &(fun) are the same thing. Functions that get their address taken are not implicitly invoked. (Again, Scala agrees.)
Feb 04 2013
On 02/04/2013 04:02 PM, deadalnix wrote:On Monday, 4 February 2013 at 14:25:10 UTC, Timon Gehr wrote:Of course Scala agrees. scala> def foo() = 2 foo: ()Int scala> foo res0: Int = 2 scala> foo _ res1: () => Int = <function0> scala> (foo) _ res2: () => Int = <function0> scala> def bar[A](arg : A) = arg bar: [A](arg: A)A scala> bar(foo) res3: Int = 2On 02/04/2013 03:05 PM, Andrei Alexandrescu wrote:Scala don't really agree. fun is the function pointer. It is evaluated if the function pointer is a NOOP, but that's it.... Couldn't AddressOf use "&(" + exp + ")"? I thought more about this. The problem remains even without property, due to optional parens in function invocation. Consider: ref int fun() { ... } auto p1 = &fun; auto p2 = &(fun); auto p3 = &(fun()); What are the types of the three? The optional parens in invocation require some disambiguation.The obvious rule is not to give significance to redundant parentheses.I think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result.No! &fun and &(fun) are the same thing. Functions that get their address taken are not implicitly invoked. (Again, Scala agrees.)Here is scala semantic with D syntax : void bar() {} bar; // execute bar. Is an exception because taking the function pointer is a NOOP.No, it is the rule.void foo(void function() bar) {} foo(bar); // OK, bar is not evaluated.This is the exception. (That nobody has argued in favour of so far.)
Feb 04 2013
On 2/4/13 9:25 AM, Timon Gehr wrote:On 02/04/2013 03:05 PM, Andrei Alexandrescu wrote:The problem with (3) is that it creates a rule that gives different meaning of expressions inside &(...) and outside it. Consider: &foo -> fine, takes the address of foo &(foo) -> parens don't matter, sweet, still takes the address of foo &( condition ? foo : bar ) -> hum, I guess takes the address of foo or bar &( { auto a = foo; ... return c ? foo : bar; }() ) -> what??? So this is essentially a rule that makes the same give expression have a meaning inside &( ... ) and a different meaning outside. In &expr.name and &(expr.name), that's it - expr may be arbitrarily complicated, but the construct must always end with a method name. In &name and &(name), it's even simpler - it's just punctuation. AndreiI think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result.No! &fun and &(fun) are the same thing. Functions that get their address taken are not implicitly invoked. (Again, Scala agrees.) The rules are straightforward: A non- property function name 'foo' denotes a function invocation without arguments iff it does not occur in one of the following contexts: 1. foo(...) // explicitly called 2. &foo // address taken 3. ...!(...,foo,...) // template argument (well, that's what DMD currently does) 4. alias ... = foo; // aliased
Feb 04 2013
2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>Couldn't AddressOf use "&(" + exp + ")"?Yes. It's enough. I wanted to explain that "we should treat address-expression carefully".I thought more about this. The problem remains even without property, due to optional parens in function invocation. Consider: ref int fun() { ... } auto p1 = &fun; auto p2 = &(fun); auto p3 = &(fun()); What are the types of the three? The optional parens in invocation require some disambiguation. I think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result.Agreed.I would agree restricting the properties, but requiring a __trait to take the address of a regular function or method seems overkill.Fully agreed. Although it looks strange and unstable, adding new distinction of semantics between &foo and &(foo) has no ambiguity. I think this is necessary feature for the D's function and property semantics. Kenji Hara
Feb 04 2013
On 02/04/2013 03:38 PM, kenji hara wrote:2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org <mailto:SeeWebsiteForEmail erdani.org>> Couldn't AddressOf use "&(" + exp + ")"? Yes. It's enough. I wanted to explain that "we should treat address-expression carefully". I thought more about this. The problem remains even without property, due to optional parens in function invocation. Consider: ref int fun() { ... } auto p1 = &fun; auto p2 = &(fun); auto p3 = &(fun()); What are the types of the three? The optional parens in invocation require some disambiguation. I think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result. Agreed.Why?I would agree restricting the properties, but requiring a __trait to take the address of a regular function or method seems overkill. Fully agreed.It is not an interesting point. It is not necessary anyway.Although it looks strange and unstable, adding new distinction of semantics between &foo and &(foo) has no ambiguity.It _is_ strange.I think this is necessary feature for the D's function and property semantics.Why?
Feb 04 2013
2013/2/4 Timon Gehr <timon.gehr gmx.ch>On 02/04/2013 03:38 PM, kenji hara wrote:Because, "property" is one of D-specific feature. In D, "property" is directly translated to function call. So, we should get balance between two requirements: 1. property should be treated as its returned type. 2. property should be distinguished from raw field. (For example, serialization library should recognize it) Address expression is _only_one_ built-in feature to make a callable object from function symbol. So this "special feature" is enough reasonable to me. Kenji HaraI think this is necessary feature for the D's function and property semantics.Why?
Feb 04 2013
On 02/04/2013 04:08 PM, kenji hara wrote:2013/2/4 Timon Gehr <timon.gehr gmx.ch <mailto:timon.gehr gmx.ch>> On 02/04/2013 03:38 PM, kenji hara wrote: I think this is necessary feature for the D's function and property semantics. Why? Because, "property" is one of D-specific feature. In D, "property" is directly translated to function call. So, we should get balance between two requirements: 1. property should be treated as its returned type. 2. property should be distinguished from raw field. (For example, serialization library should recognize it)This is what __traits are for.Address expression is _only_one_ built-in feature to make a callable object from function symbol.Property symbols are not to be treated like function symbols syntactically. That is the point. Otherwise we may as well get rid of properties.So this "special feature" is enough reasonable to me. ..."special features" are usually not reasonable.
Feb 04 2013
I have thought in long term that, in D, "proerty" is just a syntactic rerwiting rule of function call. It is much reasonable abstraction to me. So, using __trait is overkill. Kenji Hara 2013/02/05 0:45 "Timon Gehr" <timon.gehr gmx.ch>:On 02/04/2013 04:08 PM, kenji hara wrote:2013/2/4 Timon Gehr <timon.gehr gmx.ch <mailto:timon.gehr gmx.ch>> On 02/04/2013 03:38 PM, kenji hara wrote: I think this is necessary feature for the D's function and property semantics. Why? Because, "property" is one of D-specific feature. In D, "property" is directly translated to function call. So, we should get balance between two requirements: 1. property should be treated as its returned type. 2. property should be distinguished from raw field. (For example, serialization library should recognize it)This is what __traits are for. Address expression is _only_one_ built-in feature to make a callableobject from function symbol.Property symbols are not to be treated like function symbols syntactically. That is the point. Otherwise we may as well get rid of properties. So this "special feature" is enough reasonable to me...."special features" are usually not reasonable.
Feb 04 2013
On 2/4/13, kenji hara <k.hara.pg gmail.com> wrote:This is not correct."m.s & m.s" is always parsed as binary bitwise AND expression. So there is no address expression.Fantastic, more special casing. I don't think you guys realize what a mess you would introduce. Basically: s & s; // fine, they're binary operators &s; // oops, doesn't work even if property returns a type with a unary operator On 2/4/13, kenji hara <k.hara.pg gmail.com> wrote:Address expression is _only_one_ built-in feature to make a callable object from function symbol. So this "special feature" is enough reasonable to me.Yes "only one". And then later we'll add another "one", and another one, until we end up with the mess that is C++. This feature does not pull its own weight regardless of how easy it is to implement in the compiler. From a user's perspective, it is completely pointless and unintuitive.
Feb 04 2013
04-Feb-2013 19:15, Andrej Mitrovic пишет:On 2/4/13, kenji hara <k.hara.pg gmail.com> wrote:Unary & is not overloadable, precisely due to confusing mess it can create (see C++). -- Dmitry OlshanskyThis is not correct."m.s & m.s" is always parsed as binary bitwise AND expression. So there is no address expression.Fantastic, more special casing. I don't think you guys realize what a mess you would introduce. Basically: s & s; // fine, they're binary operators &s; // oops, doesn't work even if property returns a type with a unary operator
Feb 04 2013
On 2/4/13, Dmitry Olshansky <dmitry.olsh gmail.com> wrote:Unary & is not overloadable, precisely due to confusing mess it can create (see C++).Right I overlooked that, but this new rule will introduce a confusing mess as well. Anyway my vote is firmly against it. If anything we should have a vote on it before someone starts hacking on master without us knowing about it (UDA's, anyone?).
Feb 04 2013
2013/2/5 Andrej Mitrovic <andrej.mitrovich gmail.com>On 2/4/13, kenji hara <k.hara.pg gmail.com> wrote:Address operator cannot be overloaded. http://dlang.org/operatoroverloading On 2/4/13, kenji hara <k.hara.pg gmail.com> wrote:This is not correct."m.s & m.s" is always parsed as binary bitwise ANDexpression.So there is no address expression.Fantastic, more special casing. I don't think you guys realize what a mess you would introduce. Basically: s & s; // fine, they're binary operators &s; // oops, doesn't work even if property returns a type with a unary operatorWe can think like this. "To resolve ambiguity, we should introduce new operator: &( exp )". Or, we can think like that we introduce one new restriction. "If you want to get function address, you MUST not add redundant parenthesis." &func; // OK &(func); // Bad. It should be written in the article "Migration for Property Enforcement". Kenji HaraAddress expression is _only_one_ built-in feature to make a callableobjectfrom function symbol. So this "special feature" is enough reasonable to me.Yes "only one". And then later we'll add another "one", and another one, until we end up with the mess that is C++. This feature does not pull its own weight regardless of how easy it is to implement in the compiler. From a user's perspective, it is completely pointless and unintuitive.
Feb 04 2013
On 2/4/2013 6:05 AM, Andrei Alexandrescu wrote:Couldn't AddressOf use "&(" + exp + ")"? I thought more about this. The problem remains even without property, due to optional parens in function invocation. Consider: ref int fun() { ... } auto p1 = &fun; auto p2 = &(fun); auto p3 = &(fun()); What are the types of the three? The optional parens in invocation require some disambiguation. I think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result.The only time it is valid to take the address of a function's return value is if the function returns a ref. But I also would think that it's a suspicious practice to take the address of a ref. We've disallowed it in other circumstances, why allow it here? If a function intends for someone to take the address of the return ref, shouldn't the function return a pointer instead? If taking the address of a ref is disallowed, then the above problem goes away. &fun, in all its variants, takes the address of the function.
Feb 04 2013
On Mon, 04 Feb 2013 18:18:16 -0500, Walter Bright <newshound2 digitalmars.com> wrote:On 2/4/2013 6:05 AM, Andrei Alexandrescu wrote:I'd agree with you if we could have ref variables. In some cases, taking the address is the ONLY option. -SteveCouldn't AddressOf use "&(" + exp + ")"? I thought more about this. The problem remains even without property, due to optional parens in function invocation. Consider: ref int fun() { ... } auto p1 = &fun; auto p2 = &(fun); auto p3 = &(fun()); What are the types of the three? The optional parens in invocation require some disambiguation. I think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result.The only time it is valid to take the address of a function's return value is if the function returns a ref. But I also would think that it's a suspicious practice to take the address of a ref. We've disallowed it in other circumstances, why allow it here? If a function intends for someone to take the address of the return ref, shouldn't the function return a pointer instead?
Feb 05 2013
On 2/5/13 11:44 AM, Steven Schveighoffer wrote:On Mon, 04 Feb 2013 18:18:16 -0500, Walter Bright <newshound2 digitalmars.com> wrote:Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a function (and actually ref parameters and even struct members in safe code). One would still be able to take the address of a field in a class because that's assumed to live on the GC heap. To get the address of an object in system code without resorting to operator& at all, we're considering adding a stdlib function implemented like this (there are several other ways, this is just for illustration): system T* addressOf(T)(ref T obj) { static T* id(T* p) { return p; } auto idr = cast(T* function(ref T)) id; return idr(obj); } I have a DIP in the making that makes "ref" entirely sealed, i.e. it makes it impossible to have a dangling ref in safe code. If that DIP gets approved, then DIP23 gets considerably simplified because operator& won't be applicable to the result of a function anymore. AndreiOn 2/4/2013 6:05 AM, Andrei Alexandrescu wrote:I'd agree with you if we could have ref variables. In some cases, taking the address is the ONLY option.Couldn't AddressOf use "&(" + exp + ")"? I thought more about this. The problem remains even without property, due to optional parens in function invocation. Consider: ref int fun() { ... } auto p1 = &fun; auto p2 = &(fun); auto p3 = &(fun()); What are the types of the three? The optional parens in invocation require some disambiguation. I think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result.The only time it is valid to take the address of a function's return value is if the function returns a ref. But I also would think that it's a suspicious practice to take the address of a ref. We've disallowed it in other circumstances, why allow it here? If a function intends for someone to take the address of the return ref, shouldn't the function return a pointer instead?
Feb 05 2013
Andrei Alexandrescu:One would still be able to take the address of a field in a class because that's assumed to live on the GC heap.Maybe some people want to allocate many small class instances on the stack. Bye, bearephile
Feb 05 2013
On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a function (and actually ref parameters and even struct members in safe code). One would still be able to take the address of a field in a class because that's assumed to live on the GC heap.What about structs that live on the heap? e.g. a struct element of an array, or a struct member of a class instance. I think the point about safe code is moot, aren't pointers disallowed in safe code anyway?To get the address of an object in system code without resorting to operator& at all, we're considering adding a stdlib function implemented like this (there are several other ways, this is just for illustration): system T* addressOf(T)(ref T obj) { static T* id(T* p) { return p; } auto idr = cast(T* function(ref T)) id; return idr(obj); }I think a cast would be sufficient: cast(int *)(&refparam); // understood that a cast is required To jump through this machinery to turn a reference into a, um... reference, seems like a huge waste of code space and resources. -Steve
Feb 05 2013
On Tue, Feb 05, 2013 at 02:05:24PM -0500, Steven Schveighoffer wrote:On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:[...] AFAIK, pointers are allowed in safe code as long as no type casts or pointer arithmetic are performed. T -- There is no gravity. The earth sucks.Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a function (and actually ref parameters and even struct members in safe code). One would still be able to take the address of a field in a class because that's assumed to live on the GC heap.What about structs that live on the heap? e.g. a struct element of an array, or a struct member of a class instance. I think the point about safe code is moot, aren't pointers disallowed in safe code anyway?
Feb 05 2013
On 2/5/13 2:11 PM, H. S. Teoh wrote:On Tue, Feb 05, 2013 at 02:05:24PM -0500, Steven Schveighoffer wrote:Yah, apparently that's not sufficient. We must make sure pointers don't escape. AndreiOn Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:[...] AFAIK, pointers are allowed in safe code as long as no type casts or pointer arithmetic are performed.Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of& against a ref result from a function (and actually ref parameters and even struct members in safe code). One would still be able to take the address of a field in a class because that's assumed to live on the GC heap.What about structs that live on the heap? e.g. a struct element of an array, or a struct member of a class instance. I think the point about safe code is moot, aren't pointers disallowed in safe code anyway?
Feb 05 2013
On 2/5/13 2:05 PM, Steven Schveighoffer wrote:On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:In that case we'll disallow it conservatively.Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a function (and actually ref parameters and even struct members in safe code). One would still be able to take the address of a field in a class because that's assumed to live on the GC heap.What about structs that live on the heap? e.g. a struct element of an array, or a struct member of a class instance.I think the point about safe code is moot, aren't pointers disallowed in safe code anyway?Yah, time to start enforcing it more seriously. But we want to ban some uses of & in all code.The whole point was to avoid using operator &. AndreiTo get the address of an object in system code without resorting to operator& at all, we're considering adding a stdlib function implemented like this (there are several other ways, this is just for illustration): system T* addressOf(T)(ref T obj) { static T* id(T* p) { return p; } auto idr = cast(T* function(ref T)) id; return idr(obj); }I think a cast would be sufficient: cast(int *)(&refparam); // understood that a cast is required To jump through this machinery to turn a reference into a, um... reference, seems like a huge waste of code space and resources.
Feb 05 2013
On Tue, 05 Feb 2013 15:15:05 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 2/5/13 2:05 PM, Steven Schveighoffer wrote:The mechanism to avoid it seems overly extravagant (and prone to low performance). If you want actually avoid using operator &, then make a compiler special function or something. Also, the use of & can still be hidden inside a function. -SteveI think a cast would be sufficient: cast(int *)(&refparam); // understood that a cast is required To jump through this machinery to turn a reference into a, um... reference, seems like a huge waste of code space and resources.The whole point was to avoid using operator &.
Feb 05 2013
On 2/5/13 4:45 PM, Steven Schveighoffer wrote:On Tue, 05 Feb 2013 15:15:05 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:As I said, there are various solutions. I wrote one that's reasonably portable.On 2/5/13 2:05 PM, Steven Schveighoffer wrote:The mechanism to avoid it seems overly extravagant (and prone to low performance). If you want actually avoid using operator &, then make a compiler special function or something.I think a cast would be sufficient: cast(int *)(&refparam); // understood that a cast is required To jump through this machinery to turn a reference into a, um... reference, seems like a huge waste of code space and resources.The whole point was to avoid using operator &.Also, the use of & can still be hidden inside a function.My point was to not need & such that the function itself can be compiled. Overall I think this is not the focal issue, the consequences are. Andrei
Feb 05 2013
On 02/05/2013 09:15 PM, Andrei Alexandrescu wrote:... The whole point was to avoid using operator &. ...Well, that is completely unnecessary.
Feb 05 2013
On Tuesday, February 05, 2013 14:05:24 Steven Schveighoffer wrote:I think the point about safe code is moot, aren't pointers disallowed in safe code anyway?Goodness no. It's pointer arithmetic which is disallowed. Pointers themselves are perfectly safe as long as you just pass them around or dereference them (which would include calling functions on them). For instance, the result of in on an AA is a pointer to the object, and that's safe. - Jonathan M Davis
Feb 05 2013
On Tue, 05 Feb 2013 16:43:39 -0500, Jonathan M Davis <jmdavisProg gmx.com> wrote:On Tuesday, February 05, 2013 14:05:24 Steven Schveighoffer wrote:Well, it would seem setting all kinds of extra rules on ref (in addition to the restrictions we have now), when pointers are more useful even in safe code, will simply result in people using pointers more than ref. I'm not sure that's the right message, but I'm afraid that will be what it is. For example, I have to use pointers for my linked list implementation in dcollections, because ref is forbidden to be used as a class or struct member (my nodes are structs because classes are too heavy). Also, ref is not rebindable, whereas a pointer is. -SteveI think the point about safe code is moot, aren't pointers disallowed in safe code anyway?Goodness no. It's pointer arithmetic which is disallowed. Pointers themselves are perfectly safe as long as you just pass them around or dereference them (which would include calling functions on them). For instance, the result of in on an AA is a pointer to the object, and that's safe.
Feb 05 2013
On Tuesday, February 05, 2013 16:53:51 Steven Schveighoffer wrote:On Tue, 05 Feb 2013 16:43:39 -0500, Jonathan M Davis <jmdavisProg gmx.com> wrote:That may end up happening, but the issues with ref may boil over into some of what happens with pointers - the key issue being escaping references. Using & on a local variable is already considered unsafe, but using ref as a function parameter gets you pretty much exactly the same thing if a local variable is passed to it and ref is returned by the function (I believe that discussions on that are what triggered Andrei's work on the DIP on ref that he brought up). What's really needed is to be able to detect and prevent escaping pointers and references, and there are a lot of difficulties with that. The easy way out tends to mean making a lot of code be system, which could either end up being very limiting or result in a lot more code being system instead of safe. I don't know what exactly Andrei and Walter are cooking up, but SafeD could end up becoming very limited with regards to pointers and refs in order to deal with all of the corner cases. - Jonathan M DavisOn Tuesday, February 05, 2013 14:05:24 Steven Schveighoffer wrote:Well, it would seem setting all kinds of extra rules on ref (in addition to the restrictions we have now), when pointers are more useful even in safe code, will simply result in people using pointers more than ref. I'm not sure that's the right message, but I'm afraid that will be what it is. For example, I have to use pointers for my linked list implementation in dcollections, because ref is forbidden to be used as a class or struct member (my nodes are structs because classes are too heavy). Also, ref is not rebindable, whereas a pointer is.I think the point about safe code is moot, aren't pointers disallowed in safe code anyway?Goodness no. It's pointer arithmetic which is disallowed. Pointers themselves are perfectly safe as long as you just pass them around or dereference them (which would include calling functions on them). For instance, the result of in on an AA is a pointer to the object, and that's safe.
Feb 05 2013
On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a function (and actually ref parameters and even struct members in safe code). One would still be able to take the address of a field in a class because that's assumed to live on the GC heap.Back to the problem I stated, how does one do this: ref A foo(); ref A bar(); A *a; if(condition) a = &foo(); else a = &bar(); // use a for a few lines I can see a possible solution but it's not pretty: void processA(ref A a) { // lines that deal with a here } if(condition) processA(foo()); else processA(bar()); But this kind of seems hacky. Why should I have to declare a function just to keep a persistent reference to a return value for the scope of my function? Not only is is awkward, there is a performance hit in that I have to call another function. Note also that this doesn't fix memory issues: struct S { ref S self() {return this;} } ref S bad() { S s; return s.self(); } Which I believe would be valid still with your rules. -Steve
Feb 05 2013
On 2/5/13 2:21 PM, Steven Schveighoffer wrote:On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:You define the function in situ. We understand some valid code will be disallowed by the change,Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a function (and actually ref parameters and even struct members in safe code). One would still be able to take the address of a field in a class because that's assumed to live on the GC heap.Back to the problem I stated, how does one do this: ref A foo(); ref A bar(); A *a; if(condition) a = &foo(); else a = &bar(); // use a for a few lines I can see a possible solution but it's not pretty: void processA(ref A a) { // lines that deal with a here } if(condition) processA(foo()); else processA(bar()); But this kind of seems hacky. Why should I have to declare a function just to keep a persistent reference to a return value for the scope of my function? Not only is is awkward, there is a performance hit in that I have to call another function.Note also that this doesn't fix memory issues: struct S { ref S self() {return this;} } ref S bad() { S s; return s.self(); } Which I believe would be valid still with your rules.Also consider the simpler: ref int id(ref int x) { return x; } ref int id1(ref int x) { return id(x); } ref int id2(ref int x) { return id1(x); } ref int oops(int x) { return id2(x); } DIP24 addresses that and other similar cases at their core. Andrei
Feb 05 2013
On Tue, 05 Feb 2013 15:21:14 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Also consider the simpler: ref int id(ref int x) { return x; } ref int id1(ref int x) { return id(x); } ref int id2(ref int x) { return id1(x); } ref int oops(int x) { return id2(x); } DIP24 addresses that and other similar cases at their core.I look forward to reading it. -Steve
Feb 05 2013
On 02/05/2013 09:21 PM, Andrei Alexandrescu wrote:... Also consider the simpler: ref int id(ref int x) { return x; } ref int id1(ref int x) { return id(x); } ref int id2(ref int x) { return id1(x); } ref int oops(int x) { return id2(x); } DIP24 addresses that and other similar cases at their core. ...Given a noticeable tendency of your latest design proposals, I guess it does so by disallowing the 'ref' keyword in the lexer stage. :o)
Feb 05 2013
Timon Gehr <timon.gehr gmx.ch> wrote:On 02/05/2013 09:21 PM, Andrei Alexandrescu wrote:What is the noticeable tendency of my latest design proposals? Andrei... Also consider the simpler: ref int id(ref int x) { return x; } ref int id1(ref int x) { return id(x); } ref int id2(ref int x) { return id1(x); } ref int oops(int x) { return id2(x); } DIP24 addresses that and other similar cases at their core. ...Given a noticeable tendency of your latest design proposals, I guess it does so by disallowing the 'ref' keyword in the lexer stage. :o)
Feb 05 2013
<address_is invalid.invalid> wrote:Timon Gehr <timon.gehr gmx.ch> wrote:That was me on the misconfigured phone. AndreiOn 02/05/2013 09:21 PM, Andrei Alexandrescu wrote:What is the noticeable tendency of my latest design proposals? Andrei... Also consider the simpler: ref int id(ref int x) { return x; } ref int id1(ref int x) { return id(x); } ref int id2(ref int x) { return id1(x); } ref int oops(int x) { return id2(x); } DIP24 addresses that and other similar cases at their core. ...Given a noticeable tendency of your latest design proposals, I guess it does so by disallowing the 'ref' keyword in the lexer stage. :o)
Feb 05 2013
On 02/05/2013 11:58 PM, Andrei Alexandrescu wrote:<address_is invalid.invalid> wrote:They were mostly about banning stuff.Timon Gehr <timon.gehr gmx.ch> wrote:...On 02/05/2013 09:21 PM, Andrei Alexandrescu wrote:What is the noticeable tendency of my latest design proposals? Andrei... Also consider the simpler: ref int id(ref int x) { return x; } ref int id1(ref int x) { return id(x); } ref int id2(ref int x) { return id1(x); } ref int oops(int x) { return id2(x); } DIP24 addresses that and other similar cases at their core. ...Given a noticeable tendency of your latest design proposals, I guess it does so by disallowing the 'ref' keyword in the lexer stage. :o)
Feb 05 2013
On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a function (and actually ref parameters and even struct members in safe code). One would still be able to take the address of a field in a class because that's assumed to live on the GC heap.Thinking about this some more, would this be allowed: trusted T *getAddr(T)(ref T obj) { return &obj; } // allowed? You said only safe code would disallow address of ref parameters -Steve
Feb 05 2013
On 2/5/13 2:25 PM, Steven Schveighoffer wrote:On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:We hope to be able to disallow it. AndreiWalter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a function (and actually ref parameters and even struct members in safe code). One would still be able to take the address of a field in a class because that's assumed to live on the GC heap.Thinking about this some more, would this be allowed: trusted T *getAddr(T)(ref T obj) { return &obj; } // allowed? You said only safe code would disallow address of ref parameters
Feb 05 2013
On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu wrote:I have a DIP in the making that makes "ref" entirely sealed, i.e. it makes it impossible to have a dangling ref in safe code. If that DIP gets approved, then DIP23 gets considerably simplified because operator& won't be applicable to the result of a function anymore. AndreiI hope it at least considers my proposal with regard to 'out' return values. 'out' implies ref and guarantees that the result is as good as global: out int foo(ref int a) { return a; } // Error, 'out' return may not return ref parameter out int goo(ref int a) { return new int; } // Fine My impression was that this would solve 98% of problems, the other 2% requiring scope parameters, which also imply ref: ref int haa(ref int a, scope int b) { return b; } // Error, may not return scope parameter ref int gaa(ref int a, scope int b) { return a; } // Fine
Feb 05 2013
On 2/5/13 2:44 PM, Zach the Mystic wrote:On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu wrote:I'm sorry, I didn't know of that proposal. Generally we're aiming for economy of means i.e. we want to clarify semantics of existing syntax instead of adding new syntax and semantics. AndreiI have a DIP in the making that makes "ref" entirely sealed, i.e. it makes it impossible to have a dangling ref in safe code. If that DIP gets approved, then DIP23 gets considerably simplified because operator& won't be applicable to the result of a function anymore. AndreiI hope it at least considers my proposal with regard to 'out' return values. 'out' implies ref and guarantees that the result is as good as global: out int foo(ref int a) { return a; } // Error, 'out' return may not return ref parameter out int goo(ref int a) { return new int; } // Fine My impression was that this would solve 98% of problems, the other 2% requiring scope parameters, which also imply ref: ref int haa(ref int a, scope int b) { return b; } // Error, may not return scope parameter ref int gaa(ref int a, scope int b) { return a; } // Fine
Feb 05 2013
On Tuesday, 5 February 2013 at 20:24:16 UTC, Andrei Alexandrescu wrote:It's not a new syntax, just new semantics. Also, the reason for adding these semantics to the function signature was so that the compiler would never have to leave the function in order to compile it. It's a natural complement to ref returns' scope being the most local of the ref parameters, which you suggested in your proposal. It keeps that too.I hope it at least considers my proposal with regard to 'out' return values. 'out' implies ref and guarantees that the result is as good as global: out int foo(ref int a) { return a; } // Error, 'out' return may not return ref parameter out int goo(ref int a) { return new int; } // Fine My impression was that this would solve 98% of problems, the other 2% requiring scope parameters, which also imply ref: ref int haa(ref int a, scope int b) { return b; } // Error, may not return scope parameter ref int gaa(ref int a, scope int b) { return a; } // FineI'm sorry, I didn't know of that proposal. Generally we're aiming for economy of means i.e. we want to clarify semantics of existing syntax instead of adding new syntax and semantics. Andrei
Feb 05 2013
On 2/5/13 4:35 PM, Zach the Mystic wrote:On Tuesday, 5 February 2013 at 20:24:16 UTC, Andrei Alexandrescu wrote:Just to make sure: this is about http://forum.dlang.org/thread/ririagrqecshjljcdubd forum.dlang.org. Language design is a subjective topic. With time I have learned it's best to not comment very much about it. I have created dozens, maybe hundreds of tidbits of language design and invariably I believe they had obvious merits and negligible drawbacks. The confidence in the quality of my own language designs has decayed exponentially over the years. I'm telling this to put in perspective my following comment. I think it's awesome that work like yours is discussed and refined in this group. At the same time my opinion is that the design is not appropriate for us. It changes semantics of existing code and fosters a cross-talk between subcomponents that has not been time tested. It is complicated in implementation for a benefit that's not properly motivated. At the top level it solves the wrong problem. As stated: "The challenge is to do better, both in terms of functionality and in terms of syntax, than his proposal: ..." The actual challenge is to make properties work with maximum backward compatibility, minimal surprise, best integration with the rest of the language, and maximum of benefits. AndreiIt's not a new syntax, just new semantics. Also, the reason for adding these semantics to the function signature was so that the compiler would never have to leave the function in order to compile it. It's a natural complement to ref returns' scope being the most local of the ref parameters, which you suggested in your proposal. It keeps that too.I hope it at least considers my proposal with regard to 'out' return values. 'out' implies ref and guarantees that the result is as good as global: out int foo(ref int a) { return a; } // Error, 'out' return may not return ref parameter out int goo(ref int a) { return new int; } // Fine My impression was that this would solve 98% of problems, the other 2% requiring scope parameters, which also imply ref: ref int haa(ref int a, scope int b) { return b; } // Error, may not return scope parameter ref int gaa(ref int a, scope int b) { return a; } // FineI'm sorry, I didn't know of that proposal. Generally we're aiming for economy of means i.e. we want to clarify semantics of existing syntax instead of adding new syntax and semantics. Andrei
Feb 05 2013
On Tuesday, 5 February 2013 at 21:59:53 UTC, Andrei Alexandrescu wrote:Just to make sure: this is about http://forum.dlang.org/thread/ririagrqecshjljcdubd forum.dlang.org. Language design is a subjective topic. With time I have learned it's best to not comment very much about it. I have created dozens, maybe hundreds of tidbits of language design and invariably I believe they had obvious merits and negligible drawbacks. The confidence in the quality of my own language designs has decayed exponentially over the years. I'm telling this to put in perspective my following comment. I think it's awesome that work like yours is discussed and refined in this group. At the same time my opinion is that the design is not appropriate for us. It changes semantics of existing code and fosters a cross-talk between subcomponents that has not been time tested. It is complicated in implementation for a benefit that's not properly motivated. At the top level it solves the wrong problem. As stated: "The challenge is to do better, both in terms of functionality and in terms of syntax, than his proposal: ..." The actual challenge is to make properties work with maximum backward compatibility, minimal surprise, best integration with the rest of the language, and maximum of benefits. AndreiOkay. But I just want to be clear that you are saying what I am reading, which is that I came to this language too late to really make a difference in it.
Feb 05 2013
On 2/5/13 7:15 PM, Zach the Mystic wrote:Okay. But I just want to be clear that you are saying what I am reading, which is that I came to this language too late to really make a difference in it.Depends on how you look at it. Among languages of any note, I suspect D is one of the more open to language design discussions. Also, there is plenty of fun to be had with library enhancements, proving properties of language constructs, tightening the screws all around, writing articles, tutorials, and documentation, and more. We're just at the beginning of a vast expansion. If by making a difference you mean strictly adding a language feature to D, you're not late even for that but you have to come up with something pretty darn interesting. Your proposal is not that; it does hold water, it is likely implementable, and it is possibly useful (though I have some doubts about the latter). It's just not compelling enough to make the A list, and we can't afford anything but the A+ list. Note that most people tend to vastly overestimate their few first language designs, and that there are much more people who think are good at language design than those actually are. (Note I'm only passing opinion on what I saw; You may as well be an awesome language designer, but the spark is not visible in this particular proposal.) Though I've had an idea or two that stuck, I confess without any false modesty that I don't consider myself to be a noted language designer. Andrei
Feb 05 2013
On Tuesday, February 05, 2013 21:22:34 Andrei Alexandrescu wrote:Note that most people tend to vastly overestimate their few first language designs, and that there are much more people who think are good at language design than those actually are. (Note I'm only passing opinion on what I saw; You may as well be an awesome language designer, but the spark is not visible in this particular proposal.) Though I've had an idea or two that stuck, I confess without any false modesty that I don't consider myself to be a noted language designer.Another thing to consider is that it's fairly common for people to come up with ideas that seem like very good ideas and seem very solid but which ultimately end up falling apart due to corner cases. And we're already suffering from features which are partially implemented and not necessarily fully thought through, even if they're solid in their basics. As far as changing D goes, we're far enough along in the process that anything which would break backwards compatibility needs a really compelling case for it happen. We're trying to stabilize the language, which _does_ require breaking code in some cases, but we'd like to minimize that. Backwards compatible feature requests are more likely to make it in, but even then, they need very compelling use cases and are likely to be held back by all of the work that _needs_ to be done (new features may be nice, but they're unlikely to be necessary at this point). We're past the point where we're freely mucking with the language to try out new ideas but instead are trying to polish what we have. But as Andrei says, there's tons of room for stuff to be done on the library front and plenty of work to do helping out with stuff like documentation and articles. So, there's tons for people to do to help out, and there's certainly plenty of innovation that could be done with regards to how stuff is handled in new stuff in the standard library. It's just the lanugage itself where we're limiting what innovation we put into it at this point. - Jonathan M Davis
Feb 05 2013
On Wednesday, 6 February 2013 at 02:36:13 UTC, Jonathan M Davis wrote:On Tuesday, February 05, 2013 21:22:34 Andrei Alexandrescu wrote:Well, Jonathan M Davis, I had posted a second response to Andrei's first comment before reading either his second one or yours. But I think I pretty much explained my position, for better or worse. It's not so much not having the feature included so much as wanting to know why because despite Andrei's clear intelligence and good intentions, I felt pretty strongly that I had put onto the table something very good.Note that most people tend to vastly overestimate their few first language designs, and that there are much more people who think are good at language design than those actually are. (Note I'm only passing opinion on what I saw; You may as well be an awesome language designer, but the spark is not visible in this particular proposal.) Though I've had an idea or two that stuck, I confess without any false modesty that I don't consider myself to be a noted language designer.Another thing to consider is that it's fairly common for people to come up with ideas that seem like very good ideas and seem very solid but which ultimately end up falling apart due to corner cases. And we're already suffering from features which are partially implemented and not necessarily fully thought through, even if they're solid in their basics. As far as changing D goes, we're far enough along in the process that anything which would break backwards compatibility needs a really compelling case for it happen. We're trying to stabilize the language, which _does_ require breaking code in some cases, but we'd like to minimize that. Backwards compatible feature requests are more likely to make it in, but even then, they need very compelling use cases and are likely to be held back by all of the work that _needs_ to be done (new features may be nice, but they're unlikely to be necessary at this point). We're past the point where we're freely mucking with the language to try out new ideas but instead are trying to polish what we have. But as Andrei says, there's tons of room for stuff to be done on the library front and plenty of work to do helping out with stuff like documentation and articles. So, there's tons for people to do to help out, and there's certainly plenty of innovation that could be done with regards to how stuff is handled in new stuff in the standard library. It's just the lanugage itself where we're limiting what innovation we put into it at this point. - Jonathan M Davis
Feb 05 2013
On Tuesday, 5 February 2013 at 21:59:53 UTC, Andrei Alexandrescu wrote:Just to make sure: this is about http://forum.dlang.org/thread/ririagrqecshjljcdubd forum.dlang.org. Language design is a subjective topic. With time I have learned it's best to not comment very much about it. I have created dozens, maybe hundreds of tidbits of language design and invariably I believe they had obvious merits and negligible drawbacks. The confidence in the quality of my own language designs has decayed exponentially over the years. I'm telling this to put in perspective my following comment. I think it's awesome that work like yours is discussed and refined in this group. At the same time my opinion is that the design is not appropriate for us. It changes semantics of existing codeMy proposal changes exactly one existing semantic, which is that a nested struct will find symbols it doesn't find in itself in the parent before looking at module and import levels. I'm pretty sure it's a bad practice to shadow names in nested structs, and I predicted no code breakage at all in the vast majority of projects.and fosters a cross-talk between subcomponents that has not been time tested. It is complicated in implementation for a benefit that's not properly motivated. At the top level it solves the wrong problem. As stated: "The challenge is to do better, both in terms of functionality and in terms of syntax, than his proposal: ..." The actual challenge is to make properties work with maximum backward compatibility, minimal surprise, best integration with the rest of the language, and maximum of benefits. AndreiI've thought about this some more. You're right in that my proposal does not meet the first two design goals. But it doesn't harm them either. property can exist side-by-side with my proposal indefinitely. The only demand you must make on programmers is that they convert all overloads of a given local property implementation at once so there's no repeat declaration. As far as best integration with the rest of the language, my proposal requires one new syntax (Highlander) and no new keyword or even the keeping of ' property' itself. As far as maximum of benefits, I think mine wins by far. Not only have properties been granted the full semantic power of the already-designed-and-implemented structs, but the features required to make this possible have their own uses totally apart from making properties easy. Yes, my proposal fosters cross-talk between subcomponents that have not been time tested, but it doesn't prevent people from programming in the way they always have, either, with the one exception mentioned above. So is my proposal properly motivated? Here's what happened. I saw a connection between what everyone is trying to do with properties and what the built-in struct operators already do. I can't figure out why you would want to have two systems when you could just design one really well (design goal 3 above: best integration with the rest of the language). So I figured out what needed to change to be able to use the one system for the two purposes. The new proposal with nested structs is confusing, but I see no problems with it. Underneath, it's just what old-fashioned C programming is about, a bunch of functions which accept a bunch of variables, some of them references. Whether or not my proposal gains any more traction than it already has, I consider myself lucky to have discovered it. It felt like it was just sitting right there for someone, and I was the one to find it. I may feel a little bad that there was so much opposition. So far, the original person who posed the challenge has said nothing at all about it, for example, but still, I'm glad I found it, and I don't even care at this point if anyone else cares.
Feb 05 2013
On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu wrote:[..] Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a function (and actually ref parameters and even struct members in safe code). [..]Did you consider using Rust's idea of 'Named lifetimes' in order to make ref parameters memory-safe. I haven't given much thought to it, but since Rust's borrowed pointers are effectively isomorphic to D's ref variables, it should work. Here's a Rust borrowed pointer tutorial: http://static.rust-lang.org/doc/tutorial-borrowed-ptr.html
Feb 05 2013
On 2/5/13 3:08 PM, TommiT wrote:On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu wrote:Thanks, I'll give that a read. We're very careful at this point about spending much "complexity budget" (as a friend calls it) on new features. Andrei[..] Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a function (and actually ref parameters and even struct members in safe code). [..]Did you consider using Rust's idea of 'Named lifetimes' in order to make ref parameters memory-safe. I haven't given much thought to it, but since Rust's borrowed pointers are effectively isomorphic to D's ref variables, it should work. Here's a Rust borrowed pointer tutorial: http://static.rust-lang.org/doc/tutorial-borrowed-ptr.html
Feb 05 2013
On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu wrote:Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a functionPlease, no. ref T foo(); extern(C) void bar(T*); bar(&foo()); // how?
Feb 05 2013
On 2013-02-05, 23:46, Max Samukha wrote:On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu wrote:system T* addressOf(T)(ref T obj) { static T* id(T* p) { return p; } auto idr = cast(T* function(ref T)) id; return idr(obj); } bar(addressOf(foo()); // Like this It's right there in his post. -- SimenWalter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a functionPlease, no. ref T foo(); extern(C) void bar(T*); bar(&foo()); // how?
Feb 05 2013
On Monday, 4 February 2013 at 05:32:39 UTC, Andrei Alexandrescu wrote:On 2/3/13 11:00 PM, David Nadlinger wrote:Yes, that is why, ideally, you want to close the gap as much as possible.The problem I see is that usually, one can insert grouping pairs of parentheses into an expression according to the operator precedence/associativity rules at will without changing the result. This isn't merely a theoretical exercise, but the way (well, in the form of trees) I tend to reason about source code intuitively.Well this is going to sound bad, but you either use reason or intuition. I don't see how one can reason intuitively.
Feb 03 2013
On Monday, 4 February 2013 at 05:32:39 UTC, Andrei Alexandrescu wrote:On 2/3/13 11:00 PM, David Nadlinger wrote:It was my understanding that once a function is declared a property, it is meant to emulate a field. In such circumstance, there were talks about plain and simply not allowing taking the address of an property function. 2 questions: 1. Was this proposal rejected, or have we just forgotten about it? 2. What are the actual use cases for taking the address of a property function? Unless I'm mistaken, the "entire mess" of &a.b would be solved if we simply recognized it as "but you aren't allowed to take the address of the function b, so why have a syntax to support it anyways"? In such circumstance, "&a.b" == "&(a.b)" == "the address of the thing obtaining by running a.b"The problem I see is that usually, one can insert grouping pairs of parentheses into an expression according to the operator precedence/associativity rules at will without changing the result. This isn't merely a theoretical exercise, but the way (well, in the form of trees) I tend to reason about source code intuitively.Well this is going to sound bad, but you either use reason or intuition. I don't see how one can reason intuitively.Now, grouping the expression »&a.b« according to the precedence rules yields »&(a.b)« – but in your proposal, they mean completely different things.I agree they mean different things. I'm unclear that's a problem. All your examples stop here, there's no propagation of the issue. To take the address of a property, one writes &obj.prop. To take the address of a property's result, one writes &(obj.prop). And that's that. It all works with typeof. [SNIP] Andrei
Feb 03 2013
On 2/4/13 2:10 AM, monarch_dodra wrote:It was my understanding that once a function is declared a property, it is meant to emulate a field. In such circumstance, there were talks about plain and simply not allowing taking the address of an property function. 2 questions: 1. Was this proposal rejected, or have we just forgotten about it?Well I at least haven't forgotten. Generally in D we don't want to 100% disallow doing something sensible.2. What are the actual use cases for taking the address of a property function? Unless I'm mistaken, the "entire mess" of &a.b would be solved if we simply recognized it as "but you aren't allowed to take the address of the function b, so why have a syntax to support it anyways"? In such circumstance, "&a.b" == "&(a.b)" == "the address of the thing obtaining by running a.b"Yes, if we disallowed address taking things would get a bit simpler. Andrei
Feb 04 2013
On Mon, 04 Feb 2013 06:47:26 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 2/4/13 2:10 AM, monarch_dodra wrote:Basically any time you have a use case for creating a delegate that returns a field or a property value. Instead of creating a wrapping delegate to call a function, it would make more sense to access the delegate directly. In other words, the use case isn't important, what we are doing here is creating an optimization. If the compiler could do that automatically, I think that would be fine too.It was my understanding that once a function is declared a property, it is meant to emulate a field. In such circumstance, there were talks about plain and simply not allowing taking the address of an property function. 2 questions: 1. Was this proposal rejected, or have we just forgotten about it?Well I at least haven't forgotten. Generally in D we don't want to 100% disallow doing something sensible.2. What are the actual use cases for taking the address of a property function?Elsewhere you shot down my idea of __traits(getDelegate) generically because we already have this possibility: void foo(int) {} void foo(string) {} void delegate(string) dg = &foo; // select string overload What if we use the same exception for properties? property int foo(); auto x = &foo; // error int delegate() x = &foo; // ok -SteveUnless I'm mistaken, the "entire mess" of &a.b would be solved if we simply recognized it as "but you aren't allowed to take the address of the function b, so why have a syntax to support it anyways"? In such circumstance, "&a.b" == "&(a.b)" == "the address of the thing obtaining by running a.b"Yes, if we disallowed address taking things would get a bit simpler.
Feb 04 2013
On Monday, 4 February 2013 at 16:01:45 UTC, Steven Schveighoffer wrote:property int foo(); auto x = &foo; // error int delegate() x = &foo; // ok -SteveI was going to submit the same suggestion, but didn't find time to until just now. gets my vote.
Feb 04 2013
On 2/4/13 11:01 AM, Steven Schveighoffer wrote:property int foo(); auto x = &foo; // error int delegate() x = &foo; // okThat's an interesting idea. I'm a bit weary about it though. At least for properties I'm inclined toward starting real tight with address-of disabled and relax the rules later. Andrei
Feb 04 2013
On Mon, 04 Feb 2013 17:23:25 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 2/4/13 11:01 AM, Steven Schveighoffer wrote:Did you mean wary? In any case, that certainly is a defensible plan. We do have the workaround of declaring an extra delegate (and someone probably can come up with some template magic which does it). If we make it illegal, it gives us the option of coming up with a good solution later if needed. -Steveproperty int foo(); auto x = &foo; // error int delegate() x = &foo; // okThat's an interesting idea. I'm a bit weary about it though. At least for properties I'm inclined toward starting real tight with address-of disabled and relax the rules later.
Feb 05 2013
On Monday, 4 February 2013 at 11:47:25 UTC, Andrei Alexandrescu wrote:Yes, if we disallowed address taking things would get a bit simpler.The address taking of ?
Feb 04 2013
On 2/4/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I'm unclear that's a problem.The problem is you cannot replace a field with a property function without breaking user-code when you take into account operator overloading. Consider: struct S { S opBinary(string op : "&", S)(S s) { return this; } } struct M { S s; } void main() { M m; auto s = m.s & m.s; // ok } Suppose you want to turn 's' into a read-only property, so you write: struct S { S opBinary(string op : "&", S)(S s) { return this; } } struct M { property S s() { return _s; } private S _s; } void main() { M m; auto s = m.s & m.s; // fail } Now the user-code fails. I really don't understand the benefit of semantics based on whether there are parens involved. It's especially odd when we're arguing that functions can be called with or without parens (no semantic difference), yet getting an address depends on any parens involved. Requiring an address of a property function should be rare, therefore we shouldn't have to introduce special syntax rules for such a rare action. I'd argue we should introduce a trait or an .addrOf property.
Feb 04 2013
2013/2/4 Andrej Mitrovic <andrej.mitrovich gmail.com>On 2/4/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:As an essential question, how often occurs rewriting fields to property? As far as I thought, such rewriting will cause: 1. compile error by type mismatch (if you use &obj.field), 2. or, success of compilation *without any semantic breaking* (if you don't use &obj.field). I think the result is not so harmful.I'm unclear that's a problem.The problem is you cannot replace a field with a property function without breaking user-code when you take into account operator overloading. Consider:struct S { S opBinary(string op : "&", S)(S s) { return this; } } struct M { S s; } void main() { M m; auto s = m.s & m.s; // ok } Suppose you want to turn 's' into a read-only property, so you write: struct S { S opBinary(string op : "&", S)(S s) { return this; } } struct M { property S s() { return _s; } private S _s; } void main() { M m; auto s = m.s & m.s; // fail } Now the user-code fails.This is not correct."m.s & m.s" is always parsed as binary bitwise AND expression. So there is no address expression. Kenji Hara
Feb 04 2013
And how often do you think you'll find yourself in the situation of needing to get a delegate from a property anyway? Can't we just make » property getter expressions are always equivalent to their return value« a hard (simple!) rule and add something like __traits(propertyGetter, ...) for the rare cases where you really need to get hold of the underlying function?As a beginner D user this seems like a far better solution, it's much clearer and doesn't violate one's normal understanding of parentheses (which is exactly as you've outlined). &(a.b) feels very much like a hack.
Feb 05 2013
2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>On 2/3/13 3:16 AM, Andrei Alexandrescu wrote: [snip] Some more thinking got me to three simple principles that guide the proposed property design:2. A property may have EXACTLY ONE or EXACTLY TWO parameters, countingthe implicit this parameter if at all. The ONE-parameter version is ALWAYS a getter, and the TWO-parameter version is ALWAYS a setter. There's no variadics, defaulted parameters, and such. Unfortunately, I can present a counterexample. struct S { static int value; static property int foo() { return value; } static property void foo(int n) { value = n; } } void main() { int n = S.foo; S.foo = 1; } Should they be disallowed, as like module level properties? Kenji Hara
Feb 03 2013
On 02/04/2013 03:23 AM, kenji hara wrote:2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org <mailto:SeeWebsiteForEmail erdani.org>> On 2/3/13 3:16 AM, Andrei Alexandrescu wrote: [snip] Some more thinking got me to three simple principles that guide the proposed property design: <http://wiki.dlang.org/DIP23#In_a_nutshell> > 2. A property may have EXACTLY ONE or EXACTLY TWO parameters, counting the implicit this parameter if at all. The ONE-parameter version is ALWAYS a getter, and the TWO-parameter version is ALWAYS a setter. There's no variadics, defaulted parameters, and such. Unfortunately, I can present a counterexample. struct S { static int value; static property int foo() { return value; } static property void foo(int n) { value = n; } } void main() { int n = S.foo; S.foo = 1; } Should they be disallowed, as like module level properties? Kenji HaraProbably. (static essentially means module-level, but in a potentially nested name space.)
Feb 03 2013
On Monday, 4 February 2013 at 02:36:41 UTC, Timon Gehr wrote:On 02/04/2013 03:23 AM, kenji hara wrote:I disagree. Static properties can be allowed because they're not ambiguous. The problem with module-level: property void foo(int n) {} ...are the two interpretations of foo as either a setter taking an int or a getter property of int type. So, one of those interpretations must be disallowed. But, with static member properties, there aren't multiple interpretations.Unfortunately, I can present a counterexample. struct S { static int value; static property int foo() { return value; } static property void foo(int n) { value = n; } } void main() { int n = S.foo; S.foo = 1; } Should they be disallowed, as like module level properties? Kenji HaraProbably. (static essentially means module-level, but in a potentially nested name space.)
Feb 03 2013
Am Mon, 04 Feb 2013 04:24:46 +0100 schrieb "TommiT" <tommitissari hotmail.com>:On Monday, 4 February 2013 at 02:36:41 UTC, Timon Gehr wrote:"getter property of int type" But a getter shouldn't return void, right? So it's actually not ambiguous?On 02/04/2013 03:23 AM, kenji hara wrote:I disagree. Static properties can be allowed because they're not ambiguous. The problem with module-level: property void foo(int n) {} ...are the two interpretations of foo as either a setter taking an int or a getter property of int type. So, one of those interpretations must be disallowed. But, with static member properties, there aren't multiple interpretations.Unfortunately, I can present a counterexample. struct S { static int value; static property int foo() { return value; } static property void foo(int n) { value = n; } } void main() { int n = S.foo; S.foo = 1; } Should they be disallowed, as like module level properties? Kenji HaraProbably. (static essentially means module-level, but in a potentially nested name space.)
Feb 03 2013
On 02/04/2013 04:24 AM, TommiT wrote:On Monday, 4 February 2013 at 02:36:41 UTC, Timon Gehr wrote:Well, it is what the proposal says.On 02/04/2013 03:23 AM, kenji hara wrote:I disagree.Unfortunately, I can present a counterexample. struct S { static int value; static property int foo() { return value; } static property void foo(int n) { value = n; } } void main() { int n = S.foo; S.foo = 1; } Should they be disallowed, as like module level properties? Kenji HaraProbably. (static essentially means module-level, but in a potentially nested name space.)Static properties can be allowed because they're not ambiguous. The problem with module-level: property void foo(int n) {} ...are the two interpretations of foo as either a setter taking an int or a getter property of int type. So, one of those interpretations must be disallowed. But, with static member properties, there aren't multiple interpretations.You are right.
Feb 04 2013
On 2/3/13 9:23 PM, kenji hara wrote:2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org <mailto:SeeWebsiteForEmail erdani.org>> On 2/3/13 3:16 AM, Andrei Alexandrescu wrote: [snip] Some more thinking got me to three simple principles that guide the proposed property design: <http://wiki.dlang.org/DIP23#In_a_nutshell> > 2. A property may have EXACTLY ONE or EXACTLY TWO parameters, counting the implicit this parameter if at all. The ONE-parameter version is ALWAYS a getter, and the TWO-parameter version is ALWAYS a setter. There's no variadics, defaulted parameters, and such. Unfortunately, I can present a counterexample. struct S { static int value; static property int foo() { return value; } static property void foo(int n) { value = n; } } void main() { int n = S.foo; S.foo = 1; } Should they be disallowed, as like module level properties?Yes. No static properties. Andrei
Feb 03 2013
On Sunday, February 03, 2013 22:06:27 Andrei Alexandrescu wrote:Yes. No static properties.So, properties such as Duration.max would simply be normal functions called without parens if they have they have to be property functions rather than variables or enums? - Jonathan M Davis
Feb 03 2013
On Sun, 03 Feb 2013 22:06:27 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 2/3/13 9:23 PM, kenji hara wrote:Hm... can't see the reason why. Static properties play no part in UFCS (which is what makes global properties confusing). I hope it's not because you like your new nutshell rules too much... Then again, properties are for syntax, easy enough to make functions instead. -Steve2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org <mailto:SeeWebsiteForEmail erdani.org>> On 2/3/13 3:16 AM, Andrei Alexandrescu wrote: [snip] Some more thinking got me to three simple principles that guide the proposed property design: <http://wiki.dlang.org/DIP23#In_a_nutshell> > 2. A property may have EXACTLY ONE or EXACTLY TWO parameters, counting the implicit this parameter if at all. The ONE-parameter version is ALWAYS a getter, and the TWO-parameter version is ALWAYS a setter. There's no variadics, defaulted parameters, and such. Unfortunately, I can present a counterexample. struct S { static int value; static property int foo() { return value; } static property void foo(int n) { value = n; } } void main() { int n = S.foo; S.foo = 1; } Should they be disallowed, as like module level properties?Yes. No static properties.
Feb 03 2013
On Sunday, February 03, 2013 03:16:08 Andrei Alexandrescu wrote:Destroy.Another thing to consider would be to allow putting property on a variable with the idea that variables marked as such would not be usable in any situation where a property function wouldn't be - such as taking their address or passing them by ref. That would reduce code breakage when switching between public variables and property functions. The alternative would be to make it so that putting property on a variable would lower it to property functions. So, struct S { property int prop; } becomes something like struct S { private int __prop; property int prop() safe inout pure nothrow { return __prop; } property int prop(int value) safe pure nothrow { return __prop = value; } } One of the main ideas behind properties is to make it so that you can make something a variable when you don't the extra boilerplate for setter and getter functions (e.g. because you don't need to check the value it's being set to), but it's still easy to swap it out with an actual getter and setter function later when you actually _do_ need extra stuff in those functions. And if we don't do something to indicate that a variable could be swapped out with a property function later, then you risk code doing stuff like taking its address or passing it by ref, and that code will then break if the variable ever does become a property function. - Jonathan M Davis
Feb 03 2013
On Monday, 4 February 2013 at 04:45:27 UTC, Jonathan M Davis wrote:On Sunday, February 03, 2013 03:16:08 Andrei Alexandrescu wrote:If we consider a variable marked as property as a variable whose access is restricted, then the following should be also illegal uses of it: 1) calling its non-const method 2) mutating its data field If we consider a variable marked as property as lowered to getter and setter properties, then it doesn't have those restrictions. This is what I would advocate.Destroy.Another thing to consider would be to allow putting property on a variable with the idea that variables marked as such would not be usable in any situation where a property function wouldn't be - such as taking their address or passing them by ref. [..]
Feb 03 2013
From DIP: If prop is a property, &prop or a.prop obey the normal rules... I think there missing '&' before a.prop: If prop is a property, &prop or &a.prop obey the normal rules...
Feb 04 2013
On 02/03/2013 03:16 AM, Andrei Alexandrescu wrote:Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 We got input from DIP21 (which we didn't want to clobber, hence the new DIP) and the recent discussion. The proposal probably won't be accepted in its current form because it breaks some code. We hope to bring it to good shape with everyone's help. In brief: * Optional parens stay. * Just mentioning a function or method without parens does NOT automatically take its address. (This is a change from the current behavior.) * Read properties (using property) work as expected with the mention that they may NOT be called with the parens. Any parens would apply to the returned value. * Write properties (using property) may only be used in the assignment form (no function-style call allowed). It is understood that the current proposal is just a draft and there must be quite a few corner cases it doesn't discuss. We also understand it's impossible to reconcile all viewpoints and please all tastes. Our hope is to get to a point where the rules are self-consistent, meaningful, and complete. Destroy. AndreiThis would be a huge step up from the current properties. Thank you for listening and being rigorous. ------ There are a couple things in the DIP that I might be able to destroy; here's the first: the property rewrite is chosen based on whether it compiles or not. I don't like the rule and its potential ambiguities. When I was attempting a property rewrite patch for DMD, one of the first things I did was match the different contexts a property expression may appear in: - read-only - read-write - write-only In read-only contexts, stuff like "q = prop;" or "auto foo(T)(T x); ... foo(prop);" should only call the getter. In read-write context, the full rewrite is applied. "prop++" expands to "(auto t = prop, t++, prop = t);". This could include things like appearing as the argument to a function's ref parameter, but I've been convinced at one point that it might be wiser to disallow that (unfortunately, I forget /why/). In write-only contexts, only the setter is applied. This is stuff like "prop = q;" or "auto foo(T)(out T x); ... foo(prop);". ------ I would suggest guaranteeing that the property rewrite will evaluate the getter/setter no more than once in an expression. ------ As Jonathan M Davis pointed out, it should be possible to mark fields as property and forbid address-of on such members. ------ I also think that allowing address-of on properties is dubious. I've mentioned that in another response. There is no easy way to make address-of do the same thing for variables and for properties, so to make properties work consistently in the transition between POD to calculated data, it is easiest to just forbid address-of. I think that allowing getters to return lvalues is dangerous in general. It could create ambiguities in the writer's intentions with getter/setter pairs: did they want prop++ to expand to (prop++) or (auto t = prop, t++, t = prop)? I think the latter should always be chosen, and the whole example should never compile if they only provide a getter.
Feb 04 2013
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 We got input from DIP21 (which we didn't want to clobber, hence the new DIP) and the recent discussion. The proposal probably won't be accepted in its current form because it breaks some code. We hope to bring it to good shape with everyone's help. In brief: * Optional parens stay. * Just mentioning a function or method without parens does NOT automatically take its address. (This is a change from the current behavior.) * Read properties (using property) work as expected with the mention that they may NOT be called with the parens. Any parens would apply to the returned value. * Write properties (using property) may only be used in the assignment form (no function-style call allowed). It is understood that the current proposal is just a draft and there must be quite a few corner cases it doesn't discuss. We also understand it's impossible to reconcile all viewpoints and please all tastes. Our hope is to get to a point where the rules are self-consistent, meaningful, and complete. Destroy. AndreiIMO the concept of emulating a field with a function is proving to be an idea that should be simplified. Just look at the huge amount of wasted effort on these discussions, We have at least 5 threads open, two open DIPS and two superseded DIPS. As it stands, I don't even know why there's such a strong desire to have properties that emulate variables. I read the arguments in favor, and they are all very weak IMO, and probably will result in maintenance issues. We all seem to be getting along just fine without full variable emulation, and what we have now for property seems good enough (although I agree it could be done better with a few simple adjustments). If we must keep property, then my advice is to keep the emulation simple and restricted to the cases where it can work without acrobatics (eg no address taking, no pass by ref or return by ref). What I see being proposed is going too far for very little gain. BTW, I am wondering if the idea of "memberspaces" was considered, and if it was considered, then why was it dropped? I won't argue for them in here, just would like to know what the thinking is because I don't recall any feedback from Walter or Andrei. --rt
Feb 04 2013
On 2/4/13 1:15 PM, Rob T wrote:BTW, I am wondering if the idea of "memberspaces" was considered, and if it was considered, then why was it dropped?An idea that departs considerably from the current status in D has a disadvantage compared to an idea that makes things work within the property framework. Andrei
Feb 04 2013
On Monday, February 04, 2013 23:56:50 kenji hara wrote:2013/2/4 Andrej Mitrovic <andrej.mitrovich gmail.com>There's also the issue a variable being able to be passed by ref, which a property function can't emulate, which is why it would be quite valuable to be able to mark a variable as property - either to indicate that it's illegal to do anything with it that you can't do with a property function or to make it so that it lowers to getter and setter property functions and therefore can't be used with anything which wouldn't work with a property function. But if we could guarantee that swapping out variables and property functions wouldn't break code, then we could get rid of a _lot_ of property functions (since many of them don't do anything other than set and/or return the variable that they're wrapping). Because we currently allow stuff which only works with a variable or a function, we can't just seamlessly between variables and property functions, and it's not going to happen anywhere near as often for fear of breaking code. And many more people will simply create useless wrapper property functions around variables in case they need to add more code to them later (e.g. to validate the argument to the setter). We'd be much better off if anything which wasn't legal for both variables and property functions was made illegal for property functions and added a way to do the same for variables which are supposed to be treated as properties rather than explicitly being intended to be public variables like in a POD type. We could save a lot of boilerplate code if we can simply make it variables and property functions guaranteed to be swappable without breaking code. - Jonathan M DavisOn 2/4/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I'm unclear that's a problem.The problem is you cannot replace a field with a property function without breaking user-code when you take into account operatoroverloading. Consider:As an essential question, how often occurs rewriting fields to property? As far as I thought, such rewriting will cause: 1. compile error by type mismatch (if you use &obj.field), 2. or, success of compilation *without any semantic breaking* (if you don't use &obj.field). I think the result is not so harmful.
Feb 04 2013
On 2/4/13 2:04 PM, Jonathan M Davis wrote:We could save a lot of boilerplate code if we can simply make it variables and property functions guaranteed to be swappable without breaking code.I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables. Andrei
Feb 04 2013
On Monday, February 04, 2013 17:28:24 Andrei Alexandrescu wrote:On 2/4/13 2:04 PM, Jonathan M Davis wrote:Yes. There are things that propery functions need to emulate from normal variables (hence the rewrites with ++ and += and whatnot), and there are of course things that they can't emulate (like taking the address of a variable). But what we also need is a way to mark a variable as a property and then make it so such a variable and property functions have the same capabilities so that you're guaranteed to be able to swap between the two without breaking code. As soon as one of the two has capabilities that the other doesn't have, or there's a major semantic change between them (like taking the address works on one but not the other or the type returned by taking the address differs), then you can't do that. Which is why I would argue that we need to be able to mark variables with property (which either makes it so that you can't do anything with them that you can't do with a property function or makes it so that it lowers to property functions for getting and setting), and we need to disallow taking the address of property functions as well as anything else that you could do with a variable that we can't emulate with a property function. - Jonathan M DavisWe could save a lot of boilerplate code if we can simply make it variables and property functions guaranteed to be swappable without breaking code.I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables.
Feb 04 2013
On 2013-02-04 23:52, Jonathan M Davis wrote:Which is why I would argue that we need to be able to mark variables with property (which either makes it so that you can't do anything with them that you can't do with a property function or makes it so that it lowers to property functions for getting and setting), and we need to disallow taking the address of property functions as well as anything else that you could do with a variable that we can't emulate with a property function.They need to be lowered to methods. Otherwise you cannot switch from a method to a field, since methods are virtual and can be overridden in unknown subclasses. -- /Jacob Carlborg
Feb 05 2013
On 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:On 2/4/13 2:04 PM, Jonathan M Davis wrote:I agree with Jonathan. Please do not make them a subset. Make them as identical as possible. The subset thing makes them no longer "swappable". Allow variables to be marked with property to limit them to operations that property functions can do, and make sure property functions are limited to what property variables can do (ex: no address-of!). With that in hand, they'll be very swappable.We could save a lot of boilerplate code if we can simply make it variables and property functions guaranteed to be swappable without breaking code.I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables. Andrei
Feb 04 2013
On 2/4/13 10:30 PM, Chad Joan wrote:On 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:The purpose is to replace members with properties, not to change one's mind back and forth. There will be no marking of variables with property as that can be easily achieved by actually making them properties. AndreiOn 2/4/13 2:04 PM, Jonathan M Davis wrote:I agree with Jonathan. Please do not make them a subset. Make them as identical as possible. The subset thing makes them no longer "swappable". Allow variables to be marked with property to limit them to operations that property functions can do, and make sure property functions are limited to what property variables can do (ex: no address-of!). With that in hand, they'll be very swappable.We could save a lot of boilerplate code if we can simply make it variables and property functions guaranteed to be swappable without breaking code.I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables. Andrei
Feb 04 2013
On 02/04/2013 11:18 PM, Andrei Alexandrescu wrote:On 2/4/13 10:30 PM, Chad Joan wrote:Why not allow one to change their mind back and forth? That would be far more useful from a design perspective. With what you're proposing, there is no migration path for variables. They are not swappable at all. Once someone takes the address of your "public int foo;" it will no longer be possible to turn it into a property without breaking API. Going even further, suppose we allow property variables and also allow address-of on property functions only (a subset relationship!). Now it is possible to make a "public property int foo;" that can be migrated to a full-fledged property later without some god-awful boilerplate. However, the developer will hesitate to make such a change: converting property variables to property functions is a liability. Once you convert, you can't convert back without breaking API. At that point the hypothetical developer wonders: "why am I using property variables in the first place? I can't migrate them because of the liability, which makes them no more useful than public variables that break encapsulation." At that point the whole concept goes out the window and we're back in Java writing drivel like this: class XYZ { int m_foo; int getFoo() { return m_foo; } void setFoo(int val) { m_foo = val; } ... } I'm arguing the point because I'd much rather write this: class XYZ { property int foo; ... }On 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:The purpose is to replace members with properties, not to change one's mind back and forth. There will be no marking of variables with property as that can be easily achieved by actually making them properties. AndreiOn 2/4/13 2:04 PM, Jonathan M Davis wrote:I agree with Jonathan. Please do not make them a subset. Make them as identical as possible. The subset thing makes them no longer "swappable". Allow variables to be marked with property to limit them to operations that property functions can do, and make sure property functions are limited to what property variables can do (ex: no address-of!). With that in hand, they'll be very swappable.We could save a lot of boilerplate code if we can simply make it variables and property functions guaranteed to be swappable without breaking code.I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables. Andrei
Feb 04 2013
On Monday, February 04, 2013 23:18:57 Andrei Alexandrescu wrote:On 2/4/13 10:30 PM, Chad Joan wrote:One of the main purposes generally given for having properties is so that you can make them public variables when you don't need them to do anything but get and set the member variable, but you can still make it a function later when you need to add other stuff to it (such as checking the value that it's being set to). One of the primary reasons for making a property function act like a variable is precisely so that you can switch between variables and functions when refactoring without breaking code. Also, being able to mark variables as property would save us a lot of boilerplate. Instead, it's incredibly common to do stuff like struct S { property int prop() safe const pure nothrow { return _prop; } property int prop(int value) safe pure { return _prop = value; } private int _prop; } That's a lot of extra code just to buy some encapsulation. If we could do struct S { property int prop; } we could really reduce the amount of boilerplate code surrounding member variables. Even if putting property on a variable simply lowered to the property functions rather than it still be a variable, it would be a big help. But without either that or marking variables with property so that you can't do anything to them that you can't do to a property function, we lose the ability to make a property a variable when the getters and setters are unnecessary, and that means that we're stuck with a lot of extra boilerplate. - Jonathan M DavisOn 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:The purpose is to replace members with properties, not to change one's mind back and forth. There will be no marking of variables with property as that can be easily achieved by actually making them properties.On 2/4/13 2:04 PM, Jonathan M Davis wrote:I agree with Jonathan. Please do not make them a subset. Make them as identical as possible. The subset thing makes them no longer "swappable". Allow variables to be marked with property to limit them to operations that property functions can do, and make sure property functions are limited to what property variables can do (ex: no address-of!). With that in hand, they'll be very swappable.We could save a lot of boilerplate code if we can simply make it variables and property functions guaranteed to be swappable without breaking code.I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables. Andrei
Feb 04 2013
On 2013-02-05 07:13, Jonathan M Davis wrote:One of the main purposes generally given for having properties is so that you can make them public variables when you don't need them to do anything but get and set the member variable, but you can still make it a function later when you need to add other stuff to it (such as checking the value that it's being set to). One of the primary reasons for making a property function act like a variable is precisely so that you can switch between variables and functions when refactoring without breaking code. Also, being able to mark variables as property would save us a lot of boilerplate. Instead, it's incredibly common to do stuff like struct S { property int prop() safe const pure nothrow { return _prop; } property int prop(int value) safe pure { return _prop = value; } private int _prop; } That's a lot of extra code just to buy some encapsulation. If we could do struct S { property int prop; } we could really reduce the amount of boilerplate code surrounding member variables. Even if putting property on a variable simply lowered to the property functions rather than it still be a variable, it would be a big help. But without either that or marking variables with property so that you can't do anything to them that you can't do to a property function, we lose the ability to make a property a variable when the getters and setters are unnecessary, and that means that we're stuck with a lot of extra boilerplate.I fully agree. But they do need to be lowered to methods, see: http://forum.dlang.org/thread/kel6c8$1h5d$1 digitalmars.com?page=17#post-keqfol:242un9:241:40digitalmars.com -- /Jacob Carlborg
Feb 05 2013
On 2013-02-05 07:13, Jonathan M Davis wrote:One of the main purposes generally given for having properties is so that you can make them public variables when you don't need them to do anything but get and set the member variable, but you can still make it a function later when you need to add other stuff to it (such as checking the value that it's being set to). One of the primary reasons for making a property function act like a variable is precisely so that you can switch between variables and functions when refactoring without breaking code. Also, being able to mark variables as property would save us a lot of boilerplate. Instead, it's incredibly common to do stuff like struct S { property int prop() safe const pure nothrow { return _prop; } property int prop(int value) safe pure { return _prop = value; } private int _prop; } That's a lot of extra code just to buy some encapsulation. If we could do struct S { property int prop; } we could really reduce the amount of boilerplate code surrounding member variables. Even if putting property on a variable simply lowered to the property functions rather than it still be a variable, it would be a big help. But without either that or marking variables with property so that you can't do anything to them that you can't do to a property function, we lose the ability to make a property a variable when the getters and setters are unnecessary, and that means that we're stuck with a lot of extra boilerplate.BTW, if it does get lowered to methods, do we want to be able to access the instance variable directly? I think it's good to be able to bypass the setter/getter sometimes internally. Alternatively there could be a __traits to access the instance variable. -- /Jacob Carlborg
Feb 05 2013
On Tuesday, February 05, 2013 09:34:06 Jacob Carlborg wrote:BTW, if it does get lowered to methods, do we want to be able to access the instance variable directly?No, because the variable would presumably end up with a compiler-chosen name which would presumably be implementation-dependent. All that the programmer has defined is the name of the property, not the name of the underlying variable. And for the most part, it wouldn't matter. For structs, inlining would fix the problem, and for classes, if you really want to be able to access the member variable directly for efficiency, you can always declare the property functions explicitly. - Jonathan M Davis
Feb 05 2013
On 02/05/2013 12:34 PM, Jacob Carlborg wrote:On 2013-02-05 07:13, Jonathan M Davis wrote:I like the general idea. But to access variable one can still use tupleof, so there should be a guarantee that the hidden field layout is the same as if it was declared as variable.One of the main purposes generally given for having properties is so that you can make them public variables when you don't need them to do anything but get and set the member variable, but you can still make it a function later when you need to add other stuff to it (such as checking the value that it's being set to). One of the primary reasons for making a property function act like a variable is precisely so that you can switch between variables and functions when refactoring without breaking code. Also, being able to mark variables as property would save us a lot of boilerplate. Instead, it's incredibly common to do stuff like struct S { property int prop() safe const pure nothrow { return _prop; } property int prop(int value) safe pure { return _prop = value; } private int _prop; } That's a lot of extra code just to buy some encapsulation. If we could do struct S { property int prop; } we could really reduce the amount of boilerplate code surrounding member variables. Even if putting property on a variable simply lowered to the property functions rather than it still be a variable, it would be a big help. But without either that or marking variables with property so that you can't do anything to them that you can't do to a property function, we lose the ability to make a property a variable when the getters and setters are unnecessary, and that means that we're stuck with a lot of extra boilerplate.BTW, if it does get lowered to methods, do we want to be able to access the instance variable directly? I think it's good to be able to bypass the setter/getter sometimes internally. Alternatively there could be a __traits to access the instance variable.
Feb 05 2013
On 2013-02-05 10:10, Dmitry Olshansky wrote:I like the general idea. But to access variable one can still use tupleof, so there should be a guarantee that the hidden field layout is the same as if it was declared as variable.As long as accessing it via tupleof works it would be fine. A serializer would be quite crippled otherwise. -- /Jacob Carlborg
Feb 05 2013
On 02/04/2013 11:18 PM, Andrei Alexandrescu wrote:On 2/4/13 10:30 PM, Chad Joan wrote:Related: Is there some reason why we /need/ to be able to take the address of properties? Wouldn't something like 'someFunc(PropAccessor!"prop"(foo))' work in cases where we need a generic way to defer reads and writes? For clarity: auto PropAccessor(string propertyStr, T)( T tinstance ) { struct Accessor(string propertyStr, U) { private U tinstance; auto get() { mixin("return tinstance."~propertyStr~";"); } // I had to put system here to shut up a compiler error. Bug? system void set(V)(V val) { mixin("tinstance."~propertyStr~" = val;"); } } Accessor!(propertyStr, T) acc; acc.tinstance = tinstance; return acc; } auto PtrAccessor(T)( T* payload ) { struct Accessor(U) { private U* payload; U get() { return *payload; } U set(U val) { return *payload = val; } } Accessor!(T) acc; acc.payload = payload; return acc; } template isAccessor(Acc) { Acc a; static if ( __traits(compiles, { auto x = a.get(); } ) && __traits(compiles, a.set(a.get())) ) const bool isAccessor = true; else const bool isAccessor = false; } // Function that accepts the be-all-end-all of reference types. auto someFunc(Acc)(Acc qux) if ( isAccessor!(Acc) ) { auto x = qux.get(); x |= 0xF00D; qux.set(x); return qux.get(); } struct MyStruct { private int m_q; property int q() { return m_q; } property void q(int v) { m_q = v; } } unittest { MyStruct s; s.q = 0; int abc = 0; assert(someFunc(PtrAccessor(&abc)) == 0xF00D); assert(someFunc(PropAccessor!"q"(s)) == 0xF00D); } void main() { }I agree with Jonathan. Please do not make them a subset. Make them as identical as possible. The subset thing makes them no longer "swappable". Allow variables to be marked with property to limit them to operations that property functions can do, and make sure property functions are limited to what property variables can do (ex: no address-of!). With that in hand, they'll be very swappable.The purpose is to replace members with properties, not to change one's mind back and forth. There will be no marking of variables with property as that can be easily achieved by actually making them properties. Andrei
Feb 04 2013
On 2013-02-05 05:18, Andrei Alexandrescu wrote:The purpose is to replace members with properties, not to change one's mind back and forth. There will be no marking of variables with property as that can be easily achieved by actually making them properties.Why not? That will just require needless boilerplate code, wrappers just forwarding to instance variables. I have wanted to have this since the introduction of the property keyword. -- /Jacob Carlborg
Feb 05 2013
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23 We got input from DIP21 (which we didn't want to clobber, hence the new DIP) and the recent discussion. The proposal probably won't be accepted in its current form because it breaks some code. We hope to bring it to good shape with everyone's help. In brief: * Optional parens stay. * Just mentioning a function or method without parens does NOT automatically take its address. (This is a change from the current behavior.) * Read properties (using property) work as expected with the mention that they may NOT be called with the parens. Any parens would apply to the returned value. * Write properties (using property) may only be used in the assignment form (no function-style call allowed). It is understood that the current proposal is just a draft and there must be quite a few corner cases it doesn't discuss. We also understand it's impossible to reconcile all viewpoints and please all tastes. Our hope is to get to a point where the rules are self-consistent, meaningful, and complete. Destroy. Andreihttp://forum.dlang.org/thread/ririagrqecshjljcdubd forum.dlang.org Smash.
Feb 04 2013
On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM, Jonathan M Davis wrote:This is the primary real-world proble to solve. If tackle it right we'd secure a sizable flow of Java converts simply because of this feature alone ;) More seriously I believe it's worth noting that properties can't emulate (in principle) exactly one aspect of variable - taking address as a pointer. Honestly I can't see a way to overcome it without introducing a user-defined way to impose this restriction on a field of a struct/class. Then keeping in mind __traits I have the following clause to add to the current proposal: Inside of aggregate a field marked with property indicate is semantically equivalent to compiler wrapping it with trivial getter and setter. Example: struct Foo{ property T x; } treated semantically as if: T __x; // hidden by compiler //templated to have deduced safe, pure, nothrow property T x()()inout{ return x; } property void x()(T val){ x = val; } --- Dmitry OlshanskyWe could save a lot of boilerplate code if we can simply make it variables and property functions guaranteed to be swappable without breaking code.I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables.
Feb 05 2013
On 2/5/13 3:39 AM, Dmitry Olshansky wrote:On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM, Jonathan M Davis wrote: >> We could save a lot of boilerplate code if we can simply make it >> variables and >> property functions guaranteed to be swappable without breaking code. > > I think this is quite powerful. The way we can do this is by making > properties emulate a subset of actual variables. > This is the primary real-world proble to solve.The problem with this approach is feature creep - there will always be yet another possible case in which a feature helps some case. We need to put a halt on that. Unprotected, unchecked member variables that can be get and set without any hooks into the enclosing structure are rare. That's not the case we should help and cater for. When that's the case, the entire object is legitimately a "bag of values" that has only public data. Andrei
Feb 05 2013
On 02/05/2013 08:31 AM, Andrei Alexandrescu wrote:On 2/5/13 3:39 AM, Dmitry Olshansky wrote:Rare? What? No. Where is your data? My anecdotal experience is contradictory. I tend to end up with A LOT of things that I'd like to make into public variables but don't due to the risk of breaking encapsulation. The boilerplate can really suck. I would argue that being able to do the /right/ thing in a /convenient/ way is a very important feature. I also do not see how this would lead to more features. If anything, everyone seems to draw the line at address-of: it's a potential feature that we /don't/ want because it's too complicated and introduces harmful semantics. There are a finite amount of features that are needed to make D's property implementation very complete. Throw them all on the table and D will have /the best/ property implementation. If, instead, you are chintzy and give people only some of them, then you will get constant property discussions on the news group and it will /seem/ like you're having to implement an endless stream of features.On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM, Jonathan M Davis wrote:The problem with this approach is feature creep - there will always be yet another possible case in which a feature helps some case. We need to put a halt on that. Unprotected, unchecked member variables that can be get and set without any hooks into the enclosing structure are rare. That's not the case we should help and cater for. When that's the case, the entire object is legitimately a "bag of values" that has only public data. AndreiThis is the primary real-world proble to solve.We could save a lot of boilerplate code if we can simply make it variables and property functions guaranteed to be swappable without breaking code.I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables.
Feb 05 2013
On 02/05/2013 08:31 AM, Andrei Alexandrescu wrote:On 2/5/13 3:39 AM, Dmitry Olshansky wrote:Hmmm. This statement that unchecked public members are rare makes me wonder if there is a fundamental difference of background here. Things I always get this feeling that Walter and Andrei never truly understood those programmers are very comfortable with properties and know how to use them. Properties are an alien concept in C programming, and probably C++ as well. As a result, I wouldn't be surprised at all of Walter and Andrei haven't really used properties in the same capacity as "unchecked public members are rare". This isn't a bashing post or an ad hominem; I'll try to be informative. ago when I used them (ignoring Java: those programmers use properties a lot, but it is a pain). They did not require an enormous amount of features to gain their power, and D shouldn't either. The primary differences are these: (3) Unambiguous property declaration syntax. implemented property rewrites. It didn't matter because value types are rare. (This may be dated by about 3 years.) I think that those differences are very solvable in D: (1) Disallow address-of on anything dealing with property. No one will miss it; they didn't expect it to exist in the first place. (2) Do semantic rewriting on properties. Once you have semantic rewriting, the value-type-properties problem is SOLVED and never needs to be revisited again. (Disallowing value types in properties would be poor course in a language where user-defined value types are very common.) (3) This is pretty much solved in DIP23 already. huge pain. Just because something /might/ be a property in the future, probably don't believe in "bags of values"; such things are nonsense if you want proper encapsulation! People coming from this background are going to LOVE having a shorthand like "public property int foo;" that removes all of the pain from properly encapsulating public state. Using properties in a properly-constrained system was actually very enjoyable. The above is why I don't see feature creep. The D designers probably don't see where it ends because they've never been to that edge. I worry that I could be totally wrong about Andrei/Walter's experiences in these arenas. I don't assert these notions as truth, but instead as a way of communicating my perceptions. I hope this is informative and not insulting.On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM, Jonathan M Davis wrote:The problem with this approach is feature creep - there will always be yet another possible case in which a feature helps some case. We need to put a halt on that. Unprotected, unchecked member variables that can be get and set without any hooks into the enclosing structure are rare. That's not the case we should help and cater for. When that's the case, the entire object is legitimately a "bag of values" that has only public data. AndreiThis is the primary real-world proble to solve.We could save a lot of boilerplate code if we can simply make it variables and property functions guaranteed to be swappable without breaking code.I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables.
Feb 05 2013
On Tuesday, 5 February 2013 at 15:08:55 UTC, Chad Joan wrote:Hmmm. This statement that unchecked public members are rare makes me wonder if there is a fundamental difference of background here. Things might be much different if you cameWell, Andrei background is easy to check: http://en.wikipedia.org/wiki/Andrei_Alexandrescu ;)
Feb 05 2013
On 02/05/2013 10:11 AM, Dicebot wrote:On Tuesday, 5 February 2013 at 15:08:55 UTC, Chad Joan wrote:I know I know ;) C++ guru, which is why I say what I say. It's still possible that he got a good dosage of property usage somewhere. If that happened and I based an argument off of it, then that would make me an ass. I also wouldn't notice because I don't stalk Andrei ;)Hmmm. This statement that unchecked public members are rare makes me wonder if there is a fundamental difference of background here. ThingsWell, Andrei background is easy to check: http://en.wikipedia.org/wiki/Andrei_Alexandrescu ;)
Feb 05 2013
05-Feb-2013 17:31, Andrei Alexandrescu пишет:On 2/5/13 3:39 AM, Dmitry Olshansky wrote:Thinking more of it with proper properties it would be doable with a half-decent template mixin. Then it'd better be in Phobos one day as that would make it readily accessible but separate from the language. -- Dmitry OlshanskyOn 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM, Jonathan M Davis wrote: >> We could save a lot of boilerplate code if we can simply make it >> variables and >> property functions guaranteed to be swappable without breaking code. > > I think this is quite powerful. The way we can do this is by making > properties emulate a subset of actual variables. > This is the primary real-world proble to solve.The problem with this approach is feature creep - there will always be yet another possible case in which a feature helps some case. We need to put a halt on that. Unprotected, unchecked member variables that can be get and set without any hooks into the enclosing structure are rare. That's not the case we should help and cater for. When that's the case, the entire object is legitimately a "bag of values" that has only public data.
Feb 05 2013
On Tuesday, February 05, 2013 08:31:46 Andrei Alexandrescu wrote:On 2/5/13 3:39 AM, Dmitry Olshansky wrote:Being able to initially use a public variable and then swap it out later for property functions when refactoring is generally the reason that I've heard around here seem to think is a core feature of properties, and a core feature isn't feature creep. And if property on a variable makes it so that it lowers to getter and setter property functions (rather than leaving it as a public variable with certain restrictions on it), then we don't even have to worry about which features of a variable property functions do and don't emulate and whatever feature creep might appear there. The "variable" would immediately match due to the fact that you'd actually end up with property functions. You just wouldn't have had to do all the boilerplate for it.On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM, Jonathan M Davis wrote: >> We could save a lot of boilerplate code if we can simply make it >> variables and >> property functions guaranteed to be swappable without breaking code. > > I think this is quite powerful. The way we can do this is by making > properties emulate a subset of actual variables. This is the primary real-world proble to solve.The problem with this approach is feature creep - there will always be yet another possible case in which a feature helps some case. We need to put a halt on that.Unprotected, unchecked member variables that can be get and set without any hooks into the enclosing structure are rare. That's not the case we should help and cater for. When that's the case, the entire object is legitimately a "bag of values" that has only public data.Really? In my experience they're quite common. It's usually the case that not all of the variables on a type have pass-through getters and setters, but it's quite common to have at least a few which do. It's been brought up a number of times in the past that it would be nice to have property on variables be used to avoid the boilerplate code in those cases. I suppose that we could use a mixin to solve that problem, but then you wouldn't get any documentation on it, since you can't document anything that's mixed in. - Jonathan M Davis
Feb 05 2013
2013/2/6 Jonathan M Davis <jmdavisProg gmx.com>Being able to initially use a public variable and then swap it out later for property functions when refactoring is generally the reason that I've heard people around here seem to think is a core feature of properties, and a core feature isn't feature creep. And if property on a variable makes it so that it lowers to getter and setter property functions (rather than leaving it as a public variable with certain restrictions on it), then we don't even have to worry about which features of a variable property functions do and don't emulate and whatever feature creep might appear there. The "variable" would immediately match due to the fact that you'd actually end up with property functions. You just wouldn't have had to do all the boilerplate for it.I fully agree with Andrei. I can see that swapping public data field to property function call is not rare, but in almost case, such refactoring also intends to add encapsulation. struct S { // Before swapping int _data; // After swapping private int _data; property int data() { return _data; } property void data(int n) { enforce(n > 0); _data = n; } } S s; int n = s.data; s.data = 1; //int* pdata = &s.data; // changed to disallowed ... it is mostly intended.Unprotected, unchecked member variables that can be get and set withoutWrapping a field data with property function but also allow accessing to it directly through pointer is quite rare. struct S { // After swapping private int _data; property ref int data() { return _data; } // ref return property void data(int n) { enforce(n > 0); _data = n; } } S s; int n = s.data; // call getter s.data = 1; // call setter, enforce n > 0 int* pdata = &s.data; // But, if this is allowed, *pdata = -1; // this is accidentally allowed... Is this really intended? To me, it is just a encapsulation breaking. I'm not sure that it is what you would really expect. Kenji Haraany hooks into the enclosing structure are rare. That's not the case we should help and cater for. When that's the case, the entire object is legitimately a "bag of values" that has only public data.Really? In my experience they're quite common. It's usually the case that not all of the variables on a type have pass-through getters and setters, but it's quite common to have at least a few which do. It's been brought up a number of times in the past that it would be nice to have property on variables be used to avoid the boilerplate code in those cases. I suppose that we could use a mixin to solve that problem, but then you wouldn't get any documentation on it, since you can't document anything that's mixed in.
Feb 05 2013
It is not feature creep, it is properties done right. If not done this way, than honestly I don't know what properties are good for any way. We could use set/get methods just as well. If properties done right are feature creep, than properties per se are feature creep, which is debatable. But if we keep them, we should do them right. Maybe you can elaborate what properties are good for, if not for avoiding trivial set/get methods? -> Please really do that, because I am having a hard time understanding your reasoning. On Tue, 2013-02-05 at 08:31 -0500, Andrei Alexandrescu wrote:The problem with this approach is feature creep - there will always be yet another possible case in which a feature helps some case. We need to put a halt on that.
Feb 06 2013
On Tuesday, 5 February 2013 at 08:39:15 UTC, Dmitry Olshansky wrote:On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM, Jonathan M Davis wrote:I'm not really sure which part of my article you are addressing here, but allowing 'opAddress' is available as a last resort. Also note that I had proposed 'cast(function)' instead of '&' to get the top-level function, which, unlike '&', can give: 'Error: not castable as a function'make itWe could save a lot of boilerplate code if we can simplybreaking code.variables and property functions guaranteed to be swappable withoutI think this is quite powerful. The way we can do this is bymakingproperties emulate a subset of actual variables.This is the primary real-world proble to solve. If tackle it right we'd secure a sizable flow of Java converts simply because of this feature alone ;) More seriously I believe it's worth noting that properties can't emulate (in principle) exactly one aspect of variable - taking address as a pointer. Honestly I can't see a way to overcome it without introducing a user-defined way to impose this restriction on a field of a struct/class.Then keeping in mind __traits I have the following clause to add to the current proposal: Inside of aggregate a field marked with property indicate is semantically equivalent to compiler wrapping it with trivial getter and setter. Example: struct Foo{ property T x; } treated semantically as if: T __x; // hidden by compiler //templated to have deduced safe, pure, nothrow property T x()()inout{ return x; } property void x()(T val){ x = val; } --- Dmitry OlshanskyWhile I appreciate your responding to my post, I'm a little confused which of its points you are addressing here.
Feb 05 2013
05-Feb-2013 23:37, Zach the Mystic пишет: [snip]While I appreciate your responding to my post, I'm a little confused which of its points you are addressing here.Sorry, I posted reply to the wrong post. -- Dmitry Olshansky
Feb 05 2013
On Tuesday, 5 February 2013 at 19:44:03 UTC, Dmitry Olshansky wrote:05-Feb-2013 23:37, Zach the Mystic пишет: [snip]I hope this doesn't end up being the primary reason people respond to my posts. :-)While I appreciate your responding to my post, I'm a little confused which of its points you are addressing here.Sorry, I posted reply to the wrong post.
Feb 05 2013
On Wednesday, February 06, 2013 09:56:40 kenji hara wrote:I fully agree with Andrei. I can see that swapping public data field to property function call is not rare, but in almost case, such refactoring also intends to add encapsulation. struct S { // Before swapping int _data; // After swapping private int _data; property int data() { return _data; } property void data(int n) { enforce(n > 0); _data = n; } } S s; int n = s.data; s.data = 1; //int* pdata = &s.data; // changed to disallowed ... it is mostly intended.You misunderstand. We don't _want_ taking the address to work. We _want_ the encapsulation. We just don't want to have to write all of the boilerplate code. The idea is that you want to be able to just make it a variable first, because you don't need to do any extra checks or anything else but get or set the variable. So, having to declare the setters and getters is overkill. The problem is that if you just declare it a variable, then people can take the address of it or pass it by ref - which you don't want. You _want_ the encapsulation up-front. You just don't want to have to bother with all of the boilerplate code required to do it. That's why some of us have suggested making it so that you can mark variables with property. That then either makes it illegal to do anything with it which you couldn't do with a property function (e.g. take its address), or it simply lowers it to the getters and setters, making it so that you _do_ have the property functions in the beginning. You just don't have to write them explicitly. Then later, if refactoring requires that you add additional checks or other operations to the getter and/or setter, then you explicitly declare the property functions. - Jonathan M Davis
Feb 05 2013
On 2/6/13, Jonathan M Davis <jmdavisProg gmx.com> wrote:That's why some of us have suggested making it so that you can mark variables with property.What Jonathan means is this: struct S { int var; // modifiable, can take address } Now suppose later you want to turn var into a property: struct S { property int var(); property void var(int); } This potentially breaks code if the user-code was using a pointer to the public var field in the previous version of your library. So instead we should have the ability to annotate fields with property: struct S { property int var; // modifiable, can *not* take address } There's no run-time cost, but it disallows taking the address of var, and it allows you to introduce property functions in the future without breaking user-code.
Feb 05 2013
On Wednesday, 6 February 2013 at 01:40:37 UTC, Andrej Mitrovic wrote:On 2/6/13, Jonathan M Davis <jmdavisProg gmx.com> wrote:It is also possible to first start with setters/getters and then switch to a public field(!) Which leads to the conclusion, in order for the property abstraction to be complete, address taking of *anything* annotated with property should either NOT be allowed... property int var(); // can *not* take address property void var(int); // can *not* take address property int var; // can *not* take address ... or we have to guarantee that the type remains unchanged... which is problematic due to different types of the getter and setter, which would force one to always specify the expected type rather than relying on auto. property int var; int delegate() d_get = &var; void delegate(int) d_set = &var;That's why some of us have suggested making it so that you can mark variables with property.What Jonathan means is this: struct S { int var; // modifiable, can take address } Now suppose later you want to turn var into a property: struct S { property int var(); property void var(int); } This potentially breaks code if the user-code was using a pointer to the public var field in the previous version of your library. So instead we should have the ability to annotate fields with property: struct S { property int var; // modifiable, can *not* take address } There's no run-time cost, but it disallows taking the address of var, and it allows you to introduce property functions in the future without breaking user-code.
Feb 10 2013
On 02/03/2013 09:16 AM, Andrei Alexandrescu wrote:Walter and I have had a discussion on how to finalize properties. http://wiki.dlang.org/DIP23Could someone summarize the curent state and update the wiki pages accordingly. If the discussion has settled can we bless one of the 3 property DIPs with being approved? Otherwise what work has to be done to get there? http://wiki.dlang.org/DIP21 http://wiki.dlang.org/DIP23 http://wiki.dlang.org/DIP24
Dec 13 2013