www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Possible property compromise

reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
 property has gotten a lot of flak lately, and I think the unenthusiastic  
implementation of it really hasn't helped.

BUT... there are a few problems with the original non- property  
implementation that are fixed by having additional syntax (well, if it was  
properly implemented):

1. Treating any old function as a setter.  This is the writeln = "hi"; mess
2. Forcing you to use 2 sets of parentheses when returning a callable type.

However, we have seen the addition of two problems with  property.  First  
is when UFCS was introduced.

 property int iprop(int val) {...}

can be called as:

52.iprop;

or

iprop = 52;

Second problem is, when ref returns are used on properties:

 property ref int iprop();

auto x = &iprop;

Should x be the delegate for iprop, or call iprop and get the address of  
the return value?

ASIDE from the disdain that many developers have towards  property, I  
think above anything else, that the first problem  property fixed above is  
essential to the freedom of naming functions for API designers.  The  
second problem of getting delegates via properties is fixed,  so it would  
be a step backwards if we just removed  property.

So in light of all that, I propose a compromise:

1. Deprecate  property.
2. When the compiler encounters a field setting like this:

x.y = ...;

If a y field exists on the aggregate represented by x, then that is the  
assumed member being referenced, and compilation continues normally.

If there is no y field, then then the compiler ALSO tries:

x.setY(...);

It is important to note that:

x.y(...);

does not compile, y is not just another function.  To call in function  
form, you must call:

x.setY(...);

That takes care of setters, AND takes care of the new problems with  
 property.

3. Parentheses remain optional on functions, allowing the creation of  
getters as before  property.

However, this does not fix the delegate problem.  To fix that problem, we  
can use the complementary getY to allow specifying a getter that does not  
absorb parentheses.

One problem I will note with this scheme, some Unicode symbols that may be  
valid D symbol starters may NOT have an upper/lower case, making it  
impossible to use those as properties.  But I admit having an English bias  
so I don't see this as a large problem.  Besides, "set" is already English.

Note, I've been doing a lot of Objective C lately, and I kind of like the  
property scheme there (this is quite similar).

Sound crazy?  Ridiculous?  Impossible?  Insulting?

What do you think?

-Steve
Jan 29 2013
next sibling parent "q66" <quaker66 gmail.com> writes:
On Tuesday, 29 January 2013 at 17:10:00 UTC, Steven Schveighoffer 
wrote:
  property has gotten a lot of flak lately, and I think the 
 unenthusiastic implementation of it really hasn't helped.

 BUT... there are a few problems with the original non- property 
 implementation that are fixed by having additional syntax 
 (well, if it was properly implemented):

 1. Treating any old function as a setter.  This is the writeln 
 = "hi"; mess
 2. Forcing you to use 2 sets of parentheses when returning a 
 callable type.

 However, we have seen the addition of two problems with 
  property.  First is when UFCS was introduced.

  property int iprop(int val) {...}

 can be called as:

 52.iprop;

 or

 iprop = 52;

 Second problem is, when ref returns are used on properties:

  property ref int iprop();

 auto x = &iprop;

 Should x be the delegate for iprop, or call iprop and get the 
 address of the return value?

 ASIDE from the disdain that many developers have towards 
  property, I think above anything else, that the first problem 
  property fixed above is essential to the freedom of naming 
 functions for API designers.  The second problem of getting 
 delegates via properties is fixed,  so it would be a step 
 backwards if we just removed  property.

 So in light of all that, I propose a compromise:

 1. Deprecate  property.
 2. When the compiler encounters a field setting like this:

 x.y = ...;

 If a y field exists on the aggregate represented by x, then 
 that is the assumed member being referenced, and compilation 
 continues normally.

 If there is no y field, then then the compiler ALSO tries:

 x.setY(...);
no, just no.
 It is important to note that:

 x.y(...);

 does not compile, y is not just another function.  To call in 
 function form, you must call:

 x.setY(...);

 That takes care of setters, AND takes care of the new problems 
 with  property.

 3. Parentheses remain optional on functions, allowing the 
 creation of getters as before  property.

 However, this does not fix the delegate problem.  To fix that 
 problem, we can use the complementary getY to allow specifying 
 a getter that does not absorb parentheses.

 One problem I will note with this scheme, some Unicode symbols 
 that may be valid D symbol starters may NOT have an upper/lower 
 case, making it impossible to use those as properties.  But I 
 admit having an English bias so I don't see this as a large 
 problem.  Besides, "set" is already English.
"natural language inspiration" ... hmm .. where have I seen this? oh right, let's make a DOBOL.
 Note, I've been doing a lot of Objective C lately, and I kind 
 of like the property scheme there (this is quite similar).

 Sound crazy?  Ridiculous?  Impossible?  Insulting?

 What do you think?

 -Steve
more like all four combined.
Jan 29 2013
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
Not awful... but what about opDispatch setters?

Perhaps we could do it this way:


void opSet(string variable, T)(T value) {}


Foo foo;
foo.s = 10; // if s doesn't exist, do opSet!"s"(10)


If you only want a setter for one particular name

void opSet(string name : "s")(int val) {}



It'd solve the unicode thing too, though at the cost of a little 
more verboseness for some things.



Oh crap what if it needs to be virtual. Blargh. I'll throw it out 
anyway.
Jan 29 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/29/2013 06:16 PM, Adam D. Ruppe wrote:
 Not awful... but what about opDispatch setters?

 Perhaps we could do it this way:


 void opSet(string variable, T)(T value) {}
...
 Oh crap what if it needs to be virtual. Blargh. I'll throw it out anyway.
private int _s; protected void setS(int value){ this._s=value; } template opSet(string variable : "s")(int value){ alias opSet = setS; }
Jan 29 2013
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 29 January 2013 at 17:21:31 UTC, Timon Gehr wrote:
 template opSet(string variable : "s")(int value){ alias opSet = 
 setS; }
ah yes, outstanding. So that's workable.
Jan 29 2013
prev sibling next sibling parent FG <home fgda.pl> writes:
On 2013-01-29 18:10, Steven Schveighoffer wrote:
 If there is no y field, then then the compiler ALSO tries:
 x.setY(...);
                      [...]
 One problem I will note with this scheme, some Unicode symbols that may be
valid
 D symbol starters may NOT have an upper/lower case, making it impossible to use
 those as properties.  But I admit having an English bias so I don't see this as
 a large problem.  Besides, "set" is already English.
It's inconceivable why on earth would you call this a "compromise". :)
Jan 29 2013
prev sibling next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, January 29, 2013 12:10:04 Steven Schveighoffer wrote:
 Sound crazy? Ridiculous? Impossible? Insulting?
It seems like it could work, but without a way to explictly make something a getter property, it will be impossible to change a property function into a variable later without risking breaking code, because then people will still be able to call the property function with parens. Using parens on getter properties has to be illegal for that to work. And if we want it to work to be able to swap a variable for a property function (which is one of the purposes of properties in the first place), not only do we need to improve the property rewriting (which could be done with your scheme), but we'd need to be able to mark a variable in such a way that it couldn't be used for anything which wouldn't work with a property function (e.g. taking its address would have to be illegal), and for that, you'd need an explicit attribute such as property. So, if we want to be able to swap between variables and property functions during refactoring or design changes or whatnot (as properties are supposed to allow), we're going to need explicit properties of some kind. That could be done with getProp and setProp instead of property if we really wanted to, but we'd still need a way to mark variables, and for that, you'd probably need an actual attribute like property. If we go any route other than explicit properties, we're giving up on the possibility of being able to swap variables and property functions without breaking code. - Jonathan M Davis
Jan 29 2013
next sibling parent reply "Rob T" <alanb ucora.com> writes:
On Tuesday, 29 January 2013 at 23:09:55 UTC, Jonathan M Davis 
wrote:
[..]
 If we go any route other than explicit properties, we're giving 
 up on the
 possibility of being able to swap variables and property 
 functions without
 breaking code.

 - Jonathan M Davis
Given how D currently works, I don't see how we can realistically implement a function as a drop in replacement for a variable and expect code to continue working as if nothing had changed. One of the bigger problems is that the getter returns by value, not ref, so everything that expects a ref return will fail. I expect to make precise variable emulation through properties will require a lot of compiler magic, and there will be inevitable bugs and conflicts that follow. I really don't see that there's enough value with the property concept to justify the costs of precise variable emulation. You know a lot more about implementing compiler magic than I do, so I'll ask you if you think the effort is doable enough to justify having property functions that can act like a drop in replacement for existing variables? --rt
Jan 29 2013
next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, January 30, 2013 00:55:13 Rob T wrote:
 On Tuesday, 29 January 2013 at 23:09:55 UTC, Jonathan M Davis
 wrote:
 [..]
 
 If we go any route other than explicit properties, we're giving
 up on the
 possibility of being able to swap variables and property
 functions without
 breaking code.
 
 - Jonathan M Davis
Given how D currently works, I don't see how we can realistically implement a function as a drop in replacement for a variable and expect code to continue working as if nothing had changed. One of the bigger problems is that the getter returns by value, not ref, so everything that expects a ref return will fail. I expect to make precise variable emulation through properties will require a lot of compiler magic, and there will be inevitable bugs and conflicts that follow. I really don't see that there's enough value with the property concept to justify the costs of precise variable emulation. You know a lot more about implementing compiler magic than I do, so I'll ask you if you think the effort is doable enough to justify having property functions that can act like a drop in replacement for existing variables?
I believe that two main things are needed: 1. Make it possible to mark a variable such that you can't do anything with it that you couldn't do with a property function (e.g. taking its address needs to be illegal). 2. Add property rewrites to make it so that stuff like ++ and += work. You'll never get a property function to operate 100% like a variable, but you property functions swappable because it do stuff like let you take the address of a variable or a function. We basically need to do the same by restricting variables which are properties and improving the rewrites that the compile does for property functions. - Jonathan M Davis
Jan 29 2013
next sibling parent reply "q66" <quaker66 gmail.com> writes:
It deeply disturbs me that people even take the original post 
seriously.
Jan 29 2013
next sibling parent "q66" <quaker66 gmail.com> writes:
On Wednesday, 30 January 2013 at 00:26:11 UTC, q66 wrote:
 It deeply disturbs me that people even take the original post 
 seriously.
That said, obviously, propreties should be implemented in the library using opDot, with std.property implementing several property-handling policies and abstracted away in some kind of OO interface with inheritance to implement custom ones. That's gonna be awesome. Don't you think?
Jan 29 2013
prev sibling next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 30 January 2013 at 00:26:11 UTC, q66 wrote:
 It deeply disturbs me that people even take the original post 
 seriously.
Well, you may give some arguments instead of no, just no, to convince people.
Jan 29 2013
parent reply "q66" <quaker66 gmail.com> writes:
On Wednesday, 30 January 2013 at 03:02:38 UTC, deadalnix wrote:
 On Wednesday, 30 January 2013 at 00:26:11 UTC, q66 wrote:
 It deeply disturbs me that people even take the original post 
 seriously.
Well, you may give some arguments instead of no, just no, to convince people.
It just gives another meaning to foo.bar, and ENFORCING camelCase by the language while lowercasing shit is just horrible. Anyone with a slightest trace of language design sense realizes that.
Jan 30 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 30 Jan 2013 03:05:37 -0500, q66 <quaker66 gmail.com> wrote:

 On Wednesday, 30 January 2013 at 03:02:38 UTC, deadalnix wrote:
 On Wednesday, 30 January 2013 at 00:26:11 UTC, q66 wrote:
 It deeply disturbs me that people even take the original post  
 seriously.
Well, you may give some arguments instead of no, just no, to convince people.
It just gives another meaning to foo.bar, and ENFORCING camelCase by the language while lowercasing shit is just horrible. Anyone with a slightest trace of language design sense realizes that.
Apparently not the designers of objective-C. -Steve
Jan 30 2013
parent reply "q66" <quaker66 gmail.com> writes:
On Thursday, 31 January 2013 at 00:54:54 UTC, Steven 
Schveighoffer wrote:
 On Wed, 30 Jan 2013 03:05:37 -0500, q66 <quaker66 gmail.com> 
 wrote:

 On Wednesday, 30 January 2013 at 03:02:38 UTC, deadalnix wrote:
 On Wednesday, 30 January 2013 at 00:26:11 UTC, q66 wrote:
 It deeply disturbs me that people even take the original 
 post seriously.
Well, you may give some arguments instead of no, just no, to convince people.
It just gives another meaning to foo.bar, and ENFORCING camelCase by the language while lowercasing shit is just horrible. Anyone with a slightest trace of language design sense realizes that.
Apparently not the designers of objective-C. -Steve
Not contradictory, Objective-C is not a well designed language :)
Jan 31 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 Jan 2013 08:14:15 -0500, q66 <quaker66 gmail.com> wrote:

 On Thursday, 31 January 2013 at 00:54:54 UTC, Steven Schveighoffer wrote:
 On Wed, 30 Jan 2013 03:05:37 -0500, q66 <quaker66 gmail.com> wrote:

 On Wednesday, 30 January 2013 at 03:02:38 UTC, deadalnix wrote:
 On Wednesday, 30 January 2013 at 00:26:11 UTC, q66 wrote:
 It deeply disturbs me that people even take the original post  
 seriously.
Well, you may give some arguments instead of no, just no, to convince people.
It just gives another meaning to foo.bar, and ENFORCING camelCase by the language while lowercasing shit is just horrible. Anyone with a slightest trace of language design sense realizes that.
Apparently not the designers of objective-C. -Steve
Not contradictory, Objective-C is not a well designed language :)
Now we're just name calling ;) I tend to think that for the most successful company in the business to standardize on it is a pretty good testimony to it being well designed. I certainly have grown fond of it, there are some really nice features in it. But truly, xcode has played a large role in making the language seem good. As another option, what about changing my proposal so instead of setX, it's set_x, and then casing concerns are eliminated? I think C++.net does that. -Steve
Jan 31 2013
next sibling parent reply "jerro" <a a.com> writes:
 Now we're just name calling ;)  I tend to think that for the 
 most successful company in the business to standardize on it is 
 a pretty good testimony to it being well designed.
This is a really bad argument. The facts that language is being used by a large companies does not make it well designed. See PHP, for example - a *horrible* mess of a language, but it is being used at Facebook. (I don't have an opinion on objective C though, as I don't know the language)
Jan 31 2013
next sibling parent reply "Regan Heath" <regan netmail.co.nz> writes:
On Thu, 31 Jan 2013 14:39:56 -0000, jerro <a a.com> wrote:

 Now we're just name calling ;)  I tend to think that for the most  
 successful company in the business to standardize on it is a pretty  
 good testimony to it being well designed.
This is a really bad argument. The facts that language is being used by a large companies does not make it well designed. See PHP, for example - a *horrible* mess of a language, but it is being used at Facebook.
Small point. "using" != "standadized on". The latter implies some evaluation and decision making was done prior to the choice, the former.. well..
 (I don't have an opinion on objective C though, as I don't know the  
 language)
Neither. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Jan 31 2013
parent "SomeDude" <lovelydear mailmetrash.com> writes:
On Thursday, 31 January 2013 at 14:48:15 UTC, Regan Heath wrote:
 On Thu, 31 Jan 2013 14:39:56 -0000, jerro <a a.com> wrote:

 Now we're just name calling ;)  I tend to think that for the 
 most successful company in the business to standardize on it 
 is a pretty good testimony to it being well designed.
This is a really bad argument. The facts that language is being used by a large companies does not make it well designed. See PHP, for example - a *horrible* mess of a language, but it is being used at Facebook.
Small point. "using" != "standadized on". The latter implies some evaluation and decision making was done prior to the choice, the former.. well..
 (I don't have an opinion on objective C though, as I don't 
 know the language)
Neither. R
I bet the reason why Objective-C was chosen rather than C++ has more to do with licensing issues (LLVM wasn't rady at the time) and maybe GC than any other reason.
Feb 02 2013
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 Jan 2013 09:39:56 -0500, jerro <a a.com> wrote:

 Now we're just name calling ;)  I tend to think that for the most  
 successful company in the business to standardize on it is a pretty  
 good testimony to it being well designed.
This is a really bad argument. The facts that language is being used by a large companies does not make it well designed. See PHP, for example - a *horrible* mess of a language, but it is being used at Facebook.
From what I remember Andrei saying, they write their code in C++ and compile it to php, or something like that. Besides, facebook was a pet project by a single person that accidentally grew into an empire. Apple was around long before Steve Jobs brought Next Step OS (and it's usage of Objective-C) to Apple to become MacOS. You can't really argue that Mac is a horrible OS, it may not suit your tastes, but it performs well. Nick, please ignore this thread. -Steve
Jan 31 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-31 15:56, Steven Schveighoffer wrote:

 From what I remember Andrei saying, they write their code in C++ and
 compile it to php, or something like that.
I'm pretty sure it's the opposite. PHP code compiles to C++. "HipHop programmatically transforms your PHP source code into highly optimized C++ and then uses g++ to compile it." http://developers.facebook.com/blog/post/2010/02/02/hiphop-for-php--move-fast/ -- /Jacob Carlborg
Jan 31 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/31/13 11:36 AM, Jacob Carlborg wrote:
 On 2013-01-31 15:56, Steven Schveighoffer wrote:

 From what I remember Andrei saying, they write their code in C++ and
 compile it to php, or something like that.
I'm pretty sure it's the opposite. PHP code compiles to C++. "HipHop programmatically transforms your PHP source code into highly optimized C++ and then uses g++ to compile it." http://developers.facebook.com/blog/post/2010/02/02/hiphop-for-php--move-fast/
We use JITting right now: https://www.facebook.com/note.php?note_id=10150415177928920 I'm that team! Andrei
Jan 31 2013
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/31/13 12:08 PM, Andrei Alexandrescu wrote:
 I'm that team!
s/that/on that/
Jan 31 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-01-31 18:08, Andrei Alexandrescu wrote:

 We use JITting right now:
 https://www.facebook.com/note.php?note_id=10150415177928920
Aha, I didn't know that. -- /Jacob Carlborg
Jan 31 2013
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/31/2013 03:56 PM, Steven Schveighoffer wrote:
 ...See PHP, for
 example - a *horrible* mess of a language, but it is being used at
 Facebook.
From what I remember Andrei saying, they write their code in C++ and compile it to php, or something like that. ...
Other way round!
Jan 31 2013
prev sibling next sibling parent reply "q66" <quaker66 gmail.com> writes:
On Thursday, 31 January 2013 at 14:28:39 UTC, Steven 
Schveighoffer wrote:
 On Thu, 31 Jan 2013 08:14:15 -0500, q66 <quaker66 gmail.com> 
 wrote:

 On Thursday, 31 January 2013 at 00:54:54 UTC, Steven 
 Schveighoffer wrote:
 On Wed, 30 Jan 2013 03:05:37 -0500, q66 <quaker66 gmail.com> 
 wrote:

 On Wednesday, 30 January 2013 at 03:02:38 UTC, deadalnix 
 wrote:
 On Wednesday, 30 January 2013 at 00:26:11 UTC, q66 wrote:
 It deeply disturbs me that people even take the original 
 post seriously.
Well, you may give some arguments instead of no, just no, to convince people.
It just gives another meaning to foo.bar, and ENFORCING camelCase by the language while lowercasing shit is just horrible. Anyone with a slightest trace of language design sense realizes that.
Apparently not the designers of objective-C. -Steve
Not contradictory, Objective-C is not a well designed language :)
Now we're just name calling ;) I tend to think that for the most successful company in the business to standardize on it is a pretty good testimony to it being well designed. I certainly have grown fond of it, there are some really nice features in it. But truly, xcode has played a large role in making the language seem good. As another option, what about changing my proposal so instead of setX, it's set_x, and then casing concerns are eliminated? I think C++.net does that. -Steve
No, that is not a solution either. Any of these setBlah or set_blah or whatever are ugly hacks. There should be explicit property syntax. By explicit, I mean explicit - at least like
Jan 31 2013
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 Jan 2013 09:57:12 -0500, q66 <quaker66 gmail.com> wrote:

 On Thursday, 31 January 2013 at 14:28:39 UTC, Steven Schveighoffer wrote:
 As another option, what about changing my proposal so instead of setX,  
 it's set_x, and then casing concerns are eliminated?  I think C++.net  
 does that.

 -Steve
No, that is not a solution either. Any of these setBlah or set_blah or whatever are ugly hacks.
I don't agree, the benefit of being able to refer to the property as a function and as a property separately is nice. For instance, you can get a delegate for the property. The other benefit is that the setBlah or set_blah functions are self-descriptive as properties. You would be hard pressed to argue such a function doesn't set a value called blah.
 There should be explicit property syntax. By explicit, I mean explicit -  

I would be fine with that too, but with all due respect, the only person whose opinion matters is Walter. If he is possibly interested in any of these proposals instead of property, I think that's the one we should go for.

Why don't we start with a language you DO like that has properties? Or are you sour on all of them? -Steve
Jan 31 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-01-31 15:28, Steven Schveighoffer wrote:

 Now we're just name calling ;)  I tend to think that for the most
 successful company in the business to standardize on it is a pretty good
 testimony to it being well designed.  I certainly have grown fond of it,
 there are some really nice features in it.  But truly, xcode has played
 a large role in making the language seem good.
And that is thanks to Clang and LLVM. Xcode wouldn't be nearly as good on autocompletion, refactoring and static analysis to mention a few features. Also it has started to catch up in later years, thinking of Objective-C 2. More recently blocks, some kind of operator overloading and more object literals. -- /Jacob Carlborg
Jan 31 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 29 Jan 2013 19:26:09 -0500, q66 <quaker66 gmail.com> wrote:

 It deeply disturbs me that people even take the original post seriously.
Sorry it offends you, but maybe you could have a constructive comment instead of a condescending tone? This is not a frivolous proposal, and it's not my first, but I'm trying to fit something with the language designers who have expressed a significant distaste with property to the point where they just want to go back to the crap we had before. If we can get ANY kind of property syntax, I think it's better than that. -Steve
Jan 30 2013
prev sibling next sibling parent reply "Rob T" <alanb ucora.com> writes:
On Wednesday, 30 January 2013 at 00:25:41 UTC, Jonathan M Davis 
wrote:
 I believe that two main things are needed:

 1. Make it possible to mark a variable such that you can't do 
 anything with it
 that you couldn't do with a property function (e.g. taking its 
 address needs
 to be illegal).

 2. Add property rewrites to make it so that stuff like ++ and 
 += work.

 You'll never get a property function to operate 100% like a 
 variable, but you

 making variables and
 property functions swappable because it do stuff like let you 
 take the address
 of a variable or a function. We basically need to do the same 
 by restricting
 variables which are properties and improving the rewrites that 
 the compile
 does for property functions.

 - Jonathan M Davis
I agree partial emulation can work, and I see you've pointed out that the usage of a property will have to be restricted so that it can work, but this means you have to mark your naked variables as property ahead of time, otherwise you'll discover that you cannot replace a naked variable with a property without doing plenty of re-work. Given that we won't be able to drop in a property without rework unless preplanned ahead of time, I'm not so sure we'll be gaining anything new here with specially marked properties, and even if we could drop them in, I'm still not sure it's a big gain. I can see some value I suppose if you can mark a naked variable as property because you know it will likely be wrapped into a function call later but don't want to implement the wrappers immediately, but I don't know if that's something a lot of people really need or care that much about. I find the discussion we're having in another thread on the possibility of using a struct-like implementation for gaining property-like behaviors much more compelling a change for D because it extends D with interesting ways to implement variables and functions that can be used in more generalized situations AND it solves the property implementation issues too (in similar "restricted" ways as you've suggested can be done). See last few posts ... http://forum.dlang.org/thread/kdukid$stg$1 digitalmars.com If we can not only implement property as hoped for, but also get more expressive language features introduced along with it, then it may be something worth doing. --rt
Jan 29 2013
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 30, 2013 at 01:58:16AM +0100, Rob T wrote:
[...]
 I agree partial emulation can work, and I see you've pointed out
 that the usage of a property will have to be restricted so that it
 can work, but this means you have to mark your naked variables as
  property ahead of time, otherwise you'll discover that you cannot
 replace a naked variable with a property without doing plenty of
 re-work.
[...] Why do you have to mark naked variables as property? Isn't that redundant? As for using struct to implement property, I like the idea, but it does raise tricky issues about how struct methods reference the parent lexical scope. I don't think it's as simple as just rewriting 'this' to point to the outer scope instead, because it breaks language expectations that 'this' should refer to the immediately-containing struct/class. There's bound to be corner cases that will break because of this. Consider, for example, what happens if the inner struct's methods need to call opAssign of the parent struct for whatever reason. There's also the consideration of what happens if you take the address of the 'pseudo' variable: the inner struct would then be effectively dissociated from the parent struct, and you'll need that hidden context pointer (along with its gotchas) in order to have things still work as before. T -- The volume of a pizza of thickness a and radius z can be described by the following formula: pi zz a. -- Wouter Verhelst
Jan 29 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Wednesday, 30 January 2013 at 01:09:12 UTC, H. S. Teoh wrote:
 As for using struct to implement  property, I like the idea, 
 but it does
 raise tricky issues about how struct methods reference the 
 parent
 lexical scope. I don't think it's as simple as just rewriting 
 'this' to
 point to the outer scope instead, because it breaks language
 expectations that 'this' should refer to the 
 immediately-containing
 struct/class. There's bound to be corner cases that will break 
 because
 of this. Consider, for example, what happens if the inner 
 struct's
 methods need to call opAssign of the parent struct for whatever 
 reason.
outer.this outer.opAssign
 There's also the consideration of what happens if you take the 
 address
 of the 'pseudo' variable: the inner struct would then be 
 effectively
 dissociated from the parent struct, and you'll need that hidden 
 context
 pointer (along with its gotchas) in order to have things still 
 work as
 before.
Compiler detects a struct which holds no data of its own and disallows taking its address.
Jan 29 2013
parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Wednesday, 30 January 2013 at 01:20:39 UTC, Zach the Mystic 
wrote:
 On Wednesday, 30 January 2013 at 01:09:12 UTC, H. S. Teoh wrote:
 There's also the consideration of what happens if you take the 
 address
 of the 'pseudo' variable: the inner struct would then be 
 effectively
 dissociated from the parent struct, and you'll need that 
 hidden context
 pointer (along with its gotchas) in order to have things still 
 work as
 before.
Compiler detects a struct which holds no data of its own and disallows taking its address.
Actually, you're right. I see no overloading of the address operator in the documentation. I doubt it's an insurmountable problem, though. opAddress?
Jan 29 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, January 29, 2013 17:06:32 H. S. Teoh wrote:
 Why do you have to mark naked variables as  property? Isn't that
 redundant?
In order to restrict what you can do with it to the subset of operations that you can do with a property function. In particular, taking its address would need to be illegal, as that won't work with a property function (or if it did, it would return a different type). It would be impossible to replace a normal variable with a property function without risking breaking code, because there are operations that you can normally do on a variable that couldn't possibly be implemented with a function (such as taking its address). But if you mark it to restrict what it can do, then you could swap it out with a function later without the risk of breaking code (which is one of the main reasons for having properties in the first place). property doesn't currently do this, but it could, and if we don't have something like that, then it'll never be safe to swap variables and property functions. - Jonathan M Davis
Jan 29 2013
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 30, 2013 at 02:23:26AM +0100, Jonathan M Davis wrote:
 On Tuesday, January 29, 2013 17:06:32 H. S. Teoh wrote:
 Why do you have to mark naked variables as  property? Isn't that
 redundant?
In order to restrict what you can do with it to the subset of operations that you can do with a property function. In particular, taking its address would need to be illegal, as that won't work with a property function (or if it did, it would return a different type).
I see.
 It would be impossible to replace a normal variable with a property
 function without risking breaking code, because there are operations
 that you can normally do on a variable that couldn't possibly be
 implemented with a function (such as taking its address). But if you
 mark it to restrict what it can do, then you could swap it out with a
 function later without the risk of breaking code (which is one of the
 main reasons for having properties in the first place).  property
 doesn't currently do this, but it could, and if we don't have
 something like that, then it'll never be safe to swap variables and
 property functions.
[...] If this is the case, then I would have to say that property is fundamentally broken. The whole point of property is to make functions behave like variables, but if this "variable emulation" isn't even complete, then it defeats the purpose of having it in the first place. T -- Just because you survived after you did it, doesn't mean it wasn't stupid!
Jan 29 2013
parent reply "Adam Wilson" <flyboynw gmail.com> writes:
On Tue, 29 Jan 2013 17:32:20 -0800, H. S. Teoh <hsteoh quickfur.ath.cx>  
wrote:

 On Wed, Jan 30, 2013 at 02:23:26AM +0100, Jonathan M Davis wrote:
 On Tuesday, January 29, 2013 17:06:32 H. S. Teoh wrote:
 Why do you have to mark naked variables as  property? Isn't that
 redundant?
In order to restrict what you can do with it to the subset of operations that you can do with a property function. In particular, taking its address would need to be illegal, as that won't work with a property function (or if it did, it would return a different type).
I see.
 It would be impossible to replace a normal variable with a property
 function without risking breaking code, because there are operations
 that you can normally do on a variable that couldn't possibly be
 implemented with a function (such as taking its address). But if you
 mark it to restrict what it can do, then you could swap it out with a
 function later without the risk of breaking code (which is one of the
 main reasons for having properties in the first place).  property
 doesn't currently do this, but it could, and if we don't have
 something like that, then it'll never be safe to swap variables and
 property functions.
[...] If this is the case, then I would have to say that property is fundamentally broken. The whole point of property is to make functions behave like variables, but if this "variable emulation" isn't even complete, then it defeats the purpose of having it in the first place. T
Indeed, but a better idea would be to fix it, throwing it out seems a bit extreme. -- Adam Wilson IRC: LightBender Project Coordinator The Horizon Project http://www.thehorizonproject.org/
Jan 29 2013
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Jan 29, 2013 at 06:05:15PM -0800, Adam Wilson wrote:
 On Tue, 29 Jan 2013 17:32:20 -0800, H. S. Teoh
 <hsteoh quickfur.ath.cx> wrote:
 
On Wed, Jan 30, 2013 at 02:23:26AM +0100, Jonathan M Davis wrote:
On Tuesday, January 29, 2013 17:06:32 H. S. Teoh wrote:
 Why do you have to mark naked variables as  property? Isn't that
 redundant?
In order to restrict what you can do with it to the subset of operations that you can do with a property function. In particular, taking its address would need to be illegal, as that won't work with a property function (or if it did, it would return a different type).
I see.
It would be impossible to replace a normal variable with a property
function without risking breaking code, because there are operations
that you can normally do on a variable that couldn't possibly be
implemented with a function (such as taking its address). But if you
mark it to restrict what it can do, then you could swap it out with
a function later without the risk of breaking code (which is one of
the main reasons for having properties in the first place).
 property doesn't currently do this, but it could, and if we don't
have something like that, then it'll never be safe to swap variables
and property functions.
[...] If this is the case, then I would have to say that property is fundamentally broken. The whole point of property is to make functions behave like variables, but if this "variable emulation" isn't even complete, then it defeats the purpose of having it in the first place.
[...]
 
 Indeed, but a better idea would be to fix it, throwing it out seems
 a bit extreme.
[...] I'm not for throwing it out, actually. :) Just pointing out some problematic aspects of it. One way to solve the '&' problem is to have the compiler lower that into a delegate that gives access to the setter/getter for that field. Then property *would* indeed be a drop-in replacement for member variables. T -- In theory, there is no difference between theory and practice.
Jan 29 2013
parent reply Chad Joan <chadjoan gmail.com> writes:
On 01/29/2013 09:13 PM, H. S. Teoh wrote:
 I'm not for throwing it out, actually. :) Just pointing out some
 problematic aspects of it.

 One way to solve the '&' problem is to have the compiler lower that into
 a delegate that gives access to the setter/getter for that field. Then
  property *would* indeed be a drop-in replacement for member variables.


 T
I hate to be a bringer of bad news, but I don't think getter/setter proxies will ever be an invisible replacement for pointers. Getter/setter proxies cannot be incremented/decremented, and you can't use them in conjunction with the container's pointer to get the offset to the field. Pointers have very specific semantics. I think it's much easier to just restrict variables from being addressable in cases where they will eventually become properties. I would argue though, that pointers are a getter/setter proxy. The relationship is just not commutative. What this means is that we can treat getter/setter proxies as an algorithmic structure, right alongside things like ranges, iterators, containers, etc. They are the most general form of their class: anything that supports assignment and retrieval (ex: pointers) is a kind of getter/setter proxy. I think that we would eventually want a (library-defined) getter/setter proxy type. It will be the only way to defer getting/setting of an property into called code, which is what pointers are currently used for in many cases. Such a type should be possible to construct from plain variables, pointers, (hash table + key) pairs, certain functions (ex: foo(int getOrSet, void **value)), and anything else you could concoct that satisfies the "is a" relationship. </dream>
Jan 29 2013
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Jan 29, 2013 at 09:44:36PM -0500, Chad Joan wrote:
 On 01/29/2013 09:13 PM, H. S. Teoh wrote:
I'm not for throwing it out, actually. :) Just pointing out some
problematic aspects of it.

One way to solve the '&' problem is to have the compiler lower that
into a delegate that gives access to the setter/getter for that
field. Then  property *would* indeed be a drop-in replacement for
member variables.
[...]
 
 I hate to be a bringer of bad news, but I don't think getter/setter
 proxies will ever be an invisible replacement for pointers.
 
 Getter/setter proxies cannot be incremented/decremented,
This is easy to fix in the compiler.
 and you can't use them in conjunction with the container's pointer to
 get the offset to the field.  Pointers have very specific semantics.
If you write code that is specific to a particular implementation of a field, then it's no surprise that you can't use drop-in abstract replacements. I don't see that as a major issue.
 I think it's much easier to just restrict variables from being
 addressable in cases where they will eventually become properties.
You're right, there is some merit to this idea.
 I would argue though, that pointers are a getter/setter proxy.  The
 relationship is just not commutative.  What this means is that we can
 treat getter/setter proxies as an algorithmic structure, right
 alongside things like ranges, iterators, containers, etc.  They are
 the most general form of their class: anything that supports
 assignment and retrieval (ex: pointers) is a kind of getter/setter
 proxy.
I like this line of reasoning. Pointer arithmetic is unsafe anyway, and in general don't interact well with abstraction, so I don't see lack of pointer support as a major problem. As long as you treat pointers as opaque handles to some value (abstract or otherwise), you can replace them with a getter/setter proxy.
 I think that we would eventually want a (library-defined)
 getter/setter proxy type.  It will be the only way to defer
 getting/setting of an  property into called code, which is what
 pointers are currently used for in many cases.  Such a type should
 be possible to construct from plain variables, pointers, (hash table
 + key) pairs, certain functions (ex: foo(int getOrSet, void
 **value)), and anything else you could concoct that satisfies the
 "is a" relationship.
[...] I think if we can address the various issues of Rob T's struct-as-variable idea, it might be possible to turn it into a template in Phobos (maybe in std.typecons or something). T -- "I speak better English than this villain Bush" -- Mohammed Saeed al-Sahaf, Iraqi Minister of Information
Jan 29 2013
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, January 29, 2013 18:13:41 H. S. Teoh wrote:
 I'm not for throwing it out, actually. :) Just pointing out some
 problematic aspects of it.
 
 One way to solve the '&' problem is to have the compiler lower that into
 a delegate that gives access to the setter/getter for that field. Then
  property *would* indeed be a drop-in replacement for member variables.
But the type would be different. You wouldn't be able to do stuff like int* p = &s.prop; And what happens with a delegate is fundamentally different when you take the address of a variable. The property function may not even be returning a value associated with a variable. It could be calculated. I believe that you're trying to take the abstraction farther than is possible. All abstractions break at some point, and taking the address of a property is one place that property functions break as an abstraction for variables. - Jonathan M Davis
Jan 29 2013
prev sibling next sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 00:25:41 UTC, Jonathan M Davis 
wrote:
 On Wednesday, January 30, 2013 00:55:13 Rob T wrote:
 [..]
 You know a lot more about implementing compiler magic than I 
 do, so I'll ask you if you think the effort is doable enough
 to justify having property functions that can act like a
 drop in replacement for existing variables?
I believe that two main things are needed: [..]
I always thought that having public member variables is a bad style of programming because of the lack of encapsulation. So, if there's a language feature that enables you to write public member variables, and later on, replace them with property functions, wouldn't that mean that the language is encouraging this particular kind of bad style of programming?
Jan 29 2013
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 30, 2013 at 02:40:45AM +0100, TommiT wrote:
 On Wednesday, 30 January 2013 at 00:25:41 UTC, Jonathan M Davis
 wrote:
On Wednesday, January 30, 2013 00:55:13 Rob T wrote:
[..]
You know a lot more about implementing compiler magic than I do,
so I'll ask you if you think the effort is doable enough
to justify having property functions that can act like a
drop in replacement for existing variables?
I believe that two main things are needed: [..]
I always thought that having public member variables is a bad style of programming because of the lack of encapsulation. So, if there's a language feature that enables you to write public member variables, and later on, replace them with property functions, wouldn't that mean that the language is encouraging this particular kind of bad style of programming?
Property functions are precisely what gives you encapsulation. Think about it. They let you "pretend" that there's a public member variable, but actually you don't know (and don't have to know) what their real implementation is. This is, by definition, encapsulation. So this is actually an argument *for*, rather than against, property functions. There's nothing wrong with public member variables per se, it's the fact that it makes external code rely on their specific implementation. Property functions alleviate this problem by making it possible to change the underlying implementation without needing to touch user code. T -- The fact that anyone still uses AOL shows that even the presence of options doesn't stop some people from picking the pessimal one. - Mike Ellis
Jan 29 2013
prev sibling next sibling parent "Adam Wilson" <flyboynw gmail.com> writes:
On Tue, 29 Jan 2013 17:40:45 -0800, TommiT <tommitissari hotmail.com>  
wrote:

 On Wednesday, 30 January 2013 at 00:25:41 UTC, Jonathan M Davis wrote:
 On Wednesday, January 30, 2013 00:55:13 Rob T wrote:
 [..]
 You know a lot more about implementing compiler magic than I do, so  
 I'll ask you if you think the effort is doable enough
 to justify having property functions that can act like a
 drop in replacement for existing variables?
I believe that two main things are needed: [..]
I always thought that having public member variables is a bad style of programming because of the lack of encapsulation. So, if there's a language feature that enables you to write public member variables, and later on, replace them with property functions, wouldn't that mean that the language is encouraging this particular kind of bad style of programming?
Not really, public fields ARE bad, but properties allow you to sanitize the data and throw exceptions if the data doesn't fit the spec. A field does not. In this way encapsulation is maintained. -- Adam Wilson IRC: LightBender Project Coordinator The Horizon Project http://www.thehorizonproject.org/
Jan 29 2013
prev sibling next sibling parent reply "Rob T" <alanb ucora.com> writes:
On Wednesday, 30 January 2013 at 01:40:52 UTC, TommiT wrote:
 On Wednesday, 30 January 2013 at 00:25:41 UTC, Jonathan M Davis 
 wrote:
 On Wednesday, January 30, 2013 00:55:13 Rob T wrote:
 [..]
 You know a lot more about implementing compiler magic than I 
 do, so I'll ask you if you think the effort is doable enough
 to justify having property functions that can act like a
 drop in replacement for existing variables?
I believe that two main things are needed: [..]
I always thought that having public member variables is a bad style of programming because of the lack of encapsulation. So, if there's a language feature that enables you to write public member variables, and later on, replace them with property functions, wouldn't that mean that the language is encouraging this particular kind of bad style of programming?
Well, the main reason why this was bad convention, is because the "." operator conceptually returns by reference, so you are operating directly on the encapsulated variable with no possibility of oversight through the encapsulation. The property method will restrict variable usage to non-ref and non-pointer uses only, which is a form of encapsulation through the "." operator, and it can later be replaced with a function call if required. Even with property restrictions, I still don't think it will work as expected. For example, if the variable is a struct, then you have to disallow operations on the struct from outside. Example: struct Y { int a; } struct X{ property Y y; } X x; x.y.a = 4; // <- this has to be illegal! Reason? struct X{ Y _y; property Y y{ return _y; } } // this won't change _y as it did before. x.y.a = 4; I figure if we're going to do something about properties, we may as well do something much more compelling and re-invent the property rather than attempt to partially emulate variables just because someone was in a hurry and left their encapsulated variables public and used them directly outside the struct or class. --rt
Jan 29 2013
next sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 02:15:09 UTC, Rob T wrote:
 Even with  property restrictions, I still don't think it will 
 work as expected. For example, if the variable is a struct, 
 then you have to disallow operations on the struct from outside.

 Example:

 struct Y { int a; }

 struct X{  property Y y; }

 X x;

 x.y.a = 4; // <- this has to be illegal!

 Reason?

 struct X{

   Y _y;

    property Y y{ return _y; }

 }

 // this won't change _y as it did before.
 x.y.a = 4;
Somehow I had missed this post. So, we can bury the idea of restricting the access to a public member variable by making it illegal to take the address of it. And as long as it is possible to take the address of a public member variable, it is possible for the end-user to by-pass all encapsulation that you might later on add over that public member variable. For this reason, my logic says, it is impossible to invent such an implementation of property concept that would make it possible to first put in a public member variable and later on encapsulate it *without* changing the interface.
Jan 30 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 12:04:31 UTC, TommiT wrote:
 [..] it is impossible to invent such an implementation of 
 property concept that would make it possible to first put in a 
 public member variable and later on encapsulate it *without* 
 changing the interface.
And frankly, I think it's a good thing. Because this way we can add to D's documentation: "NOTE: properties are *not* inter-changeable with public member variables", and thus, actively discourage people from writing un-encapsulated interfaces which expose public member variables.
Jan 30 2013
parent "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 12:11:30 UTC, TommiT wrote:
 Because this way we can add to D's documentation: "NOTE: 
 properties are *not* inter-changeable with public member 
 variables", and thus, actively discourage people from writing 
 un-encapsulated interfaces which expose public member variables.
The moral of the story: We should all stop thinking of properties as data, and start thinking properties as functions that you call with a data-like interface. The value of properties is in clearer semantics: Separate accessor and mutator are tied together very loosely, that is, only by the similarity in their naming: getSomething, setSomething. Whereas property getter and setter have the same name, and thus are semantically un-ambiguously tied together.
Jan 30 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-01-30 03:15, Rob T wrote:

 Even with  property restrictions, I still don't think it will work as
 expected. For example, if the variable is a struct, then you have to
 disallow operations on the struct from outside.

 Example:

 struct Y { int a; }

 struct X{  property Y y; }

 X x;

 x.y.a = 4; // <- this has to be illegal!

 Reason?

 struct X{

    Y _y;

     property Y y{ return _y; }

 }

 // this won't change _y as it did before.
 x.y.a = 4;
That would require some property rewrite by the compiler. -- /Jacob Carlborg
Jan 30 2013
prev sibling next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, January 30, 2013 02:40:45 TommiT wrote:
 On Wednesday, 30 January 2013 at 00:25:41 UTC, Jonathan M Davis
 
 wrote:
 On Wednesday, January 30, 2013 00:55:13 Rob T wrote:
 [..]
 You know a lot more about implementing compiler magic than I
 do, so I'll ask you if you think the effort is doable enough
 to justify having property functions that can act like a
 drop in replacement for existing variables?
I believe that two main things are needed: [..]
I always thought that having public member variables is a bad style of programming because of the lack of encapsulation. So, if there's a language feature that enables you to write public member variables, and later on, replace them with property functions, wouldn't that mean that the language is encouraging this particular kind of bad style of programming?
Aside from the ability to take the variable's address, what really is the difference between struct S { int prop; } and struct S { property int prop() safe const pure nothrow { return _prop; } property int prop(int value) safe const pure nothrow { return _prop = value; } private int _prop; } At the moment, stuff like ++ and += wouldn't work with property, but that could be fixed. But as far as access goes, there's no real difference. You have full read-write access in both cases. That being the case, why bother with the do, but we can't with our current implementation of properties), is start with struct S { int prop; } The code's shorter and simpler. You don't need any checks on the data, and you don't need to do any operations when the property gets set. So, a variable is just fine. Then when you actually need to do something extra when the property is set, you change it to a property function. struct S { property int prop() safe const pure nothrow { return _prop; } property int prop(int value) safe const pure nothrow { validate(value); _prop = value; doSomethingElseWhichCaresAboutPropChanging(); return _prop; } private int _prop; } actually have a good property implementation, and you can't take the address so that the compiler does proper rewriting of code like s.prop++ and make it so that we can mark variables as properties (so that you can't take their address or pass them by ref or do anything else that you can't do with a property function). e.g. struct S { property int prop; } But a public variable isn't a problem if the language allows you to swap it out with a property function without breaking code. - Jonathan M Davis
Jan 29 2013
parent "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 02:22:14 UTC, Jonathan M Davis 
wrote:
 On Wednesday, January 30, 2013 02:40:45 TommiT wrote:
 I always thought that having public member variables is a bad
 style of programming because of the lack of encapsulation. So, 
 if
 there's a language feature that enables you to write public
 member variables, and later on, replace them with property
 functions, wouldn't that mean that the language is encouraging
 this particular kind of bad style of programming?
Aside from the ability to take the variable's address, what really is the difference between struct S { int prop; } and struct S { property int prop() safe const pure nothrow { return _prop; } property int prop(int value) safe const pure nothrow { return _prop = value; } private int _prop; } At the moment, stuff like ++ and += wouldn't work with property, but that could be fixed. But as far as access goes, there's no real difference. You have full read-write access in both cases. That being the case, why bother with the property functions? What you're supposed to be able to do (and do, but we can't with our current implementation of properties), is start with struct S { int prop; } The code's shorter and simpler. You don't need any checks on the data, and you don't need to do any operations when the property gets set. So, a variable is just fine. Then when you actually need to do something extra when the property is set, you change it to a property function. struct S { property int prop() safe const pure nothrow { return _prop; } property int prop(int value) safe const pure nothrow { validate(value); _prop = value; doSomethingElseWhichCaresAboutPropChanging(); return _prop; } private int _prop; } because they actually have a good property implementation, and you can't take the address need to fix it so that the compiler does proper rewriting of code like s.prop++ and make it so that we can mark variables as properties (so that you can't take their address or pass them by ref or do anything else that you can't do with a property function). e.g. struct S { property int prop; } But a public variable isn't a problem if the language allows you to swap it out with a property function without breaking code. - Jonathan M Davis
Okay, I can see how that could work. But I still stand un-corrected by my previous post. Because 'public' means to me: "end-user has direct all-access". Therefore: "public property int prop;" isn't really public given my definition. It's somewhere in the space between public and private.
Jan 29 2013
prev sibling next sibling parent Chad Joan <chadjoan gmail.com> writes:
On 01/29/2013 08:40 PM, TommiT wrote:
 On Wednesday, 30 January 2013 at 00:25:41 UTC, Jonathan M Davis wrote:
 On Wednesday, January 30, 2013 00:55:13 Rob T wrote:
 [..]
 You know a lot more about implementing compiler magic than I do, so
 I'll ask you if you think the effort is doable enough
 to justify having property functions that can act like a
 drop in replacement for existing variables?
I believe that two main things are needed: [..]
I always thought that having public member variables is a bad style of programming because of the lack of encapsulation. So, if there's a language feature that enables you to write public member variables, and later on, replace them with property functions, wouldn't that mean that the language is encouraging this particular kind of bad style of programming?
No, it means that style of programming is no longer bad. It is already possible to write public member variables. It's pretty much as dangerous to do so as the wisdom says. We avoid using public member variables specifically because, in most languages, this makes it impossible to add hooks into the assignment/retrieval of the variable later without breaking the API. Now, in D, we might one day be able to add those assignment/retrieval hooks onto a variable without breaking API. That makes it no longer necessary to avoid public variables, though you will probably have to mark them property to get the safety.
Jan 29 2013
prev sibling next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 30 January 2013 at 01:40:52 UTC, TommiT wrote:
 On Wednesday, 30 January 2013 at 00:25:41 UTC, Jonathan M Davis 
 wrote:
 On Wednesday, January 30, 2013 00:55:13 Rob T wrote:
 [..]
 You know a lot more about implementing compiler magic than I 
 do, so I'll ask you if you think the effort is doable enough
 to justify having property functions that can act like a
 drop in replacement for existing variables?
I believe that two main things are needed: [..]
I always thought that having public member variables is a bad style of programming because of the lack of encapsulation. So, if there's a language feature that enables you to write public member variables, and later on, replace them with property functions, wouldn't that mean that the language is encouraging this particular kind of bad style of programming?
Belief is rarely a good thing. public variable are an encapsulation problem if you don't have properties. Then, a bunch of boilerplate is written because in 1% of the cases, some logic will be hooked on the variable access. Allowing properties allow the same level of encapsulation, without requiring boilerplate up-front.
Jan 29 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 03:24:47 UTC, deadalnix wrote:
 public variable are an encapsulation problem if you don't have 
 properties.
I don't agree. I think public variables are an encapsulation problem, period. And again, by 'public' I mean: "really, truly public, not kidding".
Jan 29 2013
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 30 January 2013 at 03:52:22 UTC, TommiT wrote:
 On Wednesday, 30 January 2013 at 03:24:47 UTC, deadalnix wrote:
 public variable are an encapsulation problem if you don't have 
 properties.
I don't agree. I think public variables are an encapsulation problem, period. And again, by 'public' I mean: "really, truly public, not kidding".
Sounds like religious reasoning.
Jan 29 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 04:06:02 UTC, deadalnix wrote:
 I don't agree. I think public variables are an encapsulation 
 problem, period. And again, by 'public' I mean: "really, truly 
 public, not kidding".
Sounds like religious reasoning.
I don't understand you. According to wikipedia, encapsulation is: "A language mechanism for restricting access to some of the object's components." Member variable is a component of an object. Public access means un-restricted access. Therefore, public member variable is not encapsulated. Therefore, public member variable is a problem in encapsulation, by definition. I dare you to find a single religious cell in me.
Jan 29 2013
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
There's times when a member variable manages its own invariant 
and any of its values is valid for the containing class, in which 
case the container doesn't need to further restrict access to it; 
a public struct doesn't need to be wrapped in a get function or 
anything.
Jan 29 2013
next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 04:39:13 UTC, Adam D. Ruppe 
wrote:
 There's times when a member variable manages its own invariant 
 and any of its values is valid for the containing class, in 
 which case the container doesn't need to further restrict 
 access to it; a public struct doesn't need to be wrapped in a 
 get function or anything.
Okay, so we have this: struct Foo { Bar bar; } Assume that all data in Bar is stack allocated and we can't change it. What if I later on realize, that I should have really allocated bar on the heap, because its size is too great and it makes Foo inconvenient in every-day use because of stack overflow problems. Now that everybody has already been using foo.bar directly, I feel really bad for not encapsulating it. Note: that's not a problem if we have a way of saying that bar should behave like a property function, something like: struct Foo { property Bar bar; } ...and if we can create that property function later on.
Jan 29 2013
prev sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 04:39:13 UTC, Adam D. Ruppe 
wrote:
 There's times when a member variable manages its own invariant 
 and any of its values is valid for the containing class, in 
 which case the container doesn't need to further restrict 
 access to it.
But yes, there are times, when a public member variable, which encapsulates its own data, is truly designed as a part of the interface, in which case it doesn't need to be encapsulated any further.
Jan 29 2013
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/29/13 8:40 PM, TommiT wrote:
 On Wednesday, 30 January 2013 at 00:25:41 UTC, Jonathan M Davis wrote:
 On Wednesday, January 30, 2013 00:55:13 Rob T wrote:
 [..]
 You know a lot more about implementing compiler magic than I do, so
 I'll ask you if you think the effort is doable enough
 to justify having property functions that can act like a
 drop in replacement for existing variables?
I believe that two main things are needed: [..]
I always thought that having public member variables is a bad style of programming because of the lack of encapsulation. So, if there's a language feature that enables you to write public member variables, and later on, replace them with property functions, wouldn't that mean that the language is encouraging this particular kind of bad style of programming?
The thing here is that properties offer control over changing the variable, which makes all the difference. Andrei
Jan 29 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-30 02:40, TommiT wrote:

 I always thought that having public member variables is a bad style of
 programming because of the lack of encapsulation. So, if there's a
 language feature that enables you to write public member variables, and
 later on, replace them with property functions, wouldn't that mean that
 the language is encouraging this particular kind of bad style of
 programming?
I really don't see much point in properties/methods that just forwards to an instance variable. -- /Jacob Carlborg
Jan 30 2013
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/30/13 10:10 AM, Jacob Carlborg wrote:
 On 2013-01-30 02:40, TommiT wrote:

 I always thought that having public member variables is a bad style of
 programming because of the lack of encapsulation. So, if there's a
 language feature that enables you to write public member variables, and
 later on, replace them with property functions, wouldn't that mean that
 the language is encouraging this particular kind of bad style of
 programming?
I really don't see much point in properties/methods that just forwards to an instance variable.
Insurance. Andrei
Jan 30 2013
prev sibling next sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 15:10:37 UTC, Jacob Carlborg 
wrote:
 I really don't see much point in properties/methods that just 
 forwards to an instance variable.
I assume you mean something like this: struct S { private T _t; ref T get() { return _t; } void set(T t) { ... } } The benefit of the above type of coding versus having a public T variable, is that you can change the implementation of S without changing S's interface. Perhaps I would like to change it to this (or whatever): private static T[5] tees; struct S { private byte _idx; ref T get() { return tees[_idx]; } void set(T t) { ... } }
Jan 30 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-30 17:26, TommiT wrote:

 I assume you mean something like this:

 struct S
 {
      private T _t;

      ref T get() { return _t; }

      void set(T t) { ... }
 }

 The benefit of the above type of coding versus having a public T
 variable, is that you can change the implementation of S without
 changing S's interface. Perhaps I would like to change it to this (or
 whatever):

 private static T[5] tees;

 struct S
 {
      private byte _idx;

      ref T get() { return tees[_idx]; }

      void set(T t) { ... }
 }
Sure, but I think that's what properties are for. We currently don't have that in D but I think it would be great if fields could be exchanged with methods without breaking the API. -- /Jacob Carlborg
Jan 30 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 20:28:32 UTC, Jacob Carlborg 
wrote:
 Sure, but I think that's what properties are for. We currently 
 don't have that in D but I think it would be great if fields 
 could be exchanged with methods without breaking the API.
The problem is that genie is out of the bottle once you have committed yourself to an interface where there is a public member variable. And you can't put the genie back in the bottle any more. This means that your interface can't add any encapsulation over this public member variable afterwards without changing the interface.
Jan 30 2013
next sibling parent "Michael" <pr m1xa.com> writes:
As interface api good practice is usage virtual public functions 
of classes.
So, (virtual) properties add an additional usefulness.
Jan 30 2013
prev sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 21:07:56 UTC, TommiT wrote:
 The problem is that genie is out of the bottle once you have 
 committed yourself to an interface where there is a public 
 member variable. And you can't put the genie back in the bottle 
 any more. This means that your interface can't add any 
 encapsulation over this public member variable afterwards 
 without changing the interface.
A bit more code, a bit less metaphors: struct S { T data; } // end-user code: S s; *&s.data = 42; End-user thus by-passes any encapsulation that could be possible added over S.data field later on, like the following: struct S { private T _data; property ref T data() { return _data; } property ref T data(int v) { assert(v != 42); _data = v; return _data; } }
Jan 30 2013
prev sibling parent reply 1100110 <0b1100110 gmail.com> writes:
On 01/30/2013 09:10 AM, Jacob Carlborg wrote:
 On 2013-01-30 02:40, TommiT wrote:

 I always thought that having public member variables is a bad style of
 programming because of the lack of encapsulation. So, if there's a
 language feature that enables you to write public member variables, and
 later on, replace them with property functions, wouldn't that mean that
 the language is encouraging this particular kind of bad style of
 programming?
I really don't see much point in properties/methods that just forwards to an instance variable.
Me either. I mean yes, for anything that is part of a public api you should probably double check everything. But insisting on getters and setters regardless of the requirements of what you are getting and setting? Sounds like an excuse to not think, to me.
Jan 30 2013
next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 21:26:34 UTC, 1100110 wrote:
 Me either.

 I mean yes, for anything that is part of a public api you 
 should probably double check everything.  But insisting on 
 getters and setters regardless of the requirements of what you 
 are getting and setting?

 Sounds like an excuse to not think, to me.
Putting in public variables sounds like not thinking, to me. Interface should expose the minimum amount of access possible, whereas public variables expose the maximum amount of access.
Jan 30 2013
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, January 30, 2013 15:26:32 1100110 wrote:
 On 01/30/2013 09:10 AM, Jacob Carlborg wrote:
 On 2013-01-30 02:40, TommiT wrote:
 I always thought that having public member variables is a bad style of
 programming because of the lack of encapsulation. So, if there's a
 language feature that enables you to write public member variables, and
 later on, replace them with property functions, wouldn't that mean that
 the language is encouraging this particular kind of bad style of
 programming?
I really don't see much point in properties/methods that just forwards to an instance variable.
Me either. I mean yes, for anything that is part of a public api you should probably double check everything. But insisting on getters and setters regardless of the requirements of what you are getting and setting? Sounds like an excuse to not think, to me.
The main reason for it is that you can add additional code later when it no longer needs to just get or set the variable. But one of the goals of properties is to make it so that you can just make it a public variable to begin with and then swap it out with a property function later when you need to add code like that. However, that never quite seems to work perfectly, as there's always something that you can do with a variable that you can't do with a property function (e.g. take its address or pass it by ref). Without properties though, you definitely want the getters and setters so that you don't lock yourself out of being able to properly protect the variable when you actually need to later. - Jonathan m Davis
Jan 30 2013
prev sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Wednesday, 30 January 2013 at 00:25:41 UTC, Jonathan M Davis 
wrote:
 1. Make it possible to Mark a variable such that you can't do 
 anything with it that you couldn't do with a property function 
 (e.g. taking its address needs to be illegal).
If we didn't have to interface with C and we were willing to get a little extra processing in order to use flags you could get away with this. In a 64Bit environment it seems plausible. I don't see this as an option realistically with everything as it is, however the potential can't be ignored. Let's say the top 4 bits of a pointer are flags, one for 'is stack' and one for 'is function ptr', etc. The function pointer referenced then then make properties work exactly like variables. Mind you likely a few extra flags may be needed to determine constness for safety, or two ptrs for a getter/setter (or just a small lookup table for a combination of them all). If these flags then are used and recognize that it has a function instead of a variable, it can call the function, however passing to C or anything expecting a variable then it would have to throw an error as there's no way for the D specific flags to be carried over and used safely. struct S { int _a; int a() {return a + 1;} int a(int setA) { _a = setA; return setA; } } Now: void func(ref int a) { a = 100; //real int always passes assert(a == 100); //can't assume true with function property pointer } S s; //passes, flag realizes it's a function that now is //treated as a variable for this purpose. func(s.a); extern(C) void cFunction(int *ptr); //fails, C unaware of handling function reference cFunction(s.a); //fails, same reason. cFunction(&s.a); Perhaps it's a small option that in compiling these flags can be made use of; Instantiation of templates the properties can be treated as variables correctly (invisibly), assuming it never passes a reference to anything it can't verify can handle it. But as before, this is just an idea, which won't be used in D.
Jan 30 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-01-30 00:55, Rob T wrote:

 Given how D currently works, I don't see how we can realistically
 implement a function as a drop in replacement for a variable and expect
 code to continue working as if nothing had changed.

 One of the bigger problems is that the getter returns by value, not ref,
 so everything that expects a ref return will fail.

 I expect to make precise variable emulation through properties will
 require a lot of compiler magic, and there will be inevitable bugs and
 conflicts that follow. I really don't see that there's enough value with
 the property concept to justify the costs of precise variable emulation.

 You know a lot more about implementing compiler magic than I do, so I'll
 ask you if you think the effort is doable enough to justify having
 property functions that can act like a drop in replacement for existing
 variables?
Implement this: struct Foo { property int a; } Lowered to: struct Foo { private int a_; property int a () { return a_; } property int a (int value) { return a_ = value; } } -- /Jacob Carlborg
Jan 30 2013
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 29 Jan 2013 18:09:44 -0500, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 On Tuesday, January 29, 2013 12:10:04 Steven Schveighoffer wrote:
 Sound crazy? Ridiculous? Impossible? Insulting?
It seems like it could work, but without a way to explictly make something a getter property, it will be impossible to change a property function into a variable later without risking breaking code, because then people will still be able to call the property function with parens. Using parens on getter properties has to be illegal for that to work.
I don't think this is quite right. You can never *exactly* replace a field with a property, or vice versa. There are aspects that are different for both. But there are two separate cases here. One is, you define a property that is specific to a type, and then replace it with a field. The other is that there is a DEFINED API, and you replace it with a field. In the first case, yes, you would have to go through and replace () instances with ones that do not have it. If your documentation is clear, then it really is on the user to have made that mistake. With the idea I specified later where getX would require no parentheses, you could specify a property that could not be called like a function unless you use the getX version. But in the second case, consider for instance a range. A range has an empty field/property. If you called it via empty(), then your code is broken for all different types of ranges which use a field (or enum). In any case, I think there is no getting around that changing from a property to a field or vice versa will cause problems for existing code. -Steve
Jan 30 2013
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 30, 2013 at 07:49:58PM -0500, Steven Schveighoffer wrote:
 On Tue, 29 Jan 2013 18:09:44 -0500, Jonathan M Davis
 <jmdavisProg gmx.com> wrote:
 
On Tuesday, January 29, 2013 12:10:04 Steven Schveighoffer wrote:
Sound crazy? Ridiculous? Impossible? Insulting?
It seems like it could work, but without a way to explictly make something a getter property, it will be impossible to change a property function into a variable later without risking breaking code, because then people will still be able to call the property function with parens. Using parens on getter properties has to be illegal for that to work.
I don't think this is quite right. You can never *exactly* replace a field with a property, or vice versa. There are aspects that are different for both. But there are two separate cases here. One is, you define a property that is specific to a type, and then replace it with a field. The other is that there is a DEFINED API, and you replace it with a field. In the first case, yes, you would have to go through and replace () instances with ones that do not have it. If your documentation is clear, then it really is on the user to have made that mistake. With the idea I specified later where getX would require no parentheses, you could specify a property that could not be called like a function unless you use the getX version. But in the second case, consider for instance a range. A range has an empty field/property. If you called it via empty(), then your code is broken for all different types of ranges which use a field (or enum).
[...] Actually, this got me thinking. The range API only requires that .empty evaluates to a bool, right? It doesn't matter if it's a function, a public variable, or an enum, as long as it evaluates (or can be evaluated) to a bool. Some ranges indeed do define .empty as an enum (c.f. infinite ranges), so you couldn't take the address of .empty. Now consider class/struct fields in general. It's entirely possible that a particular class starts off with some fields defined as enums (of the manifest constant sort), say as an enum string. Later on, you may decide that the value should be changeable, so you make it a string class variable. Yet later, you may decide to implement a getter/setter for it for whatever reason. In the process, the only time it's valid to take the address of the field is when it's a string variable. So in that sense, the API of the class really only should specify that field xyz is a value of type string; user code should not depend on its particular implementation (enum, variable, or getter). Marking fields as property is starting to make more and more sense. T -- BREAKFAST.COM halted...Cereal Port Not Responding. -- YHL
Jan 30 2013
prev sibling next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, January 29, 2013 17:32:20 H. S. Teoh wrote:
 If this is the case, then I would have to say that  property is
 fundamentally broken. The whole point of  property is to make functions
 behave like variables, but if this "variable emulation" isn't even
 complete, then it defeats the purpose of having it in the first place.
It works if you can restrict a variable to a reasonable subset of its normal operations (which primarily means that you can't take its address or pass it by ref). You just can't fix that. Not with a systems language like D. Variables have as much low-level control over variables (like taking their address). But if we can do something like struct S {     property int prop; } then that fixes the problem. - Jonathan M Davis
Jan 29 2013
next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Wednesday, 30 January 2013 at 02:29:12 UTC, Jonathan M Davis 
wrote:
 But if we can do something like

 struct S
 {
      property int prop;
 }

 then that fixes the problem.
I had a thought. What if we use this opportunity to also fix the problem with transient ranges. So... what if, instead of using the attribute property for the purpose you suggest, we added a new attribute, let's say noref, and that's what it would mean: struct S { } S s; Transient ranges could notate their front method with noref, which would prevent all incorrect use of them, and would enable their front to return by ref or const ref, instead of by value.
Jan 29 2013
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/30/2013 03:29 AM, Jonathan M Davis wrote:

Nope.
Jan 30 2013
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, January 30, 2013 18:54:20 Timon Gehr wrote:
 On 01/30/2013 03:29 AM, Jonathan M Davis wrote:

Nope.
It was my understanding that it did. Everything that I've read on it indicated - Jonathan M Davis
Jan 30 2013
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/30/2013 08:44 PM, Jonathan M Davis wrote:
 On Wednesday, January 30, 2013 18:54:20 Timon Gehr wrote:
 On 01/30/2013 03:29 AM, Jonathan M Davis wrote:

Nope.
It was my understanding that it did. Everything that I've read on it indicated - Jonathan M Davis
fields can.)
Jan 30 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-01-30 20:44, Jonathan M Davis wrote:

 It was my understanding that it did. Everything that I've read on it indicated


-- /Jacob Carlborg
Jan 30 2013
prev sibling next sibling parent reply "Jesse Phillips" <Jessekphillips+d gmail.com> writes:
Sorry I have to oppose this. It is in no way a compromise as it 
is completely different from everything suggested. I'm going to 
take this opportunity to highjack your thread.

Can an pro- property members claim that the current behavior is 
what you want? I believe this answer is no.

It seems at least some members for  property feel that currently 
functions are being annotated with  property that shouldn't be.

It also seems those for  property aren't fighting optional parens 
as much? Can we discuss fixing the issues we have with this. I 
think a good change is to require parens if returning a callable 
(opposite of Walters suggestion).

--------------------

If I have my above claims mostly correct, then I'd say  property 
needs to be put back in the drawing board and re-implemented.

I'd be for removing it from the language and if we decide on what 
in needs to enforce and should be part of the language, then its 
implementation is completed in a feature branch and remains out 
of the language until it meets the needed enforcement and 
behavior.

Granted I'm not concerned if it doesn't ever come back. I believe 
it has a legitimate role in allowing a change from field to 
function without harming usage that can not be achieved without 
an annotation. However it seems we can't achieve this with the 
combination of features D employs.

I don't agree with the argument that properties provide a 
convince to identify low overhead access. While I'm not 
experienced in this area, profile code should indicate where 
performance is poor, it would be bad to assume "that looks like a 
field, so it must not be where the performance is bad."

---------------------

So let us decide to keep optional (), fix what we can there.

Define what is desired of properties, but for now get rid of what 
we currently know as  property. Then with a complete proposal, we 
can say it must meet these goals or it won't exist. Since 
optional () remain, introducing  property again will not break 
code and we will only deal with broken code now (and there would 
be some just to fix the current behavior and its disconnect with 
-property)
Jan 29 2013
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, January 30, 2013 05:57:14 Jesse Phillips wrote:
 It seems at least some members for  property feel that currently
 functions are being annotated with  property that shouldn't be.
The prime example of that would be save. - Jonathan M Davis
Jan 29 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 30 January 2013 at 05:07:15 UTC, Jonathan M Davis 
wrote:
 On Wednesday, January 30, 2013 05:57:14 Jesse Phillips wrote:
 It seems at least some members for  property feel that 
 currently
 functions are being annotated with  property that shouldn't be.
The prime example of that would be save. - Jonathan M Davis
rehash, dup, length (as a setter), the list goes on and on.
Jan 29 2013
prev sibling next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 30 January 2013 at 04:57:15 UTC, Jesse Phillips 
wrote:
 I don't agree with the argument that properties provide a 
 convince to identify low overhead access. While I'm not 
 experienced in this area, profile code should indicate where 
 performance is poor, it would be bad to assume "that looks like 
 a field, so it must not be where the performance is bad."
Yes, this is true, like always. Even when property isn't involved. Fectching memory that isn't in cache anymore is typically 200-250 CPU cycles on modern x86 architecture. Getting that from a register is immediate. Accessing a variable has unknown cost, and only profile can reveal the truth here. Considering that property/function have some importance in regard of performance is in complete contradiction with how computer and code actually work now. The difference is semantic. In case of property, you think data, in case of function, you think action.
Jan 29 2013
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 30, 2013 at 06:22:05AM +0100, deadalnix wrote:
 On Wednesday, 30 January 2013 at 04:57:15 UTC, Jesse Phillips wrote:
I don't agree with the argument that properties provide a convince
to identify low overhead access. While I'm not experienced in this
area, profile code should indicate where performance is poor, it
would be bad to assume "that looks like a field, so it must not be
where the performance is bad."
Yes, this is true, like always. Even when property isn't involved. Fectching memory that isn't in cache anymore is typically 200-250 CPU cycles on modern x86 architecture. Getting that from a register is immediate. Accessing a variable has unknown cost, and only profile can reveal the truth here.
+1. Too many C programmers (including myself) have preconceived notions about what is efficient and what isn't. Unfortunately, we're wrong more often than we'd like to admit. When we actually run the profiler and get real profile data, it often points to hotspots that are far, far away from where we thought they were. We inherited this premature optimization mindset from the CPUs of the 70's and 80's; today's CPUs have far different performance characteristics, and our preconceived notions are mostly all wrong.
 Considering that property/function have some importance in regard of
 performance is in complete contradiction with how computer and code
 actually work now.
 
 The difference is semantic. In case of property, you think data, in
 case of function, you think action.
+1. The voice of reason. T -- I'm still trying to find a pun for "punishment"...
Jan 29 2013
prev sibling parent "Rob T" <alanb ucora.com> writes:
On Wednesday, 30 January 2013 at 05:22:06 UTC, deadalnix wrote:
 On Wednesday, 30 January 2013 at 04:57:15 UTC, Jesse Phillips 
 wrote:
 I don't agree with the argument that properties provide a 
 convince to identify low overhead access. While I'm not 
 experienced in this area, profile code should indicate where 
 performance is poor, it would be bad to assume "that looks 
 like a field, so it must not be where the performance is bad."
Yes, this is true, like always. Even when property isn't involved. Fectching memory that isn't in cache anymore is typically 200-250 CPU cycles on modern x86 architecture. Getting that from a register is immediate. Accessing a variable has unknown cost, and only profile can reveal the truth here. Considering that property/function have some importance in regard of performance is in complete contradiction with how computer and code actually work now. The difference is semantic. In case of property, you think data, in case of function, you think action.
Yes, very good points. We're likely optimizing away for little to no gain most of the time, and maybe even making things worse not better in some cases. --rt
Jan 29 2013
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 29 Jan 2013 23:57:14 -0500, Jesse Phillips  
<Jessekphillips+d gmail.com> wrote:

 Sorry I have to oppose this. It is in no way a compromise as it is  
 completely different from everything suggested. I'm going to take this  
 opportunity to highjack your thread.
You are welcome to it! I don't know if there is a thread on this newsgroup about properties that hasn't been hijacked. I should explain that my reasoning behind this is: 1. Walter wants to get rid of property 2. Dispite 4 years of assuming property will be implemented, the old D1-style crap is still in place. 3. I've been using Objective C for the last 10 months, which implements a similar scheme to properties. The compromise is: OK, you want to ditch property? I can live with that as long as we have some way to designate properties. How about this?
 Can an pro- property members claim that the current behavior is what you  
 want? I believe this answer is no.
The answer is no, but only because what we asked for was never implemented. What was ORIGINALLY designed with property (enforcement of parentheses on functions, enforcement against parentheses on properties) is what we wanted.
 It seems at least some members for  property feel that currently  
 functions are being annotated with  property that shouldn't be.
This is unavoidable. It's like saying I feel some functions are incorrectly named. property has nothing to do with it. There is no "right" answer to whether something should be a property or not, just like there is no "right" name for a function.
 It also seems those for  property aren't fighting optional parens as  
 much? Can we discuss fixing the issues we have with this. I think a good  
 change is to require parens if returning a callable (opposite of Walters  
 suggestion).
Yes, if the choice is between having the previous implementation (D1) and optional parentheses with a way to designate properties, I'll choose the latter.
 If I have my above claims mostly correct, then I'd say  property needs  
 to be put back in the drawing board and re-implemented.
If you want to replace property, we need a replacement. property still serves a purpose, even in it's currently crippled form.
 I'd be for removing it from the language and if we decide on what in  
 needs to enforce and should be part of the language, then its  
 implementation is completed in a feature branch and remains out of the  
 language until it meets the needed enforcement and behavior.
Fine, but leave property in until you have completed the replacement feature.
 Granted I'm not concerned if it doesn't ever come back. I believe it has  
 a legitimate role in allowing a change from field to function without  
 harming usage that can not be achieved without an annotation. However it  
 seems we can't achieve this with the combination of features D employs.
Ah, your subtle bias shines through ;) The real fact of the matter is, if D never had the "hack" properties it did, I actually wouldn't care. Calling functions instead of setting or getting properties is not that horrible. But writeln = "hi" is horrible.
 I don't agree with the argument that properties provide a convince to  
 identify low overhead access. While I'm not experienced in this area,  
 profile code should indicate where performance is poor, it would be bad  
 to assume "that looks like a field, so it must not be where the  
 performance is bad."
In general, the idea is to implement fields without having to create storage for them. It will never perform as well as a field.
 ---------------------

 So let us decide to keep optional (), fix what we can there.

 Define what is desired of properties, but for now get rid of what we  
 currently know as  property. Then with a complete proposal, we can say  
 it must meet these goals or it won't exist. Since optional () remain,  
 introducing  property again will not break code and we will only deal  
 with broken code now (and there would be some just to fix the current  
 behavior and its disconnect with -property)
In other words, go back to D1 properties. No thanks. -Steve
Jan 30 2013
next sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Thursday, 31 January 2013 at 01:26:19 UTC, Steven 
Schveighoffer wrote:
 The compromise is: OK, you want to ditch  property?  I can live 
 with that as long as we have some way to designate properties.  
 How about this?
It's only natural that a person wants to advocate for his or her own proposal. That having been said, can I interest you in mine? :-) http://forum.dlang.org/thread/kdukid$stg$1 digitalmars.com?page=2#post-yqvrjszzlcpmmuyqyxdz:40forum.dlang.org That a long link. Here's a shorter one if it doesn't work (my experience with these forums is limited, sometimes the line gets truncated wrongly): http://forum.dlang.org/thread/kdukid$stg$1 digitalmars.com?page=2 If it fails to solve any of your problems, perhaps you could tell me how or why. It is necessary to read the whole discussion to get insight on how the proposal is developing. Also note that the top proposal is not directly related to the property discussion, so you have to skip down a few lines to get to the property part.
Jan 30 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 30 Jan 2013 21:49:35 -0500, Zach the Mystic  
<reachBUTMINUSTHISzach googlymail.com> wrote:

 On Thursday, 31 January 2013 at 01:26:19 UTC, Steven Schveighoffer wrote:
 The compromise is: OK, you want to ditch  property?  I can live with  
 that as long as we have some way to designate properties.  How about  
 this?
It's only natural that a person wants to advocate for his or her own proposal. That having been said, can I interest you in mine? :-) http://forum.dlang.org/thread/kdukid$stg$1 digitalmars.com?page=2#post-yqvrjszzlcpmmuyqyxdz:40forum.dlang.org That a long link. Here's a shorter one if it doesn't work (my experience with these forums is limited, sometimes the line gets truncated wrongly): http://forum.dlang.org/thread/kdukid$stg$1 digitalmars.com?page=2 If it fails to solve any of your problems, perhaps you could tell me how or why. It is necessary to read the whole discussion to get insight on how the proposal is developing. Also note that the top proposal is not directly related to the property discussion, so you have to skip down a few lines to get to the property part.
What you describe is almost exactly something I suggested when the properties but with multiple get/set functions. Can't find it right now, but I found several suggestions of that type. I even found a few that propose exactly what I have! It actually is a bit depressing, we have to reset the clock back to late 2009 to start over with properties... -Steve
Jan 31 2013
parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-01-31 14:50:40 +0000, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 It actually is a bit depressing, we have to reset the clock back to 
 late  2009 to start over with properties...
I haven't participated in the discussions about properties this time around because it's pretty obvious to me it's getting nowhere. It seems to me that nothing can be done at this point in time if we want to avoid a breakage of almost all current D code. Well, we could make some compromises, but a compromise is going to complicate things while solving only some of the issues; few of us will be really satisfied with such a thing. By the way I was a big proponent of properties with no semantic ambiguities back in 2009. I even proposed a getX/setX scheme, which I still like very much. I'd like to see real properties in D, but I don't think it's realistic at this point. And you have to admit that the way D does properties today is both simple, clever, and appealing. It does have some error-prone liabilities when it comes to callable types and generic programming especially, but beside that I do like the design of the thing. It's a natural extension of UFCS, even though it predates UFCS. Perhaps we should just call it a day and live with the ambiguities. I don't like it, but I don't see any viable alternative. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca/
Jan 31 2013
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 Jan 2013 10:40:18 -0500, Michel Fortin  
<michel.fortin michelf.ca> wrote:

 On 2013-01-31 14:50:40 +0000, "Steven Schveighoffer"  
 <schveiguy yahoo.com> said:

 It actually is a bit depressing, we have to reset the clock back to  
 late  2009 to start over with properties...
By the way I was a big proponent of properties with no semantic ambiguities back in 2009. I even proposed a getX/setX scheme, which I still like very much. I'd like to see real properties in D, but I don't think it's realistic at this point.
couldn't find.
 And you have to admit that the way D does properties today is both  
 simple, clever, and appealing. It does have some error-prone liabilities  
 when it comes to callable types and generic programming especially, but  
 beside that I do like the design of the thing. It's a natural extension  
 of UFCS, even though it predates UFCS. Perhaps we should just call it a  
 day and live with the ambiguities. I don't like it, but I don't see any  
 viable alternative.
I liked it when I first saw it. Seems, as you say, clever and intuitive. However, it left a bad taste in my mouth when I had a certain situation that I was forced to deal with. In Tango, I developed a struct called TimeSpan, which was a span of time (we have Duration in std.datetime which is similar). I created constructors for spans of time that were named after the units they used. For example, if you wanted a 10 minute, 30 second timespan you could do: auto ts = TimeSpan.minutes(10) + TimeSpan.seconds(30); The idea was to avoid having to document such a line, the above looks obvious. Now, I also had accessors for a given timespan to return the timespan in those units. For example: assert(ts.seconds == 10 * 60 + 30); The problem arose when someone complained that the seconds "setter" wasn't working: ts.seconds = 5; assert(ts.seconds != 5); Wait, what? I never made seconds a settable property! Turns out, this translates to: ts.seconds(5); and because you can call static methods from an instance (another thing I don't really like), it made the constructor act like a property! A completely unintended consequence. The only viable solution (this was D1), was to rename the functions so they couldn't be mistaken as properties. So they all became "fromSeconds" e.g. Yuck! This is one of the reasons I was so excited about D2 getting full-fledged But we never got what was promised, and now we basically have the same junk with some duct-taped garbage keyword that half works. No wonder people don't like property! At this point, I think it would be a huge step backwards not to solve (or at least have a yet-to-be implemented solution for) the above problem. I can live with getters simply being parentheses-less functions, that isn't so bad (though as an API designer, I'd like to have full control over that). But using any function as a setter is crap, and will forever be a wart on D unless we fix it. It will result in bizarre things like mystery setters that don't exist, especially with UFCS. -Steve
Jan 31 2013
parent Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-01-31 15:57:12 +0000, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 [...]
 
 Turns out, this translates to:
 
 ts.seconds(5);
 
 and because you can call static methods from an instance (another thing 
 I  don't really like), it made the constructor act like a property!  A  
 completely unintended consequence.
 
 The only viable solution (this was D1), was to rename the functions so  
 they couldn't be mistaken as properties.  So they all became 
 "fromSeconds"  e.g.  Yuck!
Could also have used global functions instead of static ones inside of the class. I still see your point.
 At this point, I think it would be a huge step backwards not to solve 
 (or  at least have a yet-to-be implemented solution for) the above 
 problem.  I  can live with getters simply being parentheses-less 
 functions, that isn't  so bad (though as an API designer, I'd like to 
 have full control over  that).  But using any function as a setter is 
 crap, and will forever be a  wart on D unless we fix it.  It will 
 result in bizarre things like mystery  setters that don't exist, 
 especially with UFCS.
True. Still, Walter has shown no sign he's willing to accept any solution that won't work with most of current code. Just look at his syntax proposal in the thread "take it behind the woodshed and shoot it?" if you're not convinced. At the same time he has gone to great lengths to keep things backward compatible even with experimental syntaxes (I'm thinking of user defined attributes). I seriously doubt changing the syntax for setters will happen… unless you can make it backward compatible. As for keeping the syntax backward compatible, you could for instance propose an attribute to prevent people from using the setter syntax when calling a particular function: explicit TimeDuration seconds(float); -- Michel Fortin michel.fortin michelf.ca http://michelf.ca/
Jan 31 2013
prev sibling next sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Thursday, 31 January 2013 at 15:40:19 UTC, Michel Fortin wrote:
 And you have to admit that the way D does properties today is 
 both simple, clever, and appealing. It does have some 
 error-prone liabilities when it comes to callable types and 
 generic programming especially, but beside that I do like the 
 design of the thing. It's a natural extension of UFCS, even 
 though it predates UFCS. Perhaps we should just call it a day 
 and live with the ambiguities. I don't like it, but I don't see 
 any viable alternative.
I'm hoping that the community won't close the books on this issue without even *examining* my proposal, found here: http://forum.dlang.org/thread/kdukid$stg$1 digitalmars.com?page=2#post-yqvrjszzlcpmmuyqyxdz:40forum.dlang.org If you want the main points, just read all of the posts by Zach the Mystic. I've done my best to defend all criticisms. I simply feel obliged to point out to everyone who wants to shut this issue down that there is another proposal. You may accuse me of being ignorant, or too new to know what I'm saying, but at least try to read the proposal and how the arguments against it have been defended. Or just shut me up by saying something about why it's just wrong or simply can't work.
Jan 31 2013
next sibling parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Thursday, 31 January 2013 at 19:13:03 UTC, Zach the Mystic 
wrote:

Here's the most concise quote which gives you the gist of the 
thing:

"Now classes are a different kettle of fish. I haven't thought
them out and I don't think I need to. They may work seamlessly
with my idea or be fraught with problems, I don't know."

"But there will never be a need for a new empty struct. The
operator new makes no sense. There's no data! Imagine an empty
struct as a list of functions under a namespace. That's all it
really is. Except it just so happens that this namespace has a
bunch of built-in functions which allow it to appear in normal
code as if it's a *type*. Want it to appear with parens, so it
looks like a function you're calling? Just define opCall inside
the struct. Want it to appear before an equals sign. Just define
opAssign. As an array? opIndex. A basic type such as an int?
opGet. There will never be any need to create an instance. You
only need one. At runtime, there is no evidence of a pointer at
all, just normal data being passed to normal functions."
Jan 31 2013
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 Jan 2013 14:13:02 -0500, Zach the Mystic  
<reachBUTMINUSTHISzach googlymail.com> wrote:

 On Thursday, 31 January 2013 at 15:40:19 UTC, Michel Fortin wrote:
 And you have to admit that the way D does properties today is both  
 simple, clever, and appealing. It does have some error-prone  
 liabilities when it comes to callable types and generic programming  
 especially, but beside that I do like the design of the thing. It's a  
 natural extension of UFCS, even though it predates UFCS. Perhaps we  
 should just call it a day and live with the ambiguities. I don't like  
 it, but I don't see any viable alternative.
I'm hoping that the community won't close the books on this issue without even *examining* my proposal, found here: http://forum.dlang.org/thread/kdukid$stg$1 digitalmars.com?page=2#post-yqvrjszzlcpmmuyqyxdz:40forum.dlang.org
been proposed before. Not that there's anything wrong with it, I'm saying it's a duplicate of what has been proposed. If it were to be an acceptable solution, I'd be for familiarity). Don't hold your breath waiting for Walter to respond though, he is notoriously silent unless he completely disagrees with you. -Steve
Jan 31 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Thursday, 31 January 2013 at 20:52:39 UTC, Steven 
Schveighoffer wrote:
 I'm hoping that the community won't close the books on this 
 issue without even *examining* my proposal, found here:

 http://forum.dlang.org/thread/kdukid$stg$1 digitalmars.com?page=2#post-yqvrjszzlcpmmuyqyxdz:40forum.dlang.org
which has been proposed before. Not that there's anything wrong with it, I'm saying it's a duplicate of what has been proposed. If it were to be an acceptable solution, I'd be on board (though I don't know why Don't hold your breath waiting for Walter to respond though, he is notoriously silent unless he completely disagrees with you. -Steve
Thanks for looking at it. didn't find my suggestion to be a duplicate of them. In set? My suggestion allows harnessing the full power of D struct has? My opGet is just another opXXX definable for all structs, not just properties. I had said it was necessary to achieve structs as properties, but I think I was wrong. It's just the equivalent of: int __someRandomFunction() { return _propValue; } alias __someRandomFunction this; But it would be syntactically nicer, much like Highlander structs are syntactically nicer. Therefore, the only language change absolutely required would be making non-static structs nested in structs behave like non-static structs nested in functions, which they arguably should do anyway. Also under the hood, some important optimizations getting rid of pointers for data-less structs. You know, the words "opGet" and "opAssign" (and all the other opXXX's) are rather ugly, but I guess anyone who has defined them in the past could come to love them, for their power if not for their looks.
Jan 31 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 Jan 2013 17:11:28 -0500, Zach the Mystic  
<reachBUTMINUSTHISzach googlymail.com> wrote:

 Thanks for looking at it.



 properties do anything more than just get and set? My suggestion allows  
 harnessing the full power of D struct semantics. Is this not a far more  

property int foo { get {return _foo;} set {_foo = value;} } Your proposal looks like this: foo struct { int opGet() {return _foo;} void opSet(int value) {_foo = value;} } What I see is that the getter and setter are assigned specific contextual keywords (opGet vs. get, and opSet vs. set). It seems like a very similar (albeit more verbose) solution. What I had originally suggested for properties is this: property int foo { int get() {return _foo;} // only one getter allowed void set(int v) {_foo = v;} void set(float v) {_foo = (int)v;} // more than one setter allowed } I think these are all along the same line of solutions. I don't think they are bad, but clearly they weren't used 4 years ago, so it may be difficult to convince Walter to use them now.
 My opGet is just another opXXX definable for all structs, not just  
 properties.
I didn't see that, but I also don't really see the point of that. What value does opGet have unless it's a getter for a property?
 I had said it was necessary to achieve structs as properties, but I  
 think I was wrong. It's just the equivalent of:

 int __someRandomFunction() { return _propValue; }
 alias __someRandomFunction this;

 But it would be syntactically nicer, much like Highlander structs are  
 syntactically nicer. Therefore, the only language change absolutely  
 required would be making non-static structs nested in structs behave  
 like non-static structs nested in functions, which they arguably should  
 do anyway. Also under the hood, some important optimizations getting rid  
 of pointers for data-less structs.
This is a VERY bad idea. A struct is POD. For example, consider a range type for a container. You may not NEED to have a pointer to the container, so that is wasted bytes. Also note that structs are not meant to have internal pointers. So a "property" struct with an internal pointer The strange case for a struct type inside a function kind of makes sense, because of the ability to access the function's variables, and because you can't really move the stack frame. -Steve
Jan 31 2013
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 Jan 2013 17:54:21 -0500, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:


 Also note that structs are not meant to have internal pointers.  So a  
 "property" struct with an internal pointer
Forgot to finish this sentence before I hit send. So a "property" struct with an internal pointer would have to be modified when a copy of the struct is made. But this is bad, structs are supposed to be movable WITHOUT updating anything. -Steve
Jan 31 2013
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Thursday, 31 January 2013 at 23:05:14 UTC, Steven 
Schveighoffer wrote:
 On Thu, 31 Jan 2013 17:54:21 -0500, Steven Schveighoffer 
 <schveiguy yahoo.com> wrote:


 Also note that structs are not meant to have internal 
 pointers.  So a "property" struct with an internal pointer
Forgot to finish this sentence before I hit send. So a "property" struct with an internal pointer would have to be modified when a copy of the struct is made. But this is bad, structs are supposed to be movable WITHOUT updating anything.
Except when postblit is defined...? Or opAssign?
Jan 31 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 Jan 2013 18:48:18 -0500, Era Scarecrow <rtcvb32 yahoo.com>  
wrote:

 On Thursday, 31 January 2013 at 23:05:14 UTC, Steven Schveighoffer wrote:
 On Thu, 31 Jan 2013 17:54:21 -0500, Steven Schveighoffer  
 <schveiguy yahoo.com> wrote:


 Also note that structs are not meant to have internal pointers.  So a  
 "property" struct with an internal pointer
Forgot to finish this sentence before I hit send. So a "property" struct with an internal pointer would have to be modified when a copy of the struct is made. But this is bad, structs are supposed to be movable WITHOUT updating anything.
Except when postblit is defined...? Or opAssign?
I'm pretty sure structs are forbidden to have internal pointers. They must be able to be moved without any post-processing. -Steve
Jan 31 2013
next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Thursday, 31 January 2013 at 23:57:59 UTC, Steven 
Schveighoffer wrote:
 On Thu, 31 Jan 2013 18:48:18 -0500, Era Scarecrow 
 <rtcvb32 yahoo.com> wrote:
 On Thursday, 31 January 2013 at 23:05:14 UTC, Steven 
 Schveighoffer wrote:
 Also note that structs are not meant to have internal 
 pointers.  So a "property" struct with an internal pointer

 So a "property" struct with an internal pointer would have to 
 be modified when a copy of the struct is made.  But this is 
 bad, structs are supposed to be movable WITHOUT updating 
 anything.
Except when postblit is defined...? Or opAssign?
I'm pretty sure structs are forbidden to have internal pointers. They must be able to be moved without any post-processing.
Hmmm... Well I threw out an idea about not returning inner structs (outside the controlling parent). If that were followed, the reference to the parent could silently be added to the function call rather than the struct itself; Then the data can be moved freely.
Jan 31 2013
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, January 31, 2013 18:58:00 Steven Schveighoffer wrote:
 I'm pretty sure structs are forbidden to have internal pointers.  They
 must be able to be moved without any post-processing.
Structs must be moveable. I believe that you can technically have a struct with a pointer refering to one of its members, but if you do, it will break as soon as your struct is moved (which _will_ happen). - Jonathan M Davis
Jan 31 2013
prev sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Thursday, 31 January 2013 at 22:54:21 UTC, Steven 
Schveighoffer wrote:


 property int foo {
   get {return _foo;}
   set {_foo = value;}
 }

 Your proposal looks like this:

 foo struct {
    int opGet() {return _foo;}
    void opSet(int value) {_foo = value;}
 }

 What I see is that the getter and setter are assigned specific 
 contextual keywords (opGet vs. get, and opSet vs. set). It 
 seems like a very similar (albeit more verbose) solution.

 What I had originally suggested for properties is this:

 property int foo {
    int get() {return _foo;} // only one getter allowed
    void set(int v) {_foo = v;}
    void set(float v) {_foo = (int)v;} // more than one setter 
 allowed
 }

 I think these are all along the same line of solutions.  I 
 don't think they are bad, but clearly they weren't used 4 years 
 ago, so it may be difficult to convince Walter to use them now.

 My opGet is just another opXXX definable for all structs, not 
 just properties.
I didn't see that, but I also don't really see the point of that. What value does opGet have unless it's a getter for a property?
 I had said it was necessary to achieve structs as properties, 
 but I think I was wrong. It's just the equivalent of:

 int __someRandomFunction() { return _propValue; }
 alias __someRandomFunction this;

 But it would be syntactically nicer, much like Highlander 
 structs are syntactically nicer. Therefore, the only language 
 change absolutely required would be making non-static structs 
 nested in structs behave like non-static structs nested in 
 functions, which they arguably should do anyway. Also under 
 the hood, some important optimizations getting rid of pointers 
 for data-less structs.
This is a VERY bad idea. A struct is POD. For example, consider a range type for a container. You may not NEED to have a pointer to the container, so that is wasted bytes. Also note that structs are not meant to have internal pointers. So a "property" struct with an internal pointer The strange case for a struct type inside a function kind of makes sense, because of the ability to access the function's variables, and because you can't really move the stack frame. -Steve
I think my suggestion goes far beyond what you suspect. It goes way beyond mere getting and setting of variables. Here is basically how you implement a basic int as a property, assuming my new syntax and language adjustments. You need: 1) a struct to have the property in, which is just a normal struct. 2) An actual integer which will be indirectly accessed by using the properties. Let's call it "_n" and the property "n". 3) a struct to hold all of the property functions which access _n. THIS STRUCT CONTAINS NO DATA OF ITS OWN. 4) A bunch of methods implementing all the operators you want. For int, that's quite a lot, so I'll shorten it to a getter, a setter, and an adder. I'll even leave out opGet and use an alias to what might as well be opGet. I'll give the adder a little personality because what's the point of properties if they don't do something different from a basic type? struct myStruct { int _n; n struct { int __mightAsWellBeOpGet() { return _n; } alias __mightAsWellBeOpGet this; int opAssign(int newN) { _n = newN; return _n; } int opBinary(string op) (int rhs) { static if (op == "+") { writeln("You sure are adding a funky int, my friend..."); return _n + rhs; } else static assert(0, "Operator "~op~" not implemented"); } } } This is not some kind of special property implementation. n is a struct. It has no data and therefore is a very peculiar kind of struct. A struct with no data needs only one instance, ever. Copying it is pointless. Taking its address is pointless. Creating a new instance is pointless. Passing it by ref is pointless. All operations which require more than one instance are pointless, which is why it doesn't need a separately defined type. The type and the instance can therefore use the same name, n in this case. Note that n uses the new rule which allows it access to its parent's scope, the same way it would in a nested function. The only pointer it needs is the same pointer used for myStruct, since myStruct actually stores some data. Using the int is as simple as: myStruct foo; foo.n = 4; // Calls opAssign writeln(foo.n); // uses alias this to call __mightAsWellBeOpGet writeln(foo.n + 4); // Calls opBinary. Prints: You sure are adding a funky int, my friend... 8 There's literally nothing these properties can't do that a full-fledged struct type couldn't do.
Jan 31 2013
next sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Friday, 1 February 2013 at 00:59:47 UTC, Zach the Mystic wrote:
 writeln(foo.n); // uses alias this to call __mightAsWellBeOpGet
No it won't. It will print "n()". And that exactly (passing to a templated parameter) is the insurmountable problem in using a variable to represent a property.
Jan 31 2013
next sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Friday, 1 February 2013 at 01:53:05 UTC, TommiT wrote:
 On Friday, 1 February 2013 at 00:59:47 UTC, Zach the Mystic 
 wrote:
 writeln(foo.n); // uses alias this to call __mightAsWellBeOpGet
No it won't. It will print "n()". And that exactly (passing to a templated parameter) is the insurmountable problem in using a variable to represent a property.
On Friday, 1 February 2013 at 01:53:05 UTC, TommiT wrote:
 And that exactly (passing to a templated parameter) is the 
 insurmountable problem in using a variable to represent a 
 property.
And here's another example of why it is as big of a problem as I make it sound to be: import std.concurrency; struct Array { int _len; length struct // Using Zach's syntax { property get() { return _len; } alias this = get; void opAssign(int rhs) { _len = rhs; } } } void func(T)(T t) { auto v = t; v = 10; } void main() { Array arr; spawn(&func!int, arr.length); arr.length = 20; // And here we have a data-race. // Good luck trying to find these // kinds of bugs. }
Jan 31 2013
next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Friday, 1 February 2013 at 02:27:30 UTC, TommiT wrote:
 [..] as big of a problem as I make it sound to be:
...make it out to be...
Jan 31 2013
prev sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 02:27:30 UTC, TommiT wrote:
 And here's another example of why it is as big of a problem as 
 I make it sound to be:

 import std.concurrency;

 struct Array
 {
     int _len;

     length struct // Using Zach's syntax
     {
          property get() { return _len; }
         alias this = get;
         void opAssign(int rhs) { _len = rhs; }
     }
 }

 void func(T)(T t)
 {
     auto v = t;
     v = 10;
 }

 void main()
 {
     Array arr;
     spawn(&func!int, arr.length);
     arr.length = 20; // And here we have a data-race.
                      // Good luck trying to find these
                      // kinds of bugs.
 }
I'm sorry, I know very little about race conditions. If you might explain just a little bit about what is happening here, I'd be in a better position to understand what you're saying. I really can't say anything other than please describe what this does and why it's a problem at this time.
Jan 31 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Friday, 1 February 2013 at 03:13:42 UTC, Zach the Mystic wrote:
 On Friday, 1 February 2013 at 02:27:30 UTC, TommiT wrote:
 And here's another example of why it is as big of a problem as 
 I make it sound to be:

 import std.concurrency;

 struct Array
 {
    int _len;

    length struct // Using Zach's syntax
    {
         property get() { return _len; }
        alias this = get;
        void opAssign(int rhs) { _len = rhs; }
    }
 }

 void func(T)(T t)
 {
    auto v = t;
    v = 10;
 }

 void main()
 {
    Array arr;
    spawn(&func!int, arr.length);
    arr.length = 20; // And here we have a data-race.
                     // Good luck trying to find these
                     // kinds of bugs.
 }
I'm sorry, I know very little about race conditions. If you might explain just a little bit about what is happening here, I'd be in a better position to understand what you're saying. I really can't say anything other than please describe what this does and why it's a problem at this time.
spawn(&func!int, arr.length); ...creates a new thread and runs the following function call in it: func!(int)(arr.length) While that function call is evaluating in the new thread, the old thread may simultaneosly execute: arr.length = 20; Since both of those threads end up at some point calling arr.length.opAssign and therefore both of them may assign to arr._len simultaneously, that's a data-race. It would be data-race also if only one of them wrote to it and the other one just read it.
Jan 31 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 03:39:19 UTC, TommiT wrote:
 On Friday, 1 February 2013 at 03:13:42 UTC, Zach the Mystic 
 wrote:
 On Friday, 1 February 2013 at 02:27:30 UTC, TommiT wrote:
 And here's another example of why it is as big of a problem 
 as I make it sound to be:

 import std.concurrency;

 struct Array
 {
   int _len;

   length struct // Using Zach's syntax
   {
        property get() { return _len; }
       alias this = get;
       void opAssign(int rhs) { _len = rhs; }
   }
 }

 void func(T)(T t)
 {
   auto v = t;
   v = 10;
 }

 void main()
 {
   Array arr;
   spawn(&func!int, arr.length);
   arr.length = 20; // And here we have a data-race.
                    // Good luck trying to find these
                    // kinds of bugs.
 }
I'm sorry, I know very little about race conditions. If you might explain just a little bit about what is happening here, I'd be in a better position to understand what you're saying. I really can't say anything other than please describe what this does and why it's a problem at this time.
spawn(&func!int, arr.length); ...creates a new thread and runs the following function call in it: func!(int)(arr.length) While that function call is evaluating in the new thread, the old thread may simultaneosly execute: arr.length = 20; Since both of those threads end up at some point calling arr.length.opAssign and therefore both of them may assign to arr._len simultaneously, that's a data-race. It would be data-race also if only one of them wrote to it and the other one just read it.
I'm familiar with the fact that programmers face endless woes with regard to data-races. I thought that D has unshared data by default. But since Array arr is defined in main instead of outside main, therefore it is sharable between the two threads? If two threads have access to the same data, what makes length as a property different from length as an int? This problem may be over my head for now...
Jan 31 2013
parent "TommiT" <tommitissari hotmail.com> writes:
On Friday, 1 February 2013 at 04:22:51 UTC, Zach the Mystic wrote:
 On Friday, 1 February 2013 at 03:39:19 UTC, TommiT wrote:
 On Friday, 1 February 2013 at 03:13:42 UTC, Zach the Mystic 
 wrote:
 On Friday, 1 February 2013 at 02:27:30 UTC, TommiT wrote:
 And here's another example of why it is as big of a problem 
 as I make it sound to be:

 import std.concurrency;

 struct Array
 {
  int _len;

  length struct // Using Zach's syntax
  {
       property get() { return _len; }
      alias this = get;
      void opAssign(int rhs) { _len = rhs; }
  }
 }

 void func(T)(T t)
 {
  auto v = t;
  v = 10;
 }

 void main()
 {
  Array arr;
  spawn(&func!int, arr.length);
  arr.length = 20; // And here we have a data-race.
                   // Good luck trying to find these
                   // kinds of bugs.
 }
I'm sorry, I know very little about race conditions. If you might explain just a little bit about what is happening here, I'd be in a better position to understand what you're saying. I really can't say anything other than please describe what this does and why it's a problem at this time.
spawn(&func!int, arr.length); ...creates a new thread and runs the following function call in it: func!(int)(arr.length) While that function call is evaluating in the new thread, the old thread may simultaneosly execute: arr.length = 20; Since both of those threads end up at some point calling arr.length.opAssign and therefore both of them may assign to arr._len simultaneously, that's a data-race. It would be data-race also if only one of them wrote to it and the other one just read it.
I'm familiar with the fact that programmers face endless woes with regard to data-races. I thought that D has unshared data by default. But since Array arr is defined in main instead of outside main, therefore it is sharable between the two threads? If two threads have access to the same data, what makes length as a property different from length as an int? This problem may be over my head for now...
Actually, that example of mine was wrong - it's not a data-race. I failed to notice that in: spawn(&func!int, arr.length); ...arr.length is actually converted to int using alias this. My bad. Now I'm going to repeat the "spooky modification at a distance" problem I showed earlier, but this time, instead of writing it in the new syntax and the new struct behaviour you invented, I write it using current D syntax: import std.concurrency; struct Array { int _len; struct PropType { Array* _outer; // In your syntax this was implicit property int get() { return _outer._len; } alias this = get; void opAssign(int rhs) { _outer._len = rhs; } } PropType length; } void func(T)(T t) if (isImplicitlyConvertible!(T,int)) { // Given that is(T == Array.PropType), then // all 3 lines below do the same thing: t = 42; t.opAssign(42); t._outer._len = 42; } void main() { Array arr; // setting the _outer pointer to the enclosing object: arr.length._outer = &arr; assert(arr._len == 0); func(arr.length); // no conversion to int happening here assert(arr._len == 42); } So, it's possible to modify arr._len just by passing arr.length by value to a function.
Feb 01 2013
prev sibling next sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 01:53:05 UTC, TommiT wrote:
 On Friday, 1 February 2013 at 00:59:47 UTC, Zach the Mystic 
 wrote:
 writeln(foo.n); // uses alias this to call __mightAsWellBeOpGet
No it won't. It will print "n()". And that exactly (passing to a templated parameter) is the insurmountable problem in using a variable to represent a property.
I need to study this principle a little more. In other words, alias this is a templated parameter in this case? Which page is the documentation for these templated parameters, because I didn't see templates in my code.
Jan 31 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Friday, 1 February 2013 at 02:52:42 UTC, Zach the Mystic wrote:
 I need to study this principle a little more. In other words, 
 alias this is a templated parameter in this case? Which page is 
 the documentation for these templated parameters, because I 
 didn't see templates in my code.
No, alias this is basically implicit cast operator that will be tried if everything else fails. But writeln is a function template, i.e. its parameters/arguments are templated. http://dlang.org/template.html
Jan 31 2013
parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 03:12:29 UTC, TommiT wrote:
 On Friday, 1 February 2013 at 02:52:42 UTC, Zach the Mystic 
 wrote:
 I need to study this principle a little more. In other words, 
 alias this is a templated parameter in this case? Which page 
 is the documentation for these templated parameters, because I 
 didn't see templates in my code.
No, alias this is basically implicit cast operator that will be tried if everything else fails. But writeln is a function template, i.e. its parameters/arguments are templated. http://dlang.org/template.html
If what you say is true, then all the more reason to build opGet into the compiler... Was I correct in saying that the template in question was to!string(foo.n)? Or does the problem occur in passing to writeln() itself?
Jan 31 2013
prev sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 01:53:05 UTC, TommiT wrote:
 On Friday, 1 February 2013 at 00:59:47 UTC, Zach the Mystic 
 wrote:
 writeln(foo.n); // uses alias this to call __mightAsWellBeOpGet
No it won't. It will print "n()". And that exactly (passing to a templated parameter) is the insurmountable problem in using a variable to represent a property.
to!string(foo.n)... hmmm... not that I know how to solve it right away, but is it possible to do: alias template theFuncIActuallyWant this; int theFuncIActuallyWant() { return 1; } ...in order to have it pass the right thing to the template parameter? That's just a jury rigged syntax which might help structs make more sense to the compiler when passed through templates. You say it's insurmountable, and I don't know enough about the details to know, but it seems like surely SOMETHING could be done to get the right result without messing up everything else in the process.
Jan 31 2013
next sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 03:08:12 UTC, Zach the Mystic wrote:
 On Friday, 1 February 2013 at 01:53:05 UTC, TommiT wrote:
 On Friday, 1 February 2013 at 00:59:47 UTC, Zach the Mystic 
 wrote:
 writeln(foo.n); // uses alias this to call 
 __mightAsWellBeOpGet
No it won't. It will print "n()". And that exactly (passing to a templated parameter) is the insurmountable problem in using a variable to represent a property.
to!string(foo.n)... hmmm...
I think this is taken care of actually, with opCast(string). The docs for std.conv.to with opCast may contain a typo: "toImpl(T, S)(S value); When source type supports member template function opCast, is is used." I think it might mean "it is used" since I don't know why it would use "is" instead of the opCast. If that's true, just override opCast(string), no? Still, it would be great to be able to "prefer" a particular alias this when passed to templates.
Jan 31 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Friday, 1 February 2013 at 03:23:09 UTC, Zach the Mystic wrote:
 I think it might mean "it is used" since I don't know why it 
 would use "is" instead of the opCast. If that's true, just 
 override opCast(string), no?
Yes, there's probably a way to pass to writeln by providing opCast(string). But we're not talking only about writeln here, we're talking about all function templates being a potential problem.
Jan 31 2013
parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 03:44:51 UTC, TommiT wrote:
 On Friday, 1 February 2013 at 03:23:09 UTC, Zach the Mystic 
 wrote:
 I think it might mean "it is used" since I don't know why it 
 would use "is" instead of the opCast. If that's true, just 
 override opCast(string), no?
Yes, there's probably a way to pass to writeln by providing opCast(string). But we're not talking only about writeln here, we're talking about all function templates being a potential problem.
Not really sure what you mean. I have a bunch of thoughts, but my overall knowledge of these things is too little, I'm afraid. If you're interested, I'd like an example of how the templates will be so much of a problem, illustrating the collision between the two core language features in question.
Jan 31 2013
prev sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Friday, 1 February 2013 at 03:08:12 UTC, Zach the Mystic wrote:
 alias template theFuncIActuallyWant this;

 int theFuncIActuallyWant() { return 1; }

 ...in order to have it pass the right thing to the template 
 parameter? That's just a jury rigged syntax which might help 
 structs make more sense to the compiler when passed through 
 templates.
None of the alias this conversions are even looked at when you pass a variable to a templated parameter. The template simply conforms to whatever type the passed variable is. No conversions ever happen. That's just how templates work in D. I can't right off the bat say that it's impossible to design a language where templates perform conversions. But it's safe to say that it's not happening with this language. It would be a huge change.
Jan 31 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 03:28:05 UTC, TommiT wrote:
 On Friday, 1 February 2013 at 03:08:12 UTC, Zach the Mystic 
 wrote:
 alias template theFuncIActuallyWant this;

 int theFuncIActuallyWant() { return 1; }

 ...in order to have it pass the right thing to the template 
 parameter? That's just a jury rigged syntax which might help 
 structs make more sense to the compiler when passed through 
 templates.
None of the alias this conversions are even looked at when you pass a variable to a templated parameter. The template simply conforms to whatever type the passed variable is. No conversions ever happen. That's just how templates work in D. I can't right off the bat say that it's impossible to design a language where templates perform conversions. But it's safe to say that it's not happening with this language. It would be a huge change.
What I meant to suggest was an actual new feature which would allow one preferred argument to be passed to a template.
Jan 31 2013
parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 03:33:05 UTC, Zach the Mystic wrote:
 On Friday, 1 February 2013 at 03:28:05 UTC, TommiT wrote:
 On Friday, 1 February 2013 at 03:08:12 UTC, Zach the Mystic 
 wrote:
 alias template theFuncIActuallyWant this;

 int theFuncIActuallyWant() { return 1; }

 ...in order to have it pass the right thing to the template 
 parameter? That's just a jury rigged syntax which might help 
 structs make more sense to the compiler when passed through 
 templates.
None of the alias this conversions are even looked at when you pass a variable to a templated parameter. The template simply conforms to whatever type the passed variable is. No conversions ever happen. That's just how templates work in D. I can't right off the bat say that it's impossible to design a language where templates perform conversions. But it's safe to say that it's not happening with this language. It would be a huge change.
What I meant to suggest was an actual new feature which would allow one preferred argument to be passed to a template.
Frankly, it was your use of the word "insurmountable" which rubbed me the wrong way, but I reach the limits of my awareness at this point.
Jan 31 2013
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 Jan 2013 19:59:46 -0500, Zach the Mystic  
<reachBUTMINUSTHISzach googlymail.com> wrote:

 I think my suggestion goes far beyond what you suspect. It goes way  
 beyond mere getting and setting of variables. Here is basically how you  
 implement a basic int as a property, assuming my new syntax and language  
 adjustments. You need: 1) a struct to have the property in, which is  
 just a normal struct. 2) An actual integer which will be indirectly  
 accessed by using the properties. Let's call it "_n" and the property  
 "n". 3) a struct to hold all of the property functions which access _n.  
 THIS STRUCT CONTAINS NO DATA OF ITS OWN. 4) A bunch of methods  
 implementing all the operators you want. For int, that's quite a lot, so  
 I'll shorten it to a getter, a setter, and an adder. I'll even leave out  
 opGet and use an alias to what might as well be opGet. I'll give the  
 adder a little personality because what's the point of properties if  
 they don't do something different from a basic type?

 struct myStruct
 {
    int _n;
    n struct
    {
      int __mightAsWellBeOpGet() { return _n; }
      alias __mightAsWellBeOpGet this;

      int opAssign(int newN) { _n = newN; return _n; }
      int opBinary(string op) (int rhs)
      {
        static if (op == "+")
        {
          writeln("You sure are adding a funky int, my friend...");
          return _n + rhs;
        }
        else static assert(0, "Operator "~op~" not implemented");
      }
    }
 }

 This is not some kind of special property implementation. n is a struct.  
 It has no data and therefore is a very peculiar kind of struct. A struct  
 with no data needs only one instance, ever. Copying it is pointless.  
 Taking its address is pointless. Creating a new instance is pointless.  
 Passing it by ref is pointless. All operations which require more than  
 one instance are pointless, which is why it doesn't need a separately  
 defined type. The type and the instance can therefore use the same name,  
 n in this case.
No, the struct must have data. If it doesn't, how does it get back to the owner type? In other words, your n struct must have a pointer to the myStruct instance it intends to modify _n on. Unless, of course, you pass the pointer to myStruct as the 'this' reference. But then, this isn't a normal struct, and I'm really failing to see why we have to make this a struct at all.
 Note that n uses the new rule which allows it access to its parent's  
 scope, the same way it would in a nested function. The only pointer it  
 needs is the same pointer used for myStruct, since myStruct actually  
 stores some data.
FYI, nested structs in functions (the ones you want to use as a model) have an extra hidden reference pointer back to the stack frame data. That is how they can access the local variables of the function. This proposal looks way too complicated. I don't see how it's a win over the current state of affairs, or even the property implementation we expected to get but didn't. You need to solve the "owner pointer" problem before it's even viable. -Steve
Jan 31 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 04:33:05 UTC, Steven Schveighoffer 
wrote:
 On Thu, 31 Jan 2013 19:59:46 -0500, Zach the Mystic:
 This is not some kind of special property implementation. n is 
 a struct. It has no data and therefore is a very peculiar kind 
 of struct. A struct with no data needs only one instance, 
 ever. Copying it is pointless. Taking its address is 
 pointless. Creating a new instance is pointless. Passing it by 
 ref is pointless. All operations which require more than one 
 instance are pointless, which is why it doesn't need a 
 separately defined type. The type and the instance can 
 therefore use the same name, n in this case.
No, the struct must have data. If it doesn't, how does it get back to the owner type? In other words, your n struct must have a pointer to the myStruct instance it intends to modify _n on.
How does any function get hooked up with data? The compiler figures out what data is to be passed to which function. It's no different from how the compiler figures out how to pass data defined in one module to functions defined in a different module. Empty structs are just namespaces with powerful semantics. They have no pointers, unless they're nested in a struct with data, in which case they have the same pointer as any member function of that struct. struct A { int q = 23; void incrementQ() { ++q; } } How on earth could this function increment q when it's not even defined in the function?!?!? It must be a miracle. Oh, no wait, it needs a pointer to the struct in question. Duh. There's no difference with data-less structs inside regular structs. struct A { int q; incrementQ struct { void opCall() { ++q; } } } Where's the need for some hocus-pocus mystery pointer here? The empty struct has no data to worry about. Functions inside the empty struct get the same damn pointer as the other functions in struct A. But of course, you can't do this: struct B { int _q; q struct { int opUnary(string s)() if (s == "++") { writeln("You know, I just wanted to have a conversation while I was busy incrementing q"); ++_q; writeln("I did all sorts of stuff with the increment operator while I was at it"); return _q; } } } ...with normal function calls.
 Unless, of course, you pass the pointer to myStruct as the 
 'this' reference.
Ain't no "this" in an empty struct. Use "outer.this" instead.
But then, this isn't a normal struct, and
 I'm really failing to see why we have to make this a struct at 
 all.
Because it's already implemented, except for a few details, because it opens up possibilities for properties other languages could only dream of, and because it obviates the need for tags like property to provide far weaker functionality.
 Note that n uses the new rule which allows it access to its 
 parent's scope, the same way it would in a nested function. 
 The only pointer it needs is the same pointer used for 
 myStruct, since myStruct actually stores some data.
FYI, nested structs in functions (the ones you want to use as a model) have an extra hidden reference pointer back to the stack frame data. That is how they can access the local variables of the function.
Yeah, see, the problem is, if empty structs, which require no "this" pointer to themselves, are allowed access to their parent scope, it suggests that all structs should do the same. Now we have one good syntax for these things : "foo struct { ... }", which could be fun to use in other places too (where you want a single instance of a struct). But if these empty structs are fundamentally different from regular structs, it will force a situation where the Highlander syntax must be used only on these "special" structs, to make sure the compiler knows the difference. It's a problem, to be sure.
 This proposal looks way too complicated.  I don't see how it's 
 a win over the current state of affairs, or even the  property 
 implementation we expected to get but didn't.  You need to 
 solve the "owner pointer" problem before it's even viable.

 -Steve
You say it's complicated, but I ask you this: does any other proposal completely eliminate the so-called eye-sore " property" while also providing functionality with unknown potential which goes far beyond what people are used to? And the owner pointer problem is only a problem if we want to make the language complete and consistent with regard to normal non-static structs holding an outer struct pointer. I think having a use case for this type of struct would seal the deal, but as it is, I'm not sure.
Jan 31 2013
next sibling parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 06:52:32 UTC, Zach the Mystic wrote:
 FYI, nested structs in functions (the ones you want to use as 
 a model) have an extra hidden reference pointer back to the 
 stack frame data.  That is how they can access the local 
 variables of the function.
Yeah, see, the problem is, if empty structs, which require no "this" pointer to themselves, are allowed access to their parent scope, it suggests that all structs should do the same. Now we have one good syntax for these things : "foo struct { ... }", which could be fun to use in other places too (where you want a single instance of a struct). But if these empty structs are fundamentally different from regular structs, it will force a situation where the Highlander syntax must be used only on these "special" structs, to make sure the compiler knows the difference. It's a problem, to be sure.
What I mean is, that the annoying aspect of making struct-nested structs act like their function-nested struct counterparts is that the part which is most difficult to implement will actually be the part people use the least. The main need is for data-less struct-nested structs to have access to their parent's scope, but implementing struct-nested structs which actually hold data will be more annoying, but it will be necessary for language consistency. But I though of a rather crude temporary fix. Simply disallow non-static struct-nested structs which actually hold data of their own. With this error built-in, all programmers can now tag all of their struct-nested structs with "static" until their program compiles once more. Now the language is clean and ready for the rather easy addition of data-less nested structs, and the slightly trickier data-ful struct-nested structs to be implemented when the developers get the chance. All structs now will behave the same way, freeing up the Highlander syntax for use on *any* struct, data-less or data-ful.
Feb 01 2013
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 01 Feb 2013 01:52:29 -0500, Zach the Mystic  
<reachBUTMINUSTHISzach googlymail.com> wrote:

 On Friday, 1 February 2013 at 04:33:05 UTC, Steven Schveighoffer wrote:
 No, the struct must have data.  If it doesn't, how does it get back to  
 the owner type?  In other words, your n struct must have a pointer to  
 the myStruct instance it intends to modify _n on.
How does any function get hooked up with data? The compiler figures out what data is to be passed to which function. It's no different from how the compiler figures out how to pass data defined in one module to functions defined in a different module. Empty structs are just namespaces with powerful semantics. They have no pointers, unless they're nested in a struct with data, in which case they have the same pointer as any member function of that struct. struct A { int q = 23; void incrementQ() { ++q; } } How on earth could this function increment q when it's not even defined in the function?!?!? It must be a miracle. Oh, no wait, it needs a pointer to the struct in question. Duh.
No need to get snippy :) Especially when you are wrong. Try this: struct A { int q; struct B { void foo() {q++;} } } Won't compile. That's becuase foo is passed a reference to the A.B struct, not the A struct. If you want it to compile, B will *necessarily* have to have a pointer to A. If you want B's methods to be passed A's pointer, then this is not a struct. Plain and simple. It's just a namespace, the "just like any other struct" is meaningless, since it isn't. Now, try this: struct S {} pragma(msg, sizeof(S).stringof); // outputs 1 (empty structs must have some size). void foo() { int q; struct A { void foo() {q++;} } pragma(msg, sizeof(A).stringof); // outputs 4 (or 8 on 64-bit machines) } Why? Because the reason those "miracle" nested structs work is because they have a hidden context pointer. Even empty structs have size of 1 byte because they must have a 'this' pointer.
 There's no difference with data-less structs inside regular structs.

 struct A
 {
    int q;
    incrementQ struct
    {
      void opCall() { ++q; }
    }
 }

 Where's the need for some hocus-pocus mystery pointer here? The empty  
 struct has no data to worry about. Functions inside the empty struct get  
 the same damn pointer as the other functions in struct A.
Then this is not a normal struct, in fact it has nothing to do with a struct.
 But of course, you can't do this:

 struct B
 {
    int _q;
    q struct
    {
      int opUnary(string s)() if (s == "++")
      {
        writeln("You know, I just wanted to have a conversation while I  
 was busy incrementing q");
        ++_q;
        writeln("I did all sorts of stuff with the increment operator  
 while I was at it");
        return _q;
      }
    }
 }

 ...with normal function calls.
Certainly you can: struct B { int _q; property auto q() { static struct incrementer { int *_q; int opUnary(string s)() if (s == "++") { writeln("You know, I just wanted to have a conversation while I was busy incrementing q"); ++(*_q); writeln("I did all sorts of stuff with the increment operator while I was at it"); return *_q; } } return incrementer(&_q); } } Although, because of dumb rvalue/lvalue rules (apparently, incrementer is not an lvalue, so can't have ++ called on it), this doesn't actually compile... Through some finagling, I can get this to compile, but it's not usable with this compiler bug: import std.stdio; struct B { int _q; struct incrementer { int *_q; int opUnary(string s)() if (s == "++") { writeln("You know, I just wanted to have a conversation while I was busy incrementing q"); ++(*_q); writeln("I did all sorts of stuff with the increment operator while I was at it"); return *_q; } } private incrementer qinc; // needed to make incrementer an lvalue. property ref incrementer q() { qinc._q = &_q; return qinc; } } void main() { B b; assert(b._q == 0); ++b.q; // b.q++ doesn't work, another bug assert(b._q == 1); } it would be useful to be able to define all the operators. So that part of the plan has merit. I think you need to drop the struct moniker. This is not a struct. You do that, and I think your proposal is on more solid ground.
 Unless, of course, you pass the pointer to myStruct as the 'this'  
 reference.
Ain't no "this" in an empty struct. Use "outer.this" instead.
outer is the pointer I am referring to. It's not magic, it must come from somewhere. If the struct has no this pointer, it's not a struct. A data-less struct *STILL* has a this pointer.
 But then, this isn't a normal struct, and
 I'm really failing to see why we have to make this a struct at all.
Because it's already implemented, except for a few details, because it opens up possibilities for properties other languages could only dream of, and because it obviates the need for tags like property to provide far weaker functionality.
Hand waving doesn't solve the problems. The details are important to resolve. What it seems like you have done is hijacked the 'struct' keyword for a property. It isn't a struct, and it doesn't obviate the need for a tag.
 You say it's complicated, but I ask you this: does any other proposal  
 completely eliminate the so-called eye-sore " property" while also  
 providing functionality with unknown potential which goes far beyond  
 what people are used to? And the owner pointer problem is only a problem  
 if we want to make the language complete and consistent with regard to  
 normal non-static structs holding an outer struct pointer. I think  
 having a use case for this type of struct would seal the deal, but as it  
 is, I'm not sure.
What I mean by complicated is that it seems like a lot more work than it should be. If we want to define new syntax to define properties, let's do it in a way that is concise and to the point. I don't want to make properties look like structs, they are not structs. -Steve
Feb 01 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 15:29:38 UTC, Steven Schveighoffer 
wrote:
 On Fri, 01 Feb 2013 01:52:29 -0500, Zach the Mystic 
 <reachBUTMINUSTHISzach googlymail.com> wrote:

 On Friday, 1 February 2013 at 04:33:05 UTC, Steven 
 Schveighoffer wrote:
 No, the struct must have data.  If it doesn't, how does it 
 get back to the owner type?  In other words, your n struct 
 must have a pointer to the myStruct instance it intends to 
 modify _n on.
How does any function get hooked up with data? The compiler figures out what data is to be passed to which function. It's no different from how the compiler figures out how to pass data defined in one module to functions defined in a different module. Empty structs are just namespaces with powerful semantics. They have no pointers, unless they're nested in a struct with data, in which case they have the same pointer as any member function of that struct. struct A { int q = 23; void incrementQ() { ++q; } } How on earth could this function increment q when it's not even defined in the function?!?!? It must be a miracle. Oh, no wait, it needs a pointer to the struct in question. Duh.
No need to get snippy :) Especially when you are wrong. Try this: struct A { int q; struct B { void foo() {q++;} } } Won't compile. That's becuase foo is passed a reference to the A.B struct, not the A struct. If you want it to compile, B will *necessarily* have to have a pointer to A. If you want B's methods to be passed A's pointer, then this is not a struct. Plain and simple. It's just a namespace, the "just like any other struct" is meaningless, since it isn't. Now, try this: struct S {} pragma(msg, sizeof(S).stringof); // outputs 1 (empty structs must have some size). void foo() { int q; struct A { void foo() {q++;} } pragma(msg, sizeof(A).stringof); // outputs 4 (or 8 on 64-bit machines) } Why? Because the reason those "miracle" nested structs work is because they have a hidden context pointer. Even empty structs have size of 1 byte because they must have a 'this' pointer.
 There's no difference with data-less structs inside regular 
 structs.

 struct A
 {
   int q;
   incrementQ struct
   {
     void opCall() { ++q; }
   }
 }

 Where's the need for some hocus-pocus mystery pointer here? 
 The empty struct has no data to worry about. Functions inside 
 the empty struct get the same damn pointer as the other 
 functions in struct A.
Then this is not a normal struct, in fact it has nothing to do with a struct.
 But of course, you can't do this:

 struct B
 {
   int _q;
   q struct
   {
     int opUnary(string s)() if (s == "++")
     {
       writeln("You know, I just wanted to have a conversation 
 while I was busy incrementing q");
       ++_q;
       writeln("I did all sorts of stuff with the increment 
 operator while I was at it");
       return _q;
     }
   }
 }

 ...with normal function calls.
Certainly you can: struct B { int _q; property auto q() { static struct incrementer { int *_q; int opUnary(string s)() if (s == "++") { writeln("You know, I just wanted to have a conversation while I was busy incrementing q"); ++(*_q); writeln("I did all sorts of stuff with the increment operator while I was at it"); return *_q; } } return incrementer(&_q); } } Although, because of dumb rvalue/lvalue rules (apparently, incrementer is not an lvalue, so can't have ++ called on it), this doesn't actually compile... Through some finagling, I can get this to compile, but it's not usable with this compiler bug: import std.stdio; struct B { int _q; struct incrementer { int *_q; int opUnary(string s)() if (s == "++") { writeln("You know, I just wanted to have a conversation while I was busy incrementing q"); ++(*_q); writeln("I did all sorts of stuff with the increment operator while I was at it"); return *_q; } } private incrementer qinc; // needed to make incrementer an lvalue. property ref incrementer q() { qinc._q = &_q; return qinc; } } void main() { B b; assert(b._q == 0); ++b.q; // b.q++ doesn't work, another bug assert(b._q == 1); } But I think actually, if we are going to define get and set in operators. So that part of the plan has merit. I think you need to drop the struct moniker. This is not a struct. You do that, and I think your proposal is on more solid ground.
 Unless, of course, you pass the pointer to myStruct as the 
 'this' reference.
Ain't no "this" in an empty struct. Use "outer.this" instead.
outer is the pointer I am referring to. It's not magic, it must come from somewhere. If the struct has no this pointer, it's not a struct. A data-less struct *STILL* has a this pointer.
 But then, this isn't a normal struct, and
 I'm really failing to see why we have to make this a struct 
 at all.
Because it's already implemented, except for a few details, because it opens up possibilities for properties other languages could only dream of, and because it obviates the need for tags like property to provide far weaker functionality.
Hand waving doesn't solve the problems. The details are important to resolve. What it seems like you have done is hijacked the 'struct' keyword for a property. It isn't a struct, and it doesn't obviate the need for a tag.
 You say it's complicated, but I ask you this: does any other 
 proposal completely eliminate the so-called eye-sore 
 " property" while also providing functionality with unknown 
 potential which goes far beyond what people are used to? And 
 the owner pointer problem is only a problem if we want to make 
 the language complete and consistent with regard to normal 
 non-static structs holding an outer struct pointer. I think 
 having a use case for this type of struct would seal the deal, 
 but as it is, I'm not sure.
What I mean by complicated is that it seems like a lot more work than it should be. If we want to define new syntax to define properties, let's do it in a way that is concise and to the point. I don't want to make properties look like structs, they are not structs. -Steve
Okay, so you're drawing the line where you think it ends. I want to point out again that my idea requires the language change which allows struct-nested structs access to their parent's scope. The temporary fix is to make it an error to have a non-static struct-nested struct which actually holds data. All programmers can quickly see what's wrong with their code, because they will have to add "static" to data-containing struct-nested structs to get them to compile. As I said above, this is arguably the behavior which should have been implemented in the first place - I'm actually making the language *more* consistent by insisting on this. And there is simply no need for a data-less struct to allow a "this" pointer. There will never be any need to know the address of a data-less struct. Any use of it will simply give: "Error: a struct with no data may not contain a 'this' pointer". And any use requiring taking its address is statically disallowed at compile time. This is not a hard feature to implement.
Feb 01 2013
parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-02-01 15:54:14 +0000, "Zach the Mystic" 
<reachBUTMINUSTHISzach gOOGLYmail.com> said:

 And there is simply no need for a data-less struct to allow a "this" 
 pointer. There will never be any need to know the address of a 
 data-less struct. Any use of it will simply give: "Error: a struct with 
 no data may not contain a 'this' pointer". And any use requiring taking 
 its address is statically disallowed at compile time. This is not a 
 hard feature to implement.
I think what Steven is saying is that you're distorting the concept of a struct beyond recognition. What you really want/need is just some kind of namespace inside the outer scope. Note that D almost has what you want already if you do it through a template mixin: http://www.digitalmars.com/d/archives/digitalmars/D/properties_using_template_mixins_and_alias_this_87952.html The only thing missing is opGet or an equivalent, and probably a more straightforward syntax. And perhaps someone should check whether the functions can be made virtual too (another requirement that doesn't really belong in a struct). -- Michel Fortin michel.fortin michelf.ca http://michelf.ca/
Feb 01 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 16:24:53 UTC, Michel Fortin wrote:
 On 2013-02-01 15:54:14 +0000, "Zach the Mystic" 
 <reachBUTMINUSTHISzach gOOGLYmail.com> said:

 And there is simply no need for a data-less struct to allow a 
 "this" pointer. There will never be any need to know the 
 address of a data-less struct. Any use of it will simply give: 
 "Error: a struct with no data may not contain a 'this' 
 pointer". And any use requiring taking its address is 
 statically disallowed at compile time. This is not a hard 
 feature to implement.
I think what Steven is saying is that you're distorting the concept of a struct beyond recognition.
Yes, this is exactly what I am trying to do, because it's yet another totally badass thing to do. But I'm simply adding it to D's list of such things - CTFE, enums as manifest constants(?), the reuse of keyword static all over the place, strings as immutables. Am I wrong?
 What you really want/need is just some kind of namespace inside 
 the outer scope.

 Note that D almost has what you want already if you do it 
 through a template mixin:
 http://www.digitalmars.com/d/archives/digitalmars/D/properties_using_template_mixins_and_alias_this_87952.html

 The only thing missing is opGet or an equivalent, and probably 
 a more straightforward syntax. And perhaps someone should check 
 whether the functions can be made virtual too (another 
 requirement that doesn't really belong in a struct).
That's why it's so weird to see people suggesting so many ideas for property, when this functionality is basically already built into the language. My suggestion already works at module level. Look: import std.traits; Front front; struct Front { ref T opCall(T)(T[] a) if (!isNarrowString!(T[]) && !is(T[] == void[])) { assert(a.length, "Attempting to fetch the front of an empty array of " ~ typeof(a[0]).stringof); return a[0]; } } int main(string[] args) { assert([1,2,3].front == 1); return 0; } It needs three improvements: 1) allow it to work everywhere, not just module level 2) make it look good with a new friendly syntax, which by the way I'm more proud of than any other suggestions I've made here 3) optimize away the unnecessary hidden pointers
Feb 01 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 01 Feb 2013 12:27:58 -0500, Zach the Mystic  
<reachBUTMINUSTHISzach googlymail.com> wrote:

 On Friday, 1 February 2013 at 16:24:53 UTC, Michel Fortin wrote:
 I think what Steven is saying is that you're distorting the concept of  
 a struct beyond recognition.
Yes, this is exactly what I am trying to do, because it's yet another totally badass thing to do. But I'm simply adding it to D's list of such things - CTFE, enums as manifest constants(?), the reuse of keyword static all over the place, strings as immutables. Am I wrong?
I think you are wrong in how you assume a struct works, but not in your attempt to implement properties. Struct is just not a key to this formula. Note that many (including myself) consider the overloading of static to be a *detriment*.
 What you really want/need is just some kind of namespace inside the  
 outer scope.

 Note that D almost has what you want already if you do it through a  
 template mixin:
 http://www.digitalmars.com/d/archives/digitalmars/D/properties_using_template_mixins_and_alias_this_87952.html

 The only thing missing is opGet or an equivalent, and probably a more  
 straightforward syntax. And perhaps someone should check whether the  
 functions can be made virtual too (another requirement that doesn't  
 really belong in a struct).
That's why it's so weird to see people suggesting so many ideas for property, when this functionality is basically already built into the language. My suggestion already works at module level. Look: import std.traits; Front front; struct Front { ref T opCall(T)(T[] a) if (!isNarrowString!(T[]) && !is(T[] == void[])) { assert(a.length, "Attempting to fetch the front of an empty array of " ~ typeof(a[0]).stringof); return a[0]; } } int main(string[] args) { assert([1,2,3].front == 1); return 0; } It needs three improvements: 1) allow it to work everywhere, not just module level 2) make it look good with a new friendly syntax, which by the way I'm more proud of than any other suggestions I've made here 3) optimize away the unnecessary hidden pointers
You are applying struct where none is needed. The current front accomplishes what you have shown except it does not require an actual struct instance (as your code does), and it's far easier to understand and implement than your method. What you are trying to do is establish a *namespace* in which to declare operator overloads. The whole idea that it has to be a struct is incorrect, it does not need a "struct" wrapper. I think you are not understanding how a struct is implemented, and how it's methods are implemented. A struct function without a 'this' reference is a static struct function. Nothing different from a standard function, except it is in the struct *namespace*. I think this is what you really are after, a separate *namespace*. I think *that* idea has merit, and should be examined. Drop the struct, and you are back to the table. -Steve
Feb 01 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 18:34:01 UTC, Steven Schveighoffer 
wrote:
 I think you are wrong in how you assume a struct works, but not 
 in your attempt to implement properties.  Struct is just not a 
 key to this formula.
I disagree. It is absolutely the fundamental key to this formula.
 Note that many (including myself) consider the overloading of 
 static to be a *detriment*.
I guess there's certainly a matter of taste involved here. Had you suggested another keyword, or what had your preferred suggested syntax looked like?
 You are applying struct where none is needed.

 The current front accomplishes what you have shown except it 
 does not require an actual struct instance (as your code does), 
 and it's far easier to understand and implement than your 
 method.

 What you are trying to do is establish a *namespace* in which 
 to declare operator overloads.  The whole idea that it has to 
 be a struct is incorrect, it does not need a "struct" wrapper.

 I think you are not understanding how a struct is implemented, 
 and how it's methods are implemented.  A struct function 
 without a 'this' reference is a static struct function.  
 Nothing different from a standard function, except it is in the 
 struct *namespace*.  I think this is what you really are after, 
 a separate *namespace*.

 I think *that* idea has merit, and should be examined.  Drop 
 the struct, and you are back to the table.

 -Steve
I'm sorry we couldn't find common ground here. I can imagine two camps developing, one with your ideas and one with mine. As far as a static struct function, how could it get the pointer to its enclosing struct, which it needs in order operate on the enclosing struct's data?
Feb 01 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 01 Feb 2013 14:17:00 -0500, Zach the Mystic  
<reachBUTMINUSTHISzach googlymail.com> wrote:

 On Friday, 1 February 2013 at 18:34:01 UTC, Steven Schveighoffer wrote:
 I think you are wrong in how you assume a struct works, but not in your  
 attempt to implement properties.  Struct is just not a key to this  
 formula.
I disagree. It is absolutely the fundamental key to this formula.
Well, we can disagree, but you still haven't explained why it's fundamental. Other languages have implemented properties just fine without having to specify that they are structs or aggregate types. Until you come up with a compelling reason for structs, I'll stand by my position.
 Note that many (including myself) consider the overloading of static to  
 be a *detriment*.
I guess there's certainly a matter of taste involved here. Had you suggested another keyword, or what had your preferred suggested syntax looked like?
property. It's already there, already used for properties. property foo { int get(); // or opGet void set(int val); // or opSet opBinary(...) // etc. }
 I'm sorry we couldn't find common ground here. I can imagine two camps  
 developing, one with your ideas and one with mine. As far as a static  
 struct function, how could it get the pointer to its enclosing struct,  
 which it needs in order operate on the enclosing struct's data?
There is NO difference between a static struct function and a normal module-level function, EXCEPT in the namespace. How could it get the pointer to its enclosing struct? It can't. Because a struct TYPE doesn't HAVE an enclosing struct. It could have an enclosing struct TYPE, but that's it. In order to have an instance pointer, it needs to have an instance, and you need to have a non-static struct function. Now, you are proposing that we have these special structs (nested structs) must be labeled static, but are not actually static (their methods require a context pointer), who can never have any fields, and whose methods accept a this pointer is not the pointer to the struct instance, but the instance of the containing type (be it class or struct) they reside in. To say this is "just another struct" is an extremely large stretch. I don't want to come across as mean or condescending, but what you have described could never be considered a struct. Period. If you insist that struct is to be used, you will be bashing your head against a brick wall forever here. Drop the idea that it must be a struct, and you may gain some traction. I'm not saying this because it's my opinion, I'm saying this to prevent you from wasting any more time. I don't really want to waste any more of my time either, if struct is what you insist on, then I will respectfully bow out of the conversation. -Steve
Feb 01 2013
next sibling parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 19:59:12 UTC, Steven Schveighoffer 
wrote:
 On Fri, 01 Feb 2013 14:17:00 -0500, Zach the Mystic 
 <reachBUTMINUSTHISzach googlymail.com> wrote:

 On Friday, 1 February 2013 at 18:34:01 UTC, Steven 
 Schveighoffer wrote:
 I think you are wrong in how you assume a struct works, but 
 not in your attempt to implement properties.  Struct is just 
 not a key to this formula.
I disagree. It is absolutely the fundamental key to this formula.
Well, we can disagree, but you still haven't explained why it's fundamental. Other languages have implemented properties just fine without having to specify that they are structs or aggregate types. Until you come up with a compelling reason for structs, I'll stand by my position.
Okay, fair.
 Note that many (including myself) consider the overloading of 
 static to be a *detriment*.
I guess there's certainly a matter of taste involved here. Had you suggested another keyword, or what had your preferred suggested syntax looked like?
property. It's already there, already used for properties. property foo { int get(); // or opGet void set(int val); // or opSet opBinary(...) // etc. }
I'm totally sorry. I had meant that some time ago, static was not used so widely in D, and I'll concede it's a bit bulky, for what it does. I wondered what you wanted then that would look or feel better than having "static" plastered all over the place. Having said that, I admit your syntax for property is pretty good. I think it does the job. Now I have to demonstrate why structs would do the job better.
 There is NO difference between a static struct function and a 
 normal module-level function, EXCEPT in the namespace.  How 
 could it get the pointer to its enclosing struct?  It can't.  
 Because a struct TYPE doesn't HAVE an enclosing struct.  It 
 could have an enclosing struct TYPE, but that's it.  In order 
 to have an instance pointer, it needs to have an instance, and 
 you need to have a non-static struct function.

 Now, you are proposing that we have these special structs 
 (nested structs) must be labeled static, but are not actually 
 static (their methods require a context pointer), who can never 
 have any fields, and whose methods accept a this pointer is not 
 the pointer to the struct instance, but the instance of the 
 containing type (be it class or struct) they reside in.  To say 
 this is "just another struct" is an extremely large stretch.
Okay, I can see the confusion... what need to become static are all *current* nested structs. These new special structs are not labelled static at all, precisely because of how important it is for them to define functions which hold pointers to instances of their parent type, no different at all from how it currently works with structs nested in functions. It's a code breakage I'm talking about here. And thank goodness it's one that's relatively easily handled. All normal structs will now define functions which accept a hidden pointer to their enclosing scope. There will be a small performance penalty, just like when a struct inside a function is not marked static, for programmers who fail to mark their nested structs static when possible. My other posts here and a comment by Era Scarecrow on the other thread are starting to address how this transition might be mitigated: http://forum.dlang.org/thread/kdukid$stg$1 digitalmars.com?page=13
 I don't want to come across as mean or condescending, but what 
 you have described could never be considered a struct.  Period.
  If you insist that struct is to be used, you will be bashing 
 your head against a brick wall forever here.  Drop the idea 
 that it must be a struct, and you may gain some traction.  I'm 
 not saying this because it's my opinion, I'm saying this to 
 prevent you from wasting any more time.

 I don't really want to waste any more of my time either, if 
 struct is what you insist on, then I will respectfully bow out 
 of the conversation.

 -Steve
Maybe we both need some time to think about what has already been said.
Feb 01 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/01/2013 08:59 PM, Steven Schveighoffer wrote:
 ...
 Note that many (including myself) consider the overloading of static to be a
*detriment*.
 ...
The modifier actually has a consistent meaning. Is it about overloading as in static if and static assert?
 ...

 Now, you are proposing that we have these special structs (nested
 structs) must be labeled static, but are not actually static (their
 methods require a context pointer), ...
This is not what static on an aggregate declaration means in D. A static struct is a struct that does not contain a context pointer as an implicit field. All member structs and aggregate members of structs are implicitly static.
Feb 01 2013
prev sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 19:59:12 UTC, Steven Schveighoffer 
wrote:
 Well, we can disagree, but you still haven't explained why it's 
 fundamental.  Other languages have implemented properties just 
 fine without having to specify that they are structs or 
 aggregate types.  Until you come up with a compelling reason 
 for structs, I'll stand by my position.
Do you mind if I put my arguments in a new thread?
Feb 04 2013
parent "Rob T" <alanb ucora.com> writes:
On Monday, 4 February 2013 at 22:46:36 UTC, Zach the Mystic wrote:
 On Friday, 1 February 2013 at 19:59:12 UTC, Steven 
 Schveighoffer wrote:
 Well, we can disagree, but you still haven't explained why 
 it's fundamental.  Other languages have implemented properties 
 just fine without having to specify that they are structs or 
 aggregate types.  Until you come up with a compelling reason 
 for structs, I'll stand by my position.
Do you mind if I put my arguments in a new thread?
FYI, I got some feedback from Andrei today in the DIP23 thread ... -------------------- 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 -------------------- See http://forum.dlang.org/post/kepcjq$5fa$1 digitalmars.com --rt
Feb 04 2013
prev sibling parent reply "Rob T" <alanb ucora.com> writes:
I've had to step away from this for a while, but I want to say 
that I don't see a problem with the data-less "struct" property 
idea at all, although calling it a struct is perhaps causing some 
confusion because real structs tend to host internal data of 
their own rather than reference it from the outside.

The proposed new type of property does not have to host its own 
internal data, and its member functions can be called just like 
the hosts member functions.

The proposed struct property is really something like a namespace 
for wrapping data and related functions. It is not a regular 
struct at all, but it does share some of the features of a 
struct. It like an improved C++ namespace with smarts.

Syntactically, we can allow the property to contain its own data 
internally, but the data will really belong to the hosted 
structure (class, struct, or module level). Nothing really new 
needs to be implemented because there's no special need for 
storing a "this" pointer, and functions get called in the same 
way as before. The "this" is the host pointer. We can still refer 
to an inner and an outter this pointer, but that's really an 
alias for either the hosts "this" (outter) or the property 
namespace (inner), both use the same this pointer.

If we view the property more like a namespace, then certain 
things become clear, for example the property by itself is not a 
movable structure, it's permanently attached to the host class, 
struct, or module. We can only take addresses of addressable 
items if they are visible.

No, the struct-property will not behave exactly like a variable, 
and I think that idea is a dead end anyway because it's far too 
complicated to implement and has questionable value. I agree with 
Walter, it's needs to be put down so we can move on and come up 
with a better idea that can work and is really useful.

I may intuitively feel this is a great idea, but we will need a 
few compelling  use cases that solve real world problems to make 
a case for it.

--rt
Feb 01 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 17:23:45 UTC, Rob T wrote:
 I've had to step away from this for a while, but I want to say 
 that I don't see a problem with the data-less "struct" property 
 idea at all, although calling it a struct is perhaps causing 
 some confusion because real structs tend to host internal data 
 of their own rather than reference it from the outside.
Hey, thanks for coming back.
 The proposed new type of property does not have to host its own 
 internal data, and its member functions can be called just like 
 the hosts member functions.

 The proposed struct property is really something like a 
 namespace for wrapping data and related functions. It is not a 
 regular struct at all, but it does share some of the features 
 of a struct. It like an improved C++ namespace with smarts.

 Syntactically, we can allow the property to contain its own 
 data internally, but the data will really belong to the hosted 
 structure (class, struct, or module level).
I don't like this because structs don't already work that way. All structs can work in exactly the same way. I'm pretty sure there's no need to treat these specially... except under the hood, where compiler optimizes away the unnecessary pointers in the case of data-free structs.
 Nothing really new needs to be implemented because there's no 
 special need for storing a "this" pointer, and functions get 
 called in the same way as before. The "this" is the host 
 pointer. We can still refer to an inner and an outter this 
 pointer, but that's really an alias for either the hosts "this" 
 (outter) or the property namespace (inner), both use the same 
 this pointer.
The problem with overriding "this" is if you later add data to the struct, it will break any code that already uses "this". "outer" doesn't have this problem at all, and is arguably clearer. Therefore, I think "this" should simply be a compile-time error with a data-free struct.
 If we view the property more like a namespace, then certain 
 things become clear, for example the property by itself is not 
 a movable structure, it's permanently attached to the host 
 class, struct, or module. We can only take addresses of 
 addressable items if they are visible.

 No, the struct-property will not behave exactly like a 
 variable, and I think that idea is a dead end anyway because 
 it's far too complicated to implement and has questionable 
 value. I agree with Walter, it's needs to be put down so we can 
 move on and come up with a better idea that can work and is 
 really useful.
I don't know, Rob T... Walter's recent article on half-floats shows that you can get a struct instance to look pretty darn close to a variable. Is there anything a variable can do that half-floats can't do? Because if not, we're in the money, dude. This does exactly the same thing, just with data stored outside the struct itself.
 I may intuitively feel this is a great idea, but we will need a 
 few compelling  use cases that solve real world problems to 
 make a case for it.

 --rt
Yes, but on the other hand, if you provide all the functionality previously requested, plus a whole lot more, a compelling use case becomes a lot less important. Undiscovered country.
Feb 01 2013
parent reply "Rob T" <alanb ucora.com> writes:
On Friday, 1 February 2013 at 17:43:54 UTC, Zach the Mystic wrote:
[...]
 Syntactically, we can allow the property to contain its own 
 data internally, but the data will really belong to the hosted 
 structure (class, struct, or module level).
I don't like this because structs don't already work that way. All structs can work in exactly the same way. I'm pretty sure there's no need to treat these specially... except under the hood, where compiler optimizes away the unnecessary pointers in the case of data-free structs.
It's one thing to implement a struct, and another thing to implement nested structs that can refer to the host instance. I know some people want nested structs that can work in that way, but implementation is problematic because when the host struct is moved, then the nested struct has to move along with it and this one reason why we don't have them. I am proposing that we avoid the nesting problem by storing all enclosed data outside in the host instance, but this means that the concept is more like a namespace than a real struct, i.e., it is not movable and cannot be accessed in isolation from the host.
 Nothing really new needs to be implemented because there's no 
 special need for storing a "this" pointer, and functions get 
 called in the same way as before. The "this" is the host 
 pointer. We can still refer to an inner and an outter this 
 pointer, but that's really an alias for either the hosts 
 "this" (outter) or the property namespace (inner), both use 
 the same this pointer.
The problem with overriding "this" is if you later add data to the struct, it will break any code that already uses "this". "outer" doesn't have this problem at all, and is arguably clearer. Therefore, I think "this" should simply be a compile-time error with a data-free struct.
The idea here is that we have a property implementation that behaves like a namespace but also has some of the features that structs have. We should not call this thing a struct because it is not a true struct, it's something else entirely, not a namespace and not a struct, but it shares some features with both. If you add data to the namespace-struct, the data is not stored inside the namespace, it only appears that way, it's instead stored with the hosting object instance, be it struct, class, or module, so data storage is like a namespace. The "inner" simply refers to the "this" pointer of the host instance, but limited to the data that was declared inside the namespace, the outter pointer refers to the "this" of the host instance as well, but limited to the hosts data instance only. For modules I don't think there's a this pointer, but that's an implementation detail that can be resolved.
 No, the struct-property will not behave exactly like a 
 variable, and I think that idea is a dead end anyway because 
 it's far too complicated to implement and has questionable 
 value. I agree with Walter, it's needs to be put down so we 
 can move on and come up with a better idea that can work and 
 is really useful.
I don't know, Rob T... Walter's recent article on half-floats shows that you can get a struct instance to look pretty darn close to a variable. Is there anything a variable can do that half-floats can't do? Because if not, we're in the money, dude. This does exactly the same thing, just with data stored outside the struct itself.
The Half-Float implementation is not a nested structure, and trying to implement nested structs is where all of the major difficulties come from.
 I may intuitively feel this is a great idea, but we will need 
 a few compelling  use cases that solve real world problems to 
 make a case for it.

 --rt
Yes, but on the other hand, if you provide all the functionality previously requested, plus a whole lot more, a compelling use case becomes a lot less important. Undiscovered country.
I think we can easily replace property already with the namespace proposal, however it will not be the full variable emulation that some people had wanted. I don't think full variable emulation can be done anyway and I've seen admissions that it cannot be done by some of the people who want to see full variable emulation. What we can get however is a much better implementation of the property concept through a new gadget that works like a namepsace with some of the nice features seen with structs. I doubt we'll ever see true nested structs that can reference data in a host structs instance and contain it's own data because it introduces a pointer sync problem when the structs are moved around. At this stage in the discussion, I believe that Steven Schveighoffer is correct that we'll get more traction if we drop the nest struct idea and focus instead on implementing a D version of the C++ namespace, with the improvements that allows things like properties to be implemented. If we can show that there are other uses for the idea, then it adds a lot more credibility to the idea because as it stands, we can get properties right now, but they suck (IMHO anyway). If the proposal is only a marginal improvement over what we have now, then it may not be seen as worth implementing. --rt
Feb 01 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 1 February 2013 at 21:33:31 UTC, Rob T wrote:
 It's one thing to implement a struct, and another thing to 
 implement nested structs that can refer to the host instance. I 
 know some people want nested structs that can work in that way, 
 but implementation is problematic because when the host struct 
 is moved, then the nested struct has to move along with it and 
 this one reason why we don't have them.
I am not proposing this and I don't think it's actually necessary. My nested struct is just a tried-and-true struct. So what's the difference? How does it still succeed? Not because it contains any special data or hidden pointers unto itself. Rather, because its *functions* are written to *accept hidden pointers*. That way they can operate on whatever instance of their parent's type gets sent to them. They could be optimized, in theory, to only accept pointers to instances they actually worked on. For example, if a nested member function did nothing but set an integer defined in a struct three nests up, it only need take an instance of that struct, but that's an advanced optimization, not necessary for a basic implementation which would simply pass three pointers to every three-deep nested struct member function. If you want an example, just ask.
Feb 01 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Saturday, 2 February 2013 at 03:14:30 UTC, Zach the Mystic 
wrote:
 On Friday, 1 February 2013 at 21:33:31 UTC, Rob T wrote:
 It's one thing to implement a struct, and another thing to 
 implement nested structs that can refer to the host instance. 
 I know some people want nested structs that can work in that 
 way, but implementation is problematic because when the host 
 struct is moved, then the nested struct has to move along with 
 it and this one reason why we don't have them.
I am not proposing this and I don't think it's actually necessary. My nested struct is just a tried-and-true struct. So what's the difference? How does it still succeed? Not because it contains any special data or hidden pointers unto itself. Rather, because its *functions* are written to *accept hidden pointers*. That way they can operate on whatever instance of their parent's type gets sent to them. They could be optimized, in theory, to only accept pointers to instances they actually worked on. For example, if a nested member function did nothing but set an integer defined in a struct three nests up, it only need take an instance of that struct, but that's an advanced optimization, not necessary for a basic implementation which would simply pass three pointers to every three-deep nested struct member function. If you want an example, just ask.
I mean a code example. But since I'm already here: struct A { int _a = 1; B b; struct B { int _b = 1; C c; struct C { int_c = 1; int myMemberFunction() { return _a + _b + _c; } } } } How does myMemberFunction know about _a and _b? Because its implementation is actually: int myMemberFunction(ref A __a, ref A.B __b, ref A.B.C __c) { return __a._a + __b._b + __c._c; } I do find it frustrating that his kind of thing is necessary to get full compatibility between structs and properties, which would be so elegant. Usage would be: A a; assert(a.b.c.myMemberFunction() == 3); ...which is secretly translated to this: assert(A.B.C.myMemberFunction(a, a.b, a.b.c) == 3);
Feb 01 2013
next sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 2 February 2013 at 03:50:49 UTC, Zach the Mystic 
wrote:
 assert(A.B.C.myMemberFunction(a, a.b, a.b.c) == 3);
That wouldn't compile, so you must mean: assert(a.b.c.myMemberFunction(a, a.b, a.b.c) == 3); What do you suppose would happen if I wrote the following? struct A { int _a = 1; B b; struct B { int _b = 1; C c; struct C { int _c = 1; int myMemberFunction() { return _a + _b + _c; } } static int otherFunction() { C cc; return cc.myMemberFunction(); } } } void main() { int i = A.B.otherFunction(); }
Feb 01 2013
next sibling parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 2 February 2013 at 06:04:01 UTC, TommiT wrote:
 What do you suppose would happen if I wrote the following?

 struct A
 {
<snip>
     static int otherFunction()
     {
       C cc;
       return cc.myMemberFunction();
     }
It would refuse to compile as a static function can't point to an instance/parent. I'm convinced you should not be able to return (or create an instance of) a nested struct outside of it's level of control or ability to reference properly. Had it not been static on the other hand... int otherFunction() cc has the same level as c, so the return would be equal to: _a + _b + cc._c
Feb 01 2013
next sibling parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Saturday, 2 February 2013 at 06:28:47 UTC, Era Scarecrow wrote:
  It would refuse to compile as a static function can't point to 
 an instance/parent. I'm convinced you should not be able to 
 return (or create an instance of) a nested struct outside of 
 it's level of control or ability to reference properly.
Does my suggested way of doing it not do this?
Feb 02 2013
prev sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Saturday, 2 February 2013 at 06:28:47 UTC, Era Scarecrow wrote:
 On Saturday, 2 February 2013 at 06:04:01 UTC, TommiT wrote:
 What do you suppose would happen if I wrote the following?

 struct A
 {
<snip>
    static int otherFunction()
    {
      C cc;
      return cc.myMemberFunction();
    }
It would refuse to compile as a static function can't point to an instance/parent. I'm convinced you should not be able to return (or create an instance of) a nested struct outside of it's level of control or ability to reference properly. Had it not been static on the other hand... int otherFunction() cc has the same level as c, so the return would be equal to: _a + _b + cc._c
... well, this function requires being called with instances of A, B, and C, so I believe it would error on that account. The only way to call this deeply nested thing would be with an instance of A, which makes sense, since it operates on a variable contained in A. It would have to look like: A a; int z = a.b.c.myMemberFunction(); ... to work, I believe.
Feb 02 2013
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 2 February 2013 at 18:03:32 UTC, Zach the Mystic 
wrote:
 On Saturday, 2 February 2013 at 06:28:47 UTC, Era Scarecrow
 It would refuse to compile as a static function can't point to 
 an instance/parent. I'm convinced you should not be able to 
 return (or create an instance of) a nested struct outside of 
 it's level of control or ability to reference properly.

 Had it not been static on the other hand...

            int otherFunction()

 cc has the same level as c, so the return would be equal to: 
 _a + _b + cc._c
... well, this function requires being called with instances of A, B, and C, so I believe it would error on that account. The only way to call this deeply nested thing would be with an instance of A, which makes sense, since it operates on a variable contained in A. It would have to look like: A a; int z = a.b.c.myMemberFunction(); ... to work, I believe.
Yes, it should be callable that way since it knows where a is at. However I would think a nested struct is more a implementation detail. This brings back training when I was on a database/web development. There were 4 tiers, the DB, the Query level (with all the queries), Logic level, then the GUI level. Now something in this was that each level would be separate and not know about the other. When you think about it, it makes sense since you can swap out one for another. But then I began to notice code that broke that very easily. The GUI level would be doing stuff like: //posted twice, once for html formatting &lt;b&gt;Price: $&lt;?db.getPrices.query(&quot;select price from priceTable where x=x&quot;)?&gt;&lt;/b&gt; <b>Price: $<?db.getPrices.query("select price from priceTable where x=x")?></b> Not a very large example, however it ended up that the gui was getting into specifics of variables and function calls in other levels that it shouldn't have known about. In short, nested structs would only be accessible (and passable) inside the struct that made it. Meaning that most likely the methods that work with it, and the struct itself should be private.
Feb 02 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Saturday, 2 February 2013 at 20:30:26 UTC, Era Scarecrow wrote:
 On Saturday, 2 February 2013 at 18:03:32 UTC, Zach the Mystic 
 wrote:
 On Saturday, 2 February 2013 at 06:28:47 UTC, Era Scarecrow
 It would refuse to compile as a static function can't point 
 to an instance/parent. I'm convinced you should not be able 
 to return (or create an instance of) a nested struct outside 
 of it's level of control or ability to reference properly.

 Had it not been static on the other hand...

           int otherFunction()

 cc has the same level as c, so the return would be equal to: 
 _a + _b + cc._c
... well, this function requires being called with instances of A, B, and C, so I believe it would error on that account. The only way to call this deeply nested thing would be with an instance of A, which makes sense, since it operates on a variable contained in A. It would have to look like: A a; int z = a.b.c.myMemberFunction(); ... to work, I believe.
Yes, it should be callable that way since it knows where a is at. However I would think a nested struct is more a implementation detail.
I think this belittles just how important that implementation detail really is. Without a good design, the thing could be prohibitively difficult to implement.
  This brings back training when I was on a database/web 
 development. There were 4 tiers, the DB, the Query level (with 
 all the queries), Logic level, then the GUI level.

  Now something in this was that each level would be separate 
 and not know about the other. When you think about it, it makes 
 sense since you can swap out one for another. But then I began 
 to notice code that broke that very easily. The GUI level would 
 be doing stuff like:

   //posted twice, once for html formatting
   &lt;b&gt;Price: $&lt;?db.getPrices.query(&quot;select price 
 from priceTable where x=x&quot;)?&gt;&lt;/b&gt;

   <b>Price: $<?db.getPrices.query("select price from priceTable 
 where x=x")?></b>

  Not a very large example, however it ended up that the gui was 
 getting into specifics of variables and function calls in other 
 levels that it shouldn't have known about.
From what I understand generally, good encapsulation is a difficult design problem. I don't think you're alone.
  In short, nested structs would only be accessible (and 
 passable) inside the struct that made it. Meaning that most 
 likely the methods that work with it, and the struct itself 
 should be private.
Well, if you want access to a struct from outside, save yourself the time and put it outside to begin with. A nested struct of course is directly related to the entity it finds itself in. My pet metaphor is struct Dog containing struct Tail. It would definitely be illogical to put the Tail outside the Dog. You might as well use the built-in functionality for tagging whatever you want private or public, though. Consider this: software design doesn't end at language design. There's only so much a language can do to encourage good design before it starts to feel like it's strong-arming you into certain arbitrary ways of doing things. Doing this too much is actually *bad* language design.
Feb 02 2013
next sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Sunday, 3 February 2013 at 02:55:44 UTC, Zach the Mystic wrote:
 Well, if you want access to a struct from outside, save 
 yourself the time and put it outside to begin with. A nested 
 struct of course is directly related to the entity it finds 
 itself in. My pet metaphor is struct Dog containing struct 
 Tail. It would definitely be illogical to put the Tail outside 
 the Dog.
If Tail is an autonomous struct/class, then it totally makes sense to put the definition of Tail outside of dog. This enables you to perhaps use the same Tail in Wolf's and Hyeena's definitions. If, on the other hand, Tail is not an autonomous type, but rather, needs to able to wag the dog, then Tail is really more like a separate logical section within Dog's definition, i.e. a namespace within Dog.
Feb 02 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Sunday, 3 February 2013 at 03:15:57 UTC, TommiT wrote:
 On Sunday, 3 February 2013 at 02:55:44 UTC, Zach the Mystic 
 wrote:
 Well, if you want access to a struct from outside, save 
 yourself the time and put it outside to begin with. A nested 
 struct of course is directly related to the entity it finds 
 itself in. My pet metaphor is struct Dog containing struct 
 Tail. It would definitely be illogical to put the Tail outside 
 the Dog.
If Tail is an autonomous struct/class, then it totally makes sense to put the definition of Tail outside of dog. This enables you to perhaps use the same Tail in Wolf's and Hyeena's definitions. If, on the other hand, Tail is not an autonomous type, but rather, needs to able to wag the dog, then Tail is really more like a separate logical section within Dog's definition, i.e. a namespace within Dog.
A dog's tail is not an autonomous struct/class. If you ever had a dog you would know that. Also, the dog's tail is no namespace because it contains tail-specific data too.
Feb 02 2013
parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Sunday, 3 February 2013 at 07:33:52 UTC, Zach the Mystic wrote:
 On Sunday, 3 February 2013 at 03:15:57 UTC, TommiT wrote:
 On Sunday, 3 February 2013 at 02:55:44 UTC, Zach the Mystic 
 wrote:
 Well, if you want access to a struct from outside, save 
 yourself the time and put it outside to begin with. A nested 
 struct of course is directly related to the entity it finds 
 itself in. My pet metaphor is struct Dog containing struct 
 Tail. It would definitely be illogical to put the Tail 
 outside the Dog.
If Tail is an autonomous struct/class, then it totally makes sense to put the definition of Tail outside of dog. This enables you to perhaps use the same Tail in Wolf's and Hyeena's definitions. If, on the other hand, Tail is not an autonomous type, but rather, needs to able to wag the dog, then Tail is really more like a separate logical section within Dog's definition, i.e. a namespace within Dog.
A dog's tail is not an autonomous struct/class. If you ever had a dog you would know that. Also, the dog's tail is no namespace because it contains tail-specific data too.
I'm sorry, I'm just getting allergic to the word "namespace", since I don't believe any introduction of a special namespace feature in the language is required. Structs are namespaces - you got me there.
Feb 02 2013
prev sibling parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Sunday, 3 February 2013 at 02:55:44 UTC, Zach the Mystic wrote:
 On Saturday, 2 February 2013 at 20:30:26 UTC, Era Scarecrow 
 wrote:
 Yes, it should be callable that way since it knows where a is 
 at. However I would think a nested struct is more a 
 implementation detail.
I think this belittles just how important that implementation detail really is. Without a good design, the thing could be prohibitively difficult to implement. From what I understand generally, good encapsulation is a difficult design problem. I don't think you're alone.
 In short, nested structs would only be accessible (and 
 passable) inside the struct that made it. Meaning that most 
 likely the methods that work with it, and the struct itself 
 should be private.
Well, if you want access to a struct from outside, save yourself the time and put it outside to begin with. A nested struct of course is directly related to the entity it finds itself in. My pet metaphor is struct Dog containing struct Tail. It would definitely be illogical to put the Tail outside the Dog.
Agreed 100%, Although a second (instance of) Dog may want to come about and them sniff tails. That's outside access, but it's still within the limits of the Dogs. In those cases a context pointer could be acceptable as long as it's ensuring the data exists (and can't return it from the function); But overwriting one instance with a different context pointer of another could have very curious side effects depending on design. struct Dog { int id; struct Tail { string colorOf = "Black"; //just data. int getId() { return id; } } Tail tail; void func(ref Dog rhs) { //tail2 retains context pointer to rhs. Tail tail2 = rhs.tail; writeln(tail.getId()); //5 writeln(tail2.getId()); //10 } } Dog dog1 = Dog(5); Dog dog2 = Dog(10); dog2.tail.colorOf = "White"; dog1.func(dog2); //context pointer of d2 thrown away after copy, //unless opAssign declared and does something. dog1.tail = dog2.tail; assert(d1.id == 5); //untouched assert(d1.tail.colorOf == "White"); At which case the tail if it's allowed to be copied should be related but not strictly required to be updated or relied on Dog for behavior. Guess it takes a few rules and experiments to find the right balance of accessibility vs reliability vs flexibility.
Feb 02 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Sunday, 3 February 2013 at 03:34:23 UTC, Era Scarecrow wrote:
  Agreed 100%, Although a second (instance of) Dog may want to 
 come about and them sniff tails. That's outside access, but 
 it's still within the limits of the Dogs. In those cases a 
 context pointer could be acceptable as long as it's ensuring 
 the data exists (and can't return it from the function); But 
 overwriting one instance with a different context pointer of 
 another could have very curious side effects depending on 
 design.

   struct Dog {
     int id;
     struct Tail {
       string colorOf = "Black"; //just data.
       int getId() { return id; }
     }
     Tail tail;

     void func(ref Dog rhs) {
       //tail2 retains context pointer to rhs.
       Tail tail2 = rhs.tail;

       writeln(tail.getId());   //5
       writeln(tail2.getId());  //10
     }
   }
There is a bug in this code and it would not compile. Your getId must receive an instance of Dog. A tail by itself has no dog. The compiler cannot rewrite tail.getId() to someImaginaryDog.tail.getId(). It's easy to think about, once you get used to it. Your getId accesses a variable defined only in its parent struct. The compiler detects this and requires receiving a hidden pointer to (and *only to!*) an instance of the parent. The resulting top-level function is: int getId(ref Dog __d) { return __d.id; } See? It may only access a dog, but it's *defined* in the tail. This is the exact behavior we're looking for, and it's easy to implement and causes no real trouble, as far as I can see.
   Dog dog1 = Dog(5);
   Dog dog2 = Dog(10); dog2.tail.colorOf = "White";

   dog1.func(dog2);

   //context pointer of d2 thrown away after copy,
   //unless opAssign declared and does something.
   dog1.tail = dog2.tail;

   assert(d1.id == 5);   //untouched
   assert(d1.tail.colorOf == "White");


   At which case the tail if it's allowed to be copied should be 
 related but not strictly required to be updated or relied on 
 Dog for behavior.

  Guess it takes a few rules and experiments to find the right 
 balance of accessibility vs reliability vs flexibility.
With the bug removed, will any of these issues pop up? My guess is no.
Feb 02 2013
parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Sunday, 3 February 2013 at 07:26:03 UTC, Zach the Mystic wrote:
 On Sunday, 3 February 2013 at 03:34:23 UTC, Era Scarecrow wrote:
  struct Dog {
    int id;
    struct Tail {
      string colorOf = "Black"; //just data.
      int getId() { return id; }
    }
    Tail tail;

    void func(ref Dog rhs) {
      //tail2 retains context pointer to rhs.
      Tail tail2 = rhs.tail;

      writeln(tail.getId());   //5
      writeln(tail2.getId());  //10
    }
  }
There is a bug in this code and it would not compile. Your getId must receive an instance of Dog. A tail by itself has no dog. The compiler cannot rewrite tail.getId() to someImaginaryDog.tail.getId(). It's easy to think about, once you get used to it. Your getId accesses a variable defined only in its parent struct. The compiler detects this and requires receiving a hidden pointer to (and *only to!*) an instance of the parent. The resulting top-level function is: int getId(ref Dog __d) { return __d.id; } See? It may only access a dog, but it's *defined* in the tail. This is the exact behavior we're looking for, and it's easy to implement and causes no real trouble, as far as I can see.
I don't see the bug. Tail is known to be a nested struct so it is required to have it's context (parent) attached, so it supplies it although silently; Therefore tail points to rhs & rhs.tail. This is only valid as long as the reference to rhs exists (or as long as this function exists for sure). Besides the 'id' think more it renamed to 'string dogName', therefore you can tell which tail belongs to which dog, be it sparky or scruffy, etc. In this case the nested struct relies on information from it's parent, but the parent doesn't need information from it's nested structs, allowing it to be correct even if the tail gets changed colors. This can have useful other effects in place like compression, maybe DB management (a text query is replaced by a compiled version of the same thing), etc.
  Dog dog1 = Dog(5);
  Dog dog2 = Dog(10); dog2.tail.colorOf = "White";

  dog1.func(dog2);

  //context pointer of d2 thrown away after copy,
  //unless opAssign is declared and does something.
  dog1.tail = dog2.tail;

  assert(dog1.id == 5);   //untouched
  assert(dog1.tail.colorOf == "White");


 At which case the tail if it's allowed to be copied should be 
 related but not strictly required to be updated or relied on 
 Dog for behavior.

 Guess it takes a few rules and experiments to find the right 
 balance of accessibility vs reliability vs flexibility.
With the bug removed, will any of these issues pop up? My guess is no.
Maybe... I forget what the issues were since I went to sleep.
Feb 03 2013
prev sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Saturday, 2 February 2013 at 06:04:01 UTC, TommiT wrote:
 On Saturday, 2 February 2013 at 03:50:49 UTC, Zach the Mystic 
 wrote:
 assert(A.B.C.myMemberFunction(a, a.b, a.b.c) == 3);
That wouldn't compile, so you must mean: assert(a.b.c.myMemberFunction(a, a.b, a.b.c) == 3);
You're right. I don't know how the compiler stores the name of the function I meant underneath the hood. But it must such a mechanism for naming A.B.C.myMemberFunction, which is nothing more than a function which takes a pointer, or in this case a few pointers, to instances of the appropriate classes. Non-static member functions generally must take pointers to instances of their types. The only difference between this: struct A { int _a; int getA() { return _a; } } And this: struct A { int _a; } int getA(ref A a) { return a._a; } Is that the compiler does the work of including the hidden pointer automatically in the first case, and also encloses getA into a, I hesitate to say it too loud now... namespace, so that it can't just be reached from anywhere.
 What do you suppose would happen if I wrote the following?

 struct A
 {
   int _a = 1;
   B b;
   struct B
   {
     int _b = 1;
     C c;
     struct C
     {
       int _c = 1;
       int myMemberFunction() { return _a + _b + _c; }
     }
     static int otherFunction()
     {
       C cc;
       return cc.myMemberFunction();
     }
   }
 }

 void main()
 {
   int i = A.B.otherFunction();
 }
I was simply using A.B.C.myMemberFunction as a shorthand for whatever name the compiler uses underneath the hood to represent the non-static version of the function.
Feb 02 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 2 February 2013 at 17:25:57 UTC, Zach the Mystic 
wrote:
 What do you suppose would happen if I wrote the following?

 struct A
 {
  int _a = 1;
  B b;
  struct B
  {
    int _b = 1;
    C c;
    struct C
    {
      int _c = 1;
      int myMemberFunction() { return _a + _b + _c; }
    }
    static int otherFunction()
    {
      C cc;
      return cc.myMemberFunction();
    }
  }
 }

 void main()
 {
  int i = A.B.otherFunction();
 }
I was simply using A.B.C.myMemberFunction as a shorthand for whatever name the compiler uses underneath the hood to represent the non-static version of the function.
Yes, I can see that now. I didn't understand that the code wasn't actual code but something that the compiler sees. But, you didn't answer my question. What would happen if I actually did write that code and click "compile". What would there be in the 'i' variable? Era Scarecrow already answered the question for you. The correct answer is that the code wouldn't compile. But I just want to see that you understand why it must be so.
Feb 02 2013
parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Saturday, 2 February 2013 at 17:33:38 UTC, TommiT wrote:
 I was simply using A.B.C.myMemberFunction as a shorthand for 
 whatever name the compiler uses underneath the hood to 
 represent the non-static version of the function.
Yes, I can see that now. I didn't understand that the code wasn't actual code but something that the compiler sees. But, you didn't answer my question. What would happen if I actually did write that code and click "compile". What would there be in the 'i' variable? Era Scarecrow already answered the question for you. The correct answer is that the code wouldn't compile. But I just want to see that you understand why it must be so.
I'm sure I'll get by, with a little help from my friends.
Feb 02 2013
prev sibling next sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 2 February 2013 at 03:50:49 UTC, Zach the Mystic 
wrote:
 [..]
What do you suppose would happen if I wrote the following? struct A { struct B {} B b1; B b2; } void main() { A a; assert(&a.b1 == &a.b2); }
Feb 01 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Saturday, 2 February 2013 at 06:19:29 UTC, TommiT wrote:
 On Saturday, 2 February 2013 at 03:50:49 UTC, Zach the Mystic 
 wrote:
 [..]
What do you suppose would happen if I wrote the following? struct A { struct B {} B b1; B b2; } void main() { A a; assert(&a.b1 == &a.b2); }
With my new rules? It would be illegal to take the address of a struct which contained no data. I don't think this will break much code, but I don't know.
Feb 02 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 2 February 2013 at 17:56:41 UTC, Zach the Mystic 
wrote:
 On Saturday, 2 February 2013 at 06:19:29 UTC, TommiT wrote:
 On Saturday, 2 February 2013 at 03:50:49 UTC, Zach the Mystic 
 wrote:
 [..]
What do you suppose would happen if I wrote the following? struct A { struct B {} B b1; B b2; } void main() { A a; assert(&a.b1 == &a.b2); }
With my new rules? It would be illegal to take the address of a struct which contained no data.
Yes, that is kind of what I was getting at with my question. But I'm going to ask the same thing in a better way now: Given your new nested struct variable behaviour and my definition of struct 'A' quoted above, would the following lines compile? static assert( A.B.sizeof == 0 ); static assert( A.sizeof == 0 );
Feb 02 2013
parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Saturday, 2 February 2013 at 18:47:37 UTC, TommiT wrote:
 On Saturday, 2 February 2013 at 17:56:41 UTC, Zach the Mystic 
 wrote:
 On Saturday, 2 February 2013 at 06:19:29 UTC, TommiT wrote:
 On Saturday, 2 February 2013 at 03:50:49 UTC, Zach the Mystic 
 wrote:
 [..]
What do you suppose would happen if I wrote the following? struct A { struct B {} B b1; B b2; } void main() { A a; assert(&a.b1 == &a.b2); }
With my new rules? It would be illegal to take the address of a struct which contained no data.
Yes, that is kind of what I was getting at with my question. But I'm going to ask the same thing in a better way now: Given your new nested struct variable behaviour and my definition of struct 'A' quoted above, would the following lines compile? static assert( A.B.sizeof == 0 ); static assert( A.sizeof == 0 );
Yes, I believe so. I don't see why not.
Feb 02 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 2 February 2013 at 03:50:49 UTC, Zach the Mystic 
wrote:
 [..]
What I'm trying to tell you through those questions is that what you insists on calling a struct in your proposal is really just a template for a namespace that lives inside a struct or a class. And variables of those nested struct types are the actual namespaces.
Feb 01 2013
prev sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 2 February 2013 at 03:50:49 UTC, Zach the Mystic 
wrote:
 [..]
Then, if we used your proposed nested structs to implement properties, pretty weird things like this would become possible: struct A { int _value; struct B { int get() { return _value; } alias this = get; void opAssign(int v) { _value = v; } } B length; } void func(T)(ref A a, T oldLength) { a.length = 100; // Trying to restore 'a' back to the old length: a.length = oldLength; } void main() { A a; a.length = 5; func(a, a.length); assert(a.length == 100); }
Feb 01 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Saturday, 2 February 2013 at 07:10:00 UTC, TommiT wrote:
 On Saturday, 2 February 2013 at 03:50:49 UTC, Zach the Mystic 
 wrote:
 [..]
Then, if we used your proposed nested structs to implement properties, pretty weird things like this would become possible: struct A { int _value; struct B { int get() { return _value; } alias this = get; void opAssign(int v) { _value = v; } } B length; } void func(T)(ref A a, T oldLength) { a.length = 100; // Trying to restore 'a' back to the old length: a.length = oldLength; } void main() { A a; a.length = 5; func(a, a.length); assert(a.length == 100); }
This code is both wrong and has nothing whatever to do with the current topic. Boiling down the template to its resulting function, and imagining _value as the intended entity: void func(ref A a, int oldLength) { a._value = 100; a._value = oldLength; } A a; a._value = 5; func(a, a._value); assert(a._value == 5); // 5, not 100 func takes an int. It's not a reference, it's a copy. Let's assume you meant void func(ref A a, ref int oldLength) {} instead. Well, if you pass a reference, set it, and then refer it, you're going to get the set value back. I'm sorry, you can't adjust a reference and then expect to get a phantom original copy back. While I may have made a mistake, I simply see no connection between this and the idea of properties as structs.
Feb 02 2013
parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 2 February 2013 at 17:49:44 UTC, Zach the Mystic 
wrote:
 On Saturday, 2 February 2013 at 07:10:00 UTC, TommiT wrote:
 On Saturday, 2 February 2013 at 03:50:49 UTC, Zach the Mystic 
 wrote:
 [..]
Then, if we used your proposed nested structs to implement properties, pretty weird things like this would become possible: struct A { int _value; struct B { int get() { return _value; } alias this = get; void opAssign(int v) { _value = v; } } B length; } void func(T)(ref A a, T oldLength) { a.length = 100; // Trying to restore 'a' back to the old length: a.length = oldLength; } void main() { A a; a.length = 5; func(a, a.length); assert(a.length == 100); }
This code is both wrong and has nothing whatever to do with the current topic. Boiling down the template to its resulting function, and imagining _value as the intended entity: void func(ref A a, int oldLength) { a._value = 100; a._value = oldLength; } A a; a._value = 5; func(a, a._value); assert(a._value == 5); // 5, not 100 func takes an int. It's not a reference, it's a copy. Let's assume you meant void func(ref A a, ref int oldLength) {} instead. Well, if you pass a reference, set it, and then refer it, you're going to get the set value back. I'm sorry, you can't adjust a reference and then expect to get a phantom original copy back. While I may have made a mistake, I simply see no connection between this and the idea of properties as structs.
No, you're not getting it. The following is a function template: void func(T)(ref A a, T oldLength) {...} The type of parameter oldLength is going to be the type of the expression you pass as the second argument when you call func. If you call func like I did in my example: A a; func(a, a.length); ...the type of the second argument to func, a.length, is A.B, and therefore the specialization of func that ends up being called is: void func(ref A a, A.B oldLength) {...} ...and variable a.length is being passed by value, not by reference.
Feb 02 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Thursday, 31 January 2013 at 19:13:03 UTC, Zach the Mystic 
wrote:
 I'm hoping that the community won't close the books on this 
 issue without even *examining* my proposal, found here:

 http://forum.dlang.org/thread/kdukid$stg$1 digitalmars.com?page=2#post-yqvrjszzlcpmmuyqyxdz:40forum.dlang.org
I'm just going to repeat the arguments I've already made on the "Property discussion wrap-up" thread against the idea of using a variable as a property: struct MyArray { int _len; // struct2.0 variables have an implicit reference 'outer' to // the enclosing object (don't ask how... not my idea) struct2.0 Len { int opCall() const { return outer._len; } alias this = opCall; void opAssign(int v) const { outer._len = v; } } Len length; // please ignore the memory overhead over here } void func(N)(N n) if (isConvertible!(N,int)) { n = 123; } void main() { MyArray arr; func(arr.length); // changes arr._len (not good) }
Jan 31 2013
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-01-31 19:13:02 +0000, "Zach the Mystic" 
<reachBUTMINUSTHISzach gOOGLYmail.com> said:

 Or just shut me up by saying something about why it's just wrong or 
 simply can't work.
Don't take it personally. I'm not saying anything about your proposal, or any other proposal for that matter. All I'm saying is that I find it very unlikely that this discussion changes anything. Sorry for being pessimistic. I'm not the one you need to convince, Walter decides in the end. And he has shown little inclination to make changes to how properties works other than some subtle refinements. This was true in 2009, it seems to be even more the case today. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca/
Jan 31 2013
prev sibling parent "Jesse Phillips" <Jessekphillips+D gmail.com> writes:
On Thursday, 31 January 2013 at 19:13:03 UTC, Zach the Mystic 
wrote:
 I'm hoping that the community won't close the books on this 
 issue without even *examining* my proposal, found here:

 http://forum.dlang.org/thread/kdukid$stg$1 digitalmars.com?page=2#post-yqvrjszzlcpmmuyqyxdz:40forum.dlang.org
I don't think the community is ready to close the books on this. and Properties. And that was purely at the syntactic level. And have a similar issue with Java's introduction of foreach. Why does it have to be so hard to remember the syntax of these very simple constructs! Anyway, I don't see what your plan offers from just fixing property to do what is needed. I've also got overwhelmed by the complexity to writing properties.
Jan 31 2013
prev sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Thursday, 31 January 2013 at 15:40:19 UTC, Michel Fortin wrote:
 On 2013-01-31 14:50:40 +0000, "Steven Schveighoffer" 
 <schveiguy yahoo.com> said:

 It actually is a bit depressing, we have to reset the clock 
 back to late  2009 to start over with properties...
I haven't participated in the discussions about properties this time around because it's pretty obvious to me it's getting nowhere. It seems to me that nothing can be done at this point in time if we want to avoid a breakage of almost all current D code.
Also if you're worried about the code breakage necessary to get properties as structs, i.e. nested structs must now have "static" in front of them, consider: 1) That having structs which are nested inside functions hold a pointer without having structs nested in structs do the same thing is an inconsistent language feature. 2) Second, that such struct will still work in all cases where an outer name is not being shadowed. They will simply suffer performance costs of having a needless pointer attached. Also, is it really asking people too much to tag nested structs with "static" now?
Jan 31 2013
parent "Michael" <pr m1xa.com> writes:
Static nested struct as property... what is going on...
In this case is better to simply rid-off  property keyword.

"Properties" are better implemented where they created. Maybe 
have bugs in design, but I think that property should be a simple 
access method/function without struct-and-whatever-else kung-fu 
code.
Jan 31 2013
prev sibling parent reply "Jesse Phillips" <Jessekphillips+D gmail.com> writes:
On Thursday, 31 January 2013 at 01:26:19 UTC, Steven 
Schveighoffer wrote:
 On Tue, 29 Jan 2013 23:57:14 -0500, Jesse Phillips 
 <Jessekphillips+d gmail.com> wrote:

 Sorry I have to oppose this. It is in no way a compromise as 
 it is completely different from everything suggested. I'm 
 going to take this opportunity to highjack your thread.
You are welcome to it! I don't know if there is a thread on this newsgroup about properties that hasn't been hijacked.
Thank you.
 I should explain that my reasoning behind this is:

 1. Walter wants to get rid of  property
I can't really speak to what Walter wants, but I think there is more to it than removing a keyword.
 2. Dispite 4 years of assuming  property will be implemented, 
 the old D1-style crap is still in place.
Yep, I thought its introduction meant things were going to break, and also that other things would work.
 The compromise is: OK, you want to ditch  property?  I can live 
 with that as long as we have some way to designate properties.  
 How about this?
I don't think that is a compromise as i don't believe it is property that is slated for removal, it is designating something a property.
 Can an pro- property members claim that the current behavior 
 is what you want? I believe this answer is no.
The answer is no, but only because what we asked for was never implemented. What was ORIGINALLY designed with property (enforcement of parentheses on functions, enforcement against parentheses on properties) is what we wanted.
Yep, totally thought that was coming. I'd still be ok with it, but I'm still partial to not having it enforced, would rather see field -> property a seamless transition.
 It seems at least some members for  property feel that 
 currently functions are being annotated with  property that 
 shouldn't be.
This is unavoidable. It's like saying I feel some functions are incorrectly named. property has nothing to do with it. There is no "right" answer to whether something should be a property or not, just like there is no "right" name for a function.
Yes, but I was thinking more on the degree of wrongness that is currently acceptable. Something to think on for what my proposal would be. But again, I don't care about the appearance, only behavior.
 It also seems those for  property aren't fighting optional 
 parens as much? Can we discuss fixing the issues we have with 
 this. I think a good change is to require parens if returning 
 a callable (opposite of Walters suggestion).
Yes, if the choice is between having the previous implementation (D1) and optional parentheses with a way to designate properties, I'll choose the latter.
Walter's suggestion isn't (D1) implementation it address some concerns with the existing behavior, but doesn't give you a way to declare properties. I think his suggestions need implemented regardless of what we do with property. I think Walter just felt this would appease the pro-property.
 If I have my above claims mostly correct, then I'd say 
  property needs to be put back in the drawing board and 
 re-implemented.
If you want to replace property, we need a replacement. property still serves a purpose, even in it's currently crippled form.
What purpose is that? Isn't it a no-op by default, and barely enforce () with -property?
 I'd be for removing it from the language and if we decide on 
 what in needs to enforce and should be part of the language, 
 then its implementation is completed in a feature branch and 
 remains out of the language until it meets the needed 
 enforcement and behavior.
Fine, but leave property in until you have completed the replacement feature.
I'm not sure if we are going to have a complete replacement, but your right, we can leave it in until such a choice is finalized, but let us get rid of -property.
 Ah, your subtle bias shines through ;)
:)
 The real fact of the matter is, if D never had the "hack" 
 properties it did, I actually wouldn't care.  Calling functions 
 instead of setting or getting properties is not that horrible.  
 But writeln = "hi" is horrible.
Yep, introducing properties would have been easy, because no one would have fallen for the joys of optional parens. writeln = "hi" would not compile with Walters suggested changes.
 In general, the idea is to implement fields without having to 
 create storage for them.  It will never perform as well as a 
 field.
I know, but you can't trust when reading code that is what happens. And having that convention was being argued for, I like Walter's position of having the compiler make guarantees and not conventions (I'm sure I've got some exception I'd want but can't think of one).
 In other words, go back to D1 properties.  No thanks.
Again, it wouldn't be D1, and we aren't going back because that is what we currently have. We need to fix it.
 -Steve
Thanks for the feedback.
Jan 31 2013
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/31/13 7:01 PM, Jesse Phillips wrote:
 I don't think that is a compromise as i don't believe it is  property
 that is slated for removal, it is designating something a property.
FWIW we want to keep a means to define properties. Andrei
Jan 31 2013
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, February 01, 2013 01:01:02 Jesse Phillips wrote:
 I think his suggestions need implemented regardless of what we do
 with  property. I think Walter just felt this would appease the
 pro-property.
Well, it doesn't even come close. For the most part, the pro- property folks want explicit proprties, and that's precisely what Walter is proposing that we get rid of.
 writeln = "hi" would not compile with Walters suggested changes.
Only because it's variadic. Something like range.popFrontN = 7; _would_ compile. And that's just as bad. We need explicit setter properties in order to avoid letting assignment work with functions where it makes no sense for it to work. - Jonathan M Davis
Jan 31 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/31/13 10:14 PM, Jonathan M Davis wrote:
 On Friday, February 01, 2013 01:01:02 Jesse Phillips wrote:
 I think his suggestions need implemented regardless of what we do
 with  property. I think Walter just felt this would appease the
 pro-property.
Well, it doesn't even come close. For the most part, the pro- property folks want explicit proprties, and that's precisely what Walter is proposing that we get rid of.
 writeln = "hi" would not compile with Walters suggested changes.
Only because it's variadic. Something like range.popFrontN = 7; _would_ compile. And that's just as bad. We need explicit setter properties in order to avoid letting assignment work with functions where it makes no sense for it to work.
Under some proposals range.popFrontN = 7 would not compile because there's no corresponding range.popFrontN that yields an int. Andrei
Jan 31 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 Jan 2013 22:38:04 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 1/31/13 10:14 PM, Jonathan M Davis wrote:
 On Friday, February 01, 2013 01:01:02 Jesse Phillips wrote:
 I think his suggestions need implemented regardless of what we do
 with  property. I think Walter just felt this would appease the
 pro-property.
Well, it doesn't even come close. For the most part, the pro- property folks want explicit proprties, and that's precisely what Walter is proposing that we get rid of.
 writeln = "hi" would not compile with Walters suggested changes.
Only because it's variadic. Something like range.popFrontN = 7; _would_ compile. And that's just as bad. We need explicit setter properties in order to avoid letting assignment work with functions where it makes no sense for it to work.
Under some proposals range.popFrontN = 7 would not compile because there's no corresponding range.popFrontN that yields an int.
I don't think this rule is good enough. You are inviting strange properties to invade your types, especially with the advent of UFCS. -Steve
Jan 31 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/31/13 11:41 PM, Steven Schveighoffer wrote:
 On Thu, 31 Jan 2013 22:38:04 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 On 1/31/13 10:14 PM, Jonathan M Davis wrote:
 On Friday, February 01, 2013 01:01:02 Jesse Phillips wrote:
 I think his suggestions need implemented regardless of what we do
 with  property. I think Walter just felt this would appease the
 pro-property.
Well, it doesn't even come close. For the most part, the pro- property folks want explicit proprties, and that's precisely what Walter is proposing that we get rid of.
 writeln = "hi" would not compile with Walters suggested changes.
Only because it's variadic. Something like range.popFrontN = 7; _would_ compile. And that's just as bad. We need explicit setter properties in order to avoid letting assignment work with functions where it makes no sense for it to work.
Under some proposals range.popFrontN = 7 would not compile because there's no corresponding range.popFrontN that yields an int.
I don't think this rule is good enough. You are inviting strange properties to invade your types, especially with the advent of UFCS.
I agree. Was just sayin'. Andrei
Jan 31 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 31 Jan 2013 19:01:02 -0500, Jesse Phillips  
<Jessekphillips+D gmail.com> wrote:

 On Thursday, 31 January 2013 at 01:26:19 UTC, Steven Schveighoffer wrote:
 On Tue, 29 Jan 2013 23:57:14 -0500, Jesse Phillips  
 <Jessekphillips+d gmail.com> wrote:

 Sorry I have to oppose this. It is in no way a compromise as it is  
 completely different from everything suggested. I'm going to take this  
 opportunity to highjack your thread.
You are welcome to it! I don't know if there is a thread on this newsgroup about properties that hasn't been hijacked.
Thank you.
 I should explain that my reasoning behind this is:

 1. Walter wants to get rid of  property
I can't really speak to what Walter wants, but I think there is more to it than removing a keyword.
I meant the property design, including the keyword. Basically whatever property was supposed to stand for.
 The compromise is: OK, you want to ditch  property?  I can live with  
 that as long as we have some way to designate properties.  How about  
 this?
I don't think that is a compromise as i don't believe it is property that is slated for removal, it is designating something a property.
I don't think that's the case. D1 has a designation of what is a property -- if it has no arguments it is a getter, if it has a single argument it is a setter. The extra rules Walter is proposing are a half-baked design that covers some cases. But the rules are controlling the behavior based on superficial observations instead of allowing an author to express specific intents. It sounds like something Congress would come up with...
 Can an pro- property members claim that the current behavior is what  
 you want? I believe this answer is no.
The answer is no, but only because what we asked for was never implemented. What was ORIGINALLY designed with property (enforcement of parentheses on functions, enforcement against parentheses on properties) is what we wanted.
Yep, totally thought that was coming. I'd still be ok with it, but I'm still partial to not having it enforced, would rather see field -> property a seamless transition.
First, it's not seamless without a keyword or special syntax (remember the delegate problem). Second, that's not a mutually exclusive choice. If you enforce property syntax, then it's still seamless (and even more so since you actually *CAN* implement what is desired).
 It seems at least some members for  property feel that currently  
 functions are being annotated with  property that shouldn't be.
This is unavoidable. It's like saying I feel some functions are incorrectly named. property has nothing to do with it. There is no "right" answer to whether something should be a property or not, just like there is no "right" name for a function.
Yes, but I was thinking more on the degree of wrongness that is currently acceptable. Something to think on for what my proposal would be. But again, I don't care about the appearance, only behavior.
Then why ever have properties at all? Functions work just fine.
 It also seems those for  property aren't fighting optional parens as  
 much? Can we discuss fixing the issues we have with this. I think a  
 good change is to require parens if returning a callable (opposite of  
 Walters suggestion).
Yes, if the choice is between having the previous implementation (D1) and optional parentheses with a way to designate properties, I'll choose the latter.
Walter's suggestion isn't (D1) implementation it address some concerns with the existing behavior, but doesn't give you a way to declare properties.
I think you are misunderstanding his proposal. Under his proposal, two completely unrelated and unconnected functions could combine together to allow a setter that is completely unintended. Instead of specifying intent, we have to jump through the compiler hoops to avoid accidental intent. This is not a solution, it's actually worse than D1 style properties. You'll have code that can call a 'setter' on an object or struct with no 'getter' and you'll have no idea why.
 I think his suggestions need implemented regardless of what we do with  
  property. I think Walter just felt this would appease the pro-property.
I certainly hope none of his suggestions are implemented, they will only confuse the situation.
 If I have my above claims mostly correct, then I'd say  property needs  
 to be put back in the drawing board and re-implemented.
If you want to replace property, we need a replacement. property still serves a purpose, even in it's currently crippled form.
What purpose is that? Isn't it a no-op by default, and barely enforce () with -property?
The purpose is to specify intent "I declare this is a property, use it that way". It's the whole point of having a property syntax. It's just not enforced by the compiler. The compiler has numerous bugs on it, that doesn't mean the features should be ditched, it means we have to correctly implement those features. array.dup allows implicit casting away from immutable (at least it did, not sure if that was fixed). Does that mean we should get rid of dup?
 I'd be for removing it from the language and if we decide on what in  
 needs to enforce and should be part of the language, then its  
 implementation is completed in a feature branch and remains out of the  
 language until it meets the needed enforcement and behavior.
Fine, but leave property in until you have completed the replacement feature.
I'm not sure if we are going to have a complete replacement, but your right, we can leave it in until such a choice is finalized, but let us get rid of -property.
That doesn't hurt anything, that switch is an experimental feature, and once we have the blessed property syntax, we likely will need that experimental feature to obey the new syntax.
 The real fact of the matter is, if D never had the "hack" properties it  
 did, I actually wouldn't care.  Calling functions instead of setting or  
 getting properties is not that horrible.  But writeln = "hi" is  
 horrible.
Yep, introducing properties would have been easy, because no one would have fallen for the joys of optional parens.
I see only minor issue with optional parens. It's the setters that are the most disruptive.
 writeln = "hi" would not compile with Walters suggested changes.
No, but other abuses would.
 In general, the idea is to implement fields without having to create  
 storage for them.  It will never perform as well as a field.
I know, but you can't trust when reading code that is what happens. And having that convention was being argued for, I like Walter's position of having the compiler make guarantees and not conventions (I'm sure I've got some exception I'd want but can't think of one).
The compiler cannot make performance guarantees of any kind really. That is up to convention. Properties do provide a *mechanism* to create a convention. What the convention is remains the will of the author.
 In other words, go back to D1 properties.  No thanks.
Again, it wouldn't be D1, and we aren't going back because that is what we currently have. We need to fix it.
OK, I stand corrected, if it is a choice between D1 properties and Walter's new rules, I'll choose D1 properties. At least I know what I get there. But if we have *any* property syntax at all, I'd prefer that. Even the current design, while not implemented, has the PROMISE of having a fully functional property syntax. I prefer the promise of something that is usable to something that is utterly useless, even if it's already implemented. -Steve
Jan 31 2013
prev sibling parent "Michael" <pr m1xa.com> writes:
As proposal:

class Example
{
     public int IntProperty
     {
         get; private set;
     }

     private double _internalMember;

     double FloatProperty
     {
         get out { assert(result > 0); } body { return 
_internalMember * 42; }
         set in  { assert(value != 0); } body { _internalMember = 
value + 42; }
     }
}

Resulting code:

class Example
{
     private _autoGeneratedBackMember;

     public int get_IntProperty() { return 
_autoGeneratedBackMember; }
     private void set_IntProperty(int value) { 
_autoGeneratedBackMember = value; }

     public
     {
         double get_FloatProperty() out(result) { assert(result > 
0); } body { return _internalMember * 42; }
         void   set_FloatPoperrty(double value) in { assert(value 
 0); } body { _internalMember = value + 42; }
} } 1. Rid-of property keyword, UFCS as they now. Optional parentheses for UFCS with one or two parameters, not for variable number of arguments. address of property, ref property, property rewrite, virtual property, explicit get/set methods, property with value semantic, exlicit calling get/set methods etc. 3. Property can be exported to libray as "<out type> get_<Name>(), void set_<Name>(<in type>)". 4. Get property always have only out(result) { } contract. 5. Set property always have only in { } contract. Thanks.
Feb 02 2013