www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - property needed or not needed?

reply "Rob T" <rob ucora.com> writes:
I can create a function that is located in a class/struct or 
outside on its own without  property. If the function has the 
signature of a property, i.e., void f( T x ) or T f(), I can use 
it as if it is a property.

Example:

// main module
int g; // global in main module
void p(int a) { g = a; }
int p() { return g; }

main()
{
    p = 7; // OK
    int t = p; // OK, t = 7
}

In the example, there's no class or struct, so I assume p() is 
considered to be a property of the module, which seems to make 
some sense.

I also see that there's a compiler option "-property" that 
currently is not recognized, but is supposed to "enforce use of 
 property on property functions".

So what's up with  property? Is it being depreciated for being 
redundant, or will it later be strictly enforced, or is it to be 
optionally enforced through a compiler switch?

--rt
Nov 18 2012
next sibling parent "Mike Parker" <aldacron gmail.com> writes:
On Monday, 19 November 2012 at 06:02:06 UTC, Rob T wrote:

 I also see that there's a compiler option "-property" that 
 currently is not recognized, but is supposed to "enforce use of 
  property on property functions".

 So what's up with  property? Is it being depreciated for being 
 redundant, or will it later be strictly enforced, or is it to 
 be optionally enforced through a compiler switch?
I don't recall seeing anything about property being deprecated. The intention of the -property switch is to, IIRC, ease the transition to the ultimate full-time enforcement of the property attribute. Enforcement is off by default. At some point, it will be turned on by default at which point the -property switch will no longer be necessary. I usually compile with -property and AFAIK it is functioning as intended. I've gotten errors in the past when it was enabled.
Nov 18 2012
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, November 19, 2012 07:02:03 Rob T wrote:
 So what's up with  property? Is it being depreciated for being
 redundant, or will it later be strictly enforced, or is it to be
 optionally enforced through a compiler switch?
It didn't used to be necessary, but there are ambiguities without it (particularly with regards to property functions which return delegates), and a number of people don't like the laxness of practically any function with a particular sort of signature being able to be used as a property function rather than it being part of the API. So, property was introduced, but similar to override, it was decided that its enforcement would be phased in. -property was introduced so that the compiler's enforcement of it could be sorted out (it's still very buggy) and so that everyone would have time to adjust their code so that it used property correctly. Now, how strict the enforcement will ultimately be is up for some debate. It needs to be the case that any property function must be used as a property function in order to avoid the aforementioned ambiguities (so using parens will be illegal with property functions), but there's quite a lot of dissension surrounding whether non-property functions should be callable as property functions (i.e. whether non- property functions with the appropriate signature can be called without parens as is currently the case). Some of us consider it to be incredibly sloppy to allow it, whereas others find the idea of requiring parens to be extremely annoying (especially when dealing with UFCS). TDPL is somewhat ambiguous on the matter, and AFAIK, no official decision has been made. - Jonathan M Davis
Nov 18 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/19/12 1:16 AM, Jonathan M Davis wrote:
 On Monday, November 19, 2012 07:02:03 Rob T wrote:
 So what's up with  property? Is it being depreciated for being
 redundant, or will it later be strictly enforced, or is it to be
 optionally enforced through a compiler switch?
It didn't used to be necessary, but there are ambiguities without it (particularly with regards to property functions which return delegates),
I think we need to seriously revisit that. It's a corner case that hurts everyone everywhere.
 and
 a number of people don't like the laxness of practically any function with a
 particular sort of signature being able to be used as a property function
 rather than it being part of the API.
I think UFCS changes the playfield quite a lot. Code using UFCS looks a whole lot crappier with a bunch of arbitrary extra parens. Andrei
Nov 18 2012
next sibling parent reply "Rob T" <rob ucora.com> writes:
On Monday, 19 November 2012 at 06:53:46 UTC, Andrei Alexandrescu 
wrote:
 I think UFCS changes the playfield quite a lot. Code using UFCS 
 looks a whole lot crappier with a bunch of arbitrary extra 
 parens.


 Andrei
I'm making good use out of UFCS functions that work like properties, so to remain consistent with struct/class calling syntax, I would expect to have the ability to define functions that have property semantics at the module level. I really think that modules should have properties anyway, and since I can do it, I am doing it, and it works great. My guess is that if property gets enforced, we'll see a lot of functions with empty parameter lists being defined as property for the sole reason to get rid of having to type in the (). --rt
Nov 19 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, November 19, 2012 09:16:29 Rob T wrote:
 My guess is that if  property gets enforced, we'll see a lot of
 functions with empty parameter lists being defined as  property
 for the sole reason to get rid of having to type in the ().
Which completely violates the concept of a property in the first place. It's intended to be an abstraction for a variable. Using property just to get rid of parens would be like naming types with verbs instead of nouns. It's completely backwards. - Jonathan M Davis
Nov 19 2012
next sibling parent reply "thedeemon" <dlang thedeemon.com> writes:
On Monday, 19 November 2012 at 08:23:43 UTC, Jonathan M Davis 
wrote:
 On Monday, November 19, 2012 09:16:29 Rob T wrote:
 My guess is that if  property gets enforced, we'll see a lot of
 functions with empty parameter lists being defined as  property
 for the sole reason to get rid of having to type in the ().
Which completely violates the concept of a property in the first place. It's intended to be an abstraction for a variable. Using property just to get rid of parens would be like naming types with verbs instead of nouns. It's completely backwards. - Jonathan M Davis
I very much like the combination of UFCS, ranges and parens-free style which allows writing code like iota(0, 1000000).map!(to!string).retro.take(50).retro[10].writeln; So I like Andrei's idea to force property only for those functions where it's absolutely necessary to fight ambiguity.
Nov 19 2012
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 19 November 2012 at 08:45:03 UTC, thedeemon wrote:
 On Monday, 19 November 2012 at 08:23:43 UTC, Jonathan M Davis 
 wrote:
 On Monday, November 19, 2012 09:16:29 Rob T wrote:
 My guess is that if  property gets enforced, we'll see a lot 
 of
 functions with empty parameter lists being defined as 
  property
 for the sole reason to get rid of having to type in the ().
Which completely violates the concept of a property in the first place. It's intended to be an abstraction for a variable. Using property just to get rid of parens would be like naming types with verbs instead of nouns. It's completely backwards. - Jonathan M Davis
I very much like the combination of UFCS, ranges and parens-free style which allows writing code like iota(0, 1000000).map!(to!string).retro.take(50).retro[10].writeln; So I like Andrei's idea to force property only for those functions where it's absolutely necessary to fight ambiguity.
I kind of agree with Jonathan here. property really shines when you want to "add" an attribute to a struct. array "front", for example, is a perfect example of this. RefCounted's "payload" (IMO), is also a good example. *Functions* that do actual operations, in particular, "retro", IMO, should not be properties. "byLines", for example, is a member function, and not property. How is: r.retro; any better than r.byLines() ? At best, it makes it look like r has a built-in retro attribute, which is miss-leading. -------- I'll admit I thought too it would be "convenient" to write ".retro" without the parens, but let's face it, that'd be incorrect usage...
Nov 19 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/19/12 4:01 AM, monarch_dodra wrote:
 I kind of agree with Jonathan here.  property really shines when you
 want to "add" an attribute to a struct.
I kind of agree with him, too, but it would be a mistake to not reckon a change in dynamics. UFCS makes all those extra parens just awkward, and people will vote with their code regardless whether some particular viewpoint from some particular angle considers the approach backwards. Andrei
Nov 19 2012
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 19 November 2012 at 14:58:29 UTC, Andrei Alexandrescu 
wrote:
 On 11/19/12 4:01 AM, monarch_dodra wrote:
 I kind of agree with Jonathan here.  property really shines 
 when you
 want to "add" an attribute to a struct.
I kind of agree with him, too, but it would be a mistake to not reckon a change in dynamics. UFCS makes all those extra parens just awkward, and people will vote with their code regardless whether some particular viewpoint from some particular angle considers the approach backwards. Andrei
One of the things that we may want to take into account, is that -property prevents any existing function from migrating to/from property. For example, if we want to make "retro" a property, we can't without breaking any and all UFCS usage of retro.
Nov 19 2012
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
11/19/2012 7:18 PM, monarch_dodra пишет:
 On Monday, 19 November 2012 at 14:58:29 UTC, Andrei Alexandrescu wrote:
 On 11/19/12 4:01 AM, monarch_dodra wrote:
 I kind of agree with Jonathan here.  property really shines when you
 want to "add" an attribute to a struct.
I kind of agree with him, too, but it would be a mistake to not reckon a change in dynamics. UFCS makes all those extra parens just awkward, and people will vote with their code regardless whether some particular viewpoint from some particular angle considers the approach backwards. Andrei
One of the things that we may want to take into account, is that -property prevents any existing function from migrating to/from property. For example, if we want to make "retro" a property, we can't without breaking any and all UFCS usage of retro.
The major problem about property enforcement as it stands is that it breaks the duality of things like retro: a.retro vs retro(a) Both should be allowed as it's a matter of taste that shouldn't be enforced. A lot of new code uses a.retro and a lot of older code uses retro(a). If retro is property then only the first one compiles If retro is a function then only the second one compiles. Which obviously means property has to be reconsidered. -- Dmitry Olshansky
Nov 19 2012
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 19 November 2012 at 17:42:28 UTC, Dmitry Olshansky 
wrote:
 11/19/2012 7:18 PM, monarch_dodra пишет:
 On Monday, 19 November 2012 at 14:58:29 UTC, Andrei 
 Alexandrescu wrote:
 On 11/19/12 4:01 AM, monarch_dodra wrote:
 I kind of agree with Jonathan here.  property really shines 
 when you
 want to "add" an attribute to a struct.
I kind of agree with him, too, but it would be a mistake to not reckon a change in dynamics. UFCS makes all those extra parens just awkward, and people will vote with their code regardless whether some particular viewpoint from some particular angle considers the approach backwards. Andrei
One of the things that we may want to take into account, is that -property prevents any existing function from migrating to/from property. For example, if we want to make "retro" a property, we can't without breaking any and all UFCS usage of retro.
The major problem about property enforcement as it stands is that it breaks the duality of things like retro: a.retro vs retro(a) Both should be allowed as it's a matter of taste that shouldn't be enforced. A lot of new code uses a.retro and a lot of older code uses retro(a). If retro is property then only the first one compiles If retro is a function then only the second one compiles. Which obviously means property has to be reconsidered.
Hum... Perhaps you meant: a.retro vs a.retro() ??? Because "retro(a)" works regardless of the property.
Nov 19 2012
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
11/19/2012 9:58 PM, monarch_dodra пишет:
 On Monday, 19 November 2012 at 17:42:28 UTC, Dmitry Olshansky wrote:
 11/19/2012 7:18 PM, monarch_dodra пишет:
 On Monday, 19 November 2012 at 14:58:29 UTC, Andrei Alexandrescu wrote:
 On 11/19/12 4:01 AM, monarch_dodra wrote:
 I kind of agree with Jonathan here.  property really shines when you
 want to "add" an attribute to a struct.
I kind of agree with him, too, but it would be a mistake to not reckon a change in dynamics. UFCS makes all those extra parens just awkward, and people will vote with their code regardless whether some particular viewpoint from some particular angle considers the approach backwards. Andrei
One of the things that we may want to take into account, is that -property prevents any existing function from migrating to/from property. For example, if we want to make "retro" a property, we can't without breaking any and all UFCS usage of retro.
The major problem about property enforcement as it stands is that it breaks the duality of things like retro: a.retro vs retro(a) Both should be allowed as it's a matter of taste that shouldn't be enforced. A lot of new code uses a.retro and a lot of older code uses retro(a). If retro is property then only the first one compiles If retro is a function then only the second one compiles. Which obviously means property has to be reconsidered.
Hum... Perhaps you meant: a.retro vs a.retro()
This one too.
 Because "retro(a)" works regardless of the property.
Hm.. being a while since I tried to use -property switch. I thought it was also disallowed. Not so bad then I guess. Looking forward to DIP21. -- Dmitry Olshansky
Nov 19 2012
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, November 19, 2012 21:42:25 Dmitry Olshansky wrote:
 11/19/2012 7:18 PM, monarch_dodra =D0=BF=D0=B8=D1=88=D0=B5=D1=82:
 On Monday, 19 November 2012 at 14:58:29 UTC, Andrei Alexandrescu wr=
ote:
 On 11/19/12 4:01 AM, monarch_dodra wrote:
 I kind of agree with Jonathan here.  property really shines when =
you
 want to "add" an attribute to a struct.
=20 I kind of agree with him, too, but it would be a mistake to not re=
ckon
 a change in dynamics. UFCS makes all those extra parens just awkwa=
rd,
 and people will vote with their code regardless whether some
 particular viewpoint from some particular angle considers the appr=
oach
 backwards.
=20
 Andrei
=20 One of the things that we may want to take into account, is that -property prevents any existing function from migrating to/from property. For example, if we want to make "retro" a property, we ca=
n't
 without breaking any and all UFCS usage of retro.
=20 The major problem about property enforcement as it stands is that it=
 breaks the duality of things like retro:
 a.retro
 vs
 retro(a)
=20
 Both should be allowed as it's a matter of taste that shouldn't be
 enforced. A lot of new code uses a.retro and a lot of older code uses=
 retro(a).
=20
 If retro is property then only the first one compiles
 If retro is a function then only the second one compiles.
=20
 Which obviously means  property has to be reconsidered.
The thing is that if property is really an abstraction for variables, = then it=20 _doesn't_ make sense to allow both, because it's _not_ a matter of tast= e.=20 Either it's a variable, or it's a function. Not both. And if it's a var= iable,=20 then obviously no parens should be used with it. And if it's a function= , then=20 obviously parens should be used with it. If you're viewing it as just a way to not have to use parens on functio= ns,=20 then that's something else entirely. And if that's what we're looking t= o=20 support, then using property for that makes no sense at all. Personally, I hate the fact it's legal to have any kind of optional par= ens. I=20 think that it's incredibly sloppy and goes against the abstractions of=20= variables and functions. I'm all for forcing the full set of parens in = a long=20 chain of UFCS. But clearly plenty of other folks don't agree. Because of all of those folks, it may make sense to make it so that par= ens are=20 optional on functions but are outright verboten on property functions.= That=20 way, anyone wanting to use property for actual properties can do so wi= th=20 proper enforcement, but those who want to just leave parens off of norm= al=20 function calls can. I really don't like the idea, but at this point, I = think=20 that it's fairly clear that there are a lot of people who _like_ the sl= oppy=20 nature of being able to leave parens off much as a number of the rest o= f us=20 hate it. - Jonathan M Davis
Nov 19 2012
parent reply "Rob T" <rob ucora.com> writes:
On Monday, 19 November 2012 at 20:04:24 UTC, Jonathan M Davis 
wrote:
 The thing is that if  property is really an abstraction for 
 variables, then it
 _doesn't_ make sense to allow both, because it's _not_ a matter 
 of taste.
 Either it's a variable, or it's a function. Not both. And if 
 it's a variable,
 then obviously no parens should be used with it. And if it's a 
 function, then
 obviously parens should be used with it.
That makes perfect sense to me if that's what the meaning of property is supposed to be, and if so then it can constrain the usage to that of a variable, which currently is not the case.
 If you're viewing it as just a way to not have to use parens on 
 functions,
 then that's something else entirely. And if that's what we're 
 looking to
 support, then using  property for that makes no sense at all.
That makes sense to me as well, and indicates that the property topic is getting mixed up with another topic, which concerns the optional use of () for empty parameter lists. What may be forgotten, is that we currently have the ability to not only drop the (), but also to perform optional assignments, eg Foo = 23;, without defining a function Foo to be property. In one case we're talking about variable abstractions, and in another case we're talking about simply making () optional, these are two entirely separate topics that are mangled up together. I think you understand this already, but perhaps not everyone else does. To further complicate things, I find that when deciding to define a function as property or not is like trying to decide if Pluto is a planet or not, it's often not clear which way you should go, and that may be why I really did enjoy not having to specify property to make use of the semantics it (was supposed to) provide when and where I saw fit to do so.
 Personally, I hate the fact it's legal to have any kind of 
 optional parens. I
 think that it's incredibly sloppy and goes against the 
 abstractions of
 variables and functions. I'm all for forcing the full set of 
 parens in a long
 chain of UFCS. But clearly plenty of other folks don't agree.
I seriously don't think you should try to constrain coding style, instead it makes much more sense to provide the user with a means to constrain it themselves as they see fit. Look at languages that constrain coding style too much vs languages that don't, and consider the popularity among them. My two cents :) --rt
Nov 19 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, November 19, 2012 22:04:02 Rob T wrote:
 I seriously don't think you should try to constrain coding style,
 instead it makes much more sense to provide the user with a means
 to constrain it themselves as they see fit. Look at languages
 that constrain coding style too much vs languages that don't, and
 consider the popularity among them.
Excep that i don't think that it's really a question of style. It's treating a function as if it were a variable, when it's not only not a variable, but it's not even acting like one. It's implying that the code has one set of semantics when it has another. Dropping parens when specifically creating a function which is intended to emulate a variable makes sense. But dropping parens just because you feel like it then makes a function look like a variable when it's not and not intended to even act like one. That violates the very difference between function and variable on even a conceptual level. It would be one thing to make a particular character or sequence of characters optional when doing so doesn't make it look like it's something else entirely (e.g. optional braces don't make anything look like anything else - they just drop some characters, and they don't introduce any ambiguities in the process). But it's quite another to make those characters optional when they make one language construct look like another. - Jonathan M Davis
Nov 19 2012
next sibling parent reply "Rob T" <rob ucora.com> writes:
On Monday, 19 November 2012 at 21:44:35 UTC, Jonathan M Davis 
wrote:
 Excep that i don't think that it's really a question of style. 
 It's treating a
 function as if it were a variable, when it's not only not a 
 variable, but it's
 not even acting like one. It's implying that the code has one 
 set of semantics
 when it has another. Dropping parens when specifically creating 
 a function
 which is intended to emulate a variable makes sense. But 
 dropping parens just
 because you feel like it then makes a function look like a 
 variable when it's
 not and not intended to even act like one. That violates the 
 very difference
 between function and variable on even a conceptual level. It 
 would be one
 thing to make a particular character or sequence of characters 
 optional when
 doing so doesn't make it look like it's something else entirely
  (e.g.
 optional braces don't make anything look like anything else - 
 they just drop
 some characters, and they don't introduce any ambiguities in 
 the process). But
 it's quite another to make those characters optional when they 
 make one
 language construct look like another.

 - Jonathan M Davis
I see what you are saying. Consider this: property allows a function to behave as if it were a variable, so in that case we're effectively creating an alternate set of language constructs for at least some functions. The enforcement through property however constrains it to only behave as if it were a variable and not a function, there's no ambiguity in this case, and it's clearly intentional, not a mistake. Without property, but allowing the programmer to decide if, when, and where, a function may emulate a variable, and when it will not, may confuse some people and may also confuse the compiler in some cases, but it does offer the programmer additional flexibility that may prove to be useful, although it may also prove to be a costly mistake, and if so it may be a matter of how good the programmer is. All I know at this point is that because property was not fully implemented as originally intended, I was able to experience the flexibility, and personally I found it to be OK for whatever reason, esp wrt UFCS. I would still be happy to have property perform constraints to enforce a function to emulate a variable or to resolve ambiguities, and certainly for any function no matter where it may be declared. I can definitely see the value in that and I can't see any reason for not supporting it. Side Note: In some cases you may want a setter but no getter for write only variable emulation, or a setter but no getter for read only emulation. What is not so clear, is if optional () should be allowed or not, but I do understand the argument that it makes the code look better in some cases which in that case is a question of style rather than anything to do with property. Also do not forget that we can not only drop the (), but also perform assignments to functions that take in one variable, but I'm not sure if the return must be void for that to work. It seems strange to allow arbitrarily dual function/variable constructs for functions, but being strange does not necessarily mean it is wrong. I do wonder however, if there's something much more fundamental or generalized going on with this that can settle the question in clear terms? I fully understand the variable emulation argument, and it's seems to be sound, however imagine reversing the argument and suggesting that all (or some) variables should be enforced to emulate function calls with function. We've seen this being done in C++, where I can initialize a variable in multiple emulated ways: // class constructor emulation int x(42); // function emulation int y; x = y(42); // regular variable form int x = 42; I don't have an answer, but there may be more to the picture than we think. --rt
Nov 19 2012
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/19/12 5:23 PM, Rob T wrote:
 I don't have an answer, but there may be more to the picture than we think.
I agree. In particular I find it a specious argument to insist on religiously associating "()" with function calling and the lack thereof with variable access. I don't see myself, when seeing an expression like "generator(x, y, z).map!(x => x * x)()", going like "holy cow, good I saw those trailing parens, otherwise I would've sworn it was a variable". Trailing parens in UFCS chains are just warts, this is the reality. Let's deal with it. Andrei
Nov 19 2012
next sibling parent =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= <sludwig outerproduct.org> writes:
Am 20.11.2012 05:12, schrieb Andrei Alexandrescu:
 On 11/19/12 5:23 PM, Rob T wrote:
 I don't have an answer, but there may be more to the picture than we think.
I agree. In particular I find it a specious argument to insist on religiously associating "()" with function calling and the lack thereof with variable access. I don't see myself, when seeing an expression like "generator(x, y, z).map!(x => x * x)()", going like "holy cow, good I saw those trailing parens, otherwise I would've sworn it was a variable". Trailing parens in UFCS chains are just warts, this is the reality. Let's deal with it. Andrei
Isn't it more that they seem like warts whenever a parameterless (or pseudo-parameterless in the case of UFCS) template function is called, because template instantiations already look a lot like function calls? Anyway, my take on this is, while I find it a bit sad, that there is no visual distinction between variables and functions for various reasons, in the presence of properties this distinction has already gone long time ago. So realistically this argument has no weight anymore. Personally, I started to like a partially relaxed approach like the one Adam Ruppe describes a lot, so a DIP would definitely be a great step.
Nov 20 2012
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 20 November 2012 at 04:12:54 UTC, Andrei Alexandrescu 
wrote:
 On 11/19/12 5:23 PM, Rob T wrote:
 I don't have an answer, but there may be more to the picture 
 than we think.
I agree. In particular I find it a specious argument to insist on religiously associating "()" with function calling and the lack thereof with variable access. I don't see myself, when seeing an expression like "generator(x, y, z).map!(x => x * x)()", going like "holy cow, good I saw those trailing parens, otherwise I would've sworn it was a variable". Trailing parens in UFCS chains are just warts, this is the reality. Let's deal with it. Andrei
And what do you think about map!(x => x * x) = generator(x, y, z) ?
Dec 01 2012
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, December 02, 2012 07:49:52 deadalnix wrote:
 And what do you think about map!(x => x * x) = generator(x, y, z)
 ?
What's that even supposed to mean? map has been given no function argument either as UFCS or with a normal function call, so it's not being called. And even if it were, it wouldn't result in an lvalue, so putting it on the left of an assignment makes no sense. I have no idea what you're trying to do here. - Jonathan M Davis
Dec 01 2012
parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 2 December 2012 at 06:58:12 UTC, Jonathan M Davis 
wrote:
 On Sunday, December 02, 2012 07:49:52 deadalnix wrote:
 And what do you think about map!(x => x * x) = generator(x, y, 
 z)
 ?
What's that even supposed to mean? map has been given no function argument either as UFCS or with a normal function call, so it's not being called. And even if it were, it wouldn't result in an lvalue, so putting it on the left of an assignment makes no sense. I have no idea what you're trying to do here.
I want to express that regular function are really different than regular function calls. If map had to behave like a property, then the code above would be correct, and 100% equivalent to Andrei's snippet.
Dec 01 2012
prev sibling next sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 12/02/12 07:57, Jonathan M Davis wrote:
 On Sunday, December 02, 2012 07:49:52 deadalnix wrote:
 And what do you think about map!(x => x * x) = generator(x, y, z)
 ?
What's that even supposed to mean? map has been given no function argument either as UFCS or with a normal function call, so it's not being called. And even if it were, it wouldn't result in an lvalue, so putting it on the left of an assignment makes no sense. I have no idea what you're trying to do here.
void main() { import std.stdio; writeln!string = "Hello World!"; } // The explicit "!string" is only needed because of no IFTI, if 'writeln' was // a function instead of a template you could just call it like "writeln = "blah". Allowing that /by default/ does much more harm than good, proper property enforcement is necessary. Function calls go via '()'. Programmer can override when he knows better. UFCS doesn't change things. [1] artur [1] If you think the required '()' in UFCS chains look ugly, you're right, but the right fix isn't to butcher the language. '()' carry important information. Having a mode where function calls are made w/o the parens would be a good idea, but it should be limited to an explicit scope. ie something like "auto r = function {generator(x, y, z).map!(x => x * x)};", except 'function' keyword can't be overloaded like that, it's too long, and ()-less calls isn't the only change that could be done.
Dec 02 2012
next sibling parent reply "Rob T" <rob ucora.com> writes:
There's more than just  property that operate like variables.

Should we restrict this as well?

struct stdio
{
    void opAssign(T)( T a_arg )
    {
       writeln( a_arg );
    }
}

main()
{
    stdio writeln;
    writeln = "hellow world";
}

Conceptually, I don't see why we have to impose a difference 
between how variables are assigned and how functions are called.

A variable "=" assignment is simply a special case of a function 
call that is written for you by the compiler.

The example of opAssign shows that for some time now, there's 
been pressure to eliminate the difference in at least some cases, 
and allow the programmer to implement their own version of the 
assignment function call.

If you want to remove inconsistencies, then the way functions and 
variables are manipulated should be unified.

If someone can honestly demonstrate a non-subjective reason why 
there must be a difference between function call and variable 
assignments, please show it. So far I've only seen arguments that 
boil down to "I don't like it".

--rt
Dec 02 2012
parent reply "Regan Heath" <regan netmail.co.nz> writes:
On Sun, 02 Dec 2012 18:47:26 -0000, Rob T <rob ucora.com> wrote:
 If someone can honestly demonstrate a non-subjective reason why there  
 must be a difference between function call and variable assignments,  
 please show it. So far I've only seen arguments that boil down to "I  
 don't like it".
A variable assignment is in 99% of cases a simple operation. A function call is in 99% of cases a more complex operation. Being able to immediately "see" those costs is useful. A language which allows you to make variable assignments costly will be inherently harder to understand in terms of cost, than a language which does not. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Dec 02 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 12/02/2012 09:19 PM, Regan Heath wrote:
 On Sun, 02 Dec 2012 18:47:26 -0000, Rob T <rob ucora.com> wrote:
 If someone can honestly demonstrate a non-subjective reason why there
 must be a difference between function call and variable assignments,
 please show it. So far I've only seen arguments that boil down to "I
 don't like it".
A variable assignment is in 99% of cases a simple operation. A function call is in 99% of cases a more complex operation. Being able to immediately "see" those costs is useful. A language which allows you to make variable assignments costly will be inherently harder to understand in terms of cost, than a language which does not. R
Costs are understood by profiling and/or detailed analysis, not by looking at trivial syntactic properties.
Dec 02 2012
parent reply "Regan Heath" <regan netmail.co.nz> writes:
On Mon, 03 Dec 2012 04:02:15 -0000, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 12/02/2012 09:19 PM, Regan Heath wrote:
 On Sun, 02 Dec 2012 18:47:26 -0000, Rob T <rob ucora.com> wrote:
 If someone can honestly demonstrate a non-subjective reason why there
 must be a difference between function call and variable assignments,
 please show it. So far I've only seen arguments that boil down to "I
 don't like it".
A variable assignment is in 99% of cases a simple operation. A function call is in 99% of cases a more complex operation. Being able to immediately "see" those costs is useful. A language which allows you to make variable assignments costly will be inherently harder to understand in terms of cost, than a language which does not. R
Costs are understood by profiling and/or detailed analysis, not by looking at trivial syntactic properties.
Exact costs, yes. But syntactic properties can, and have historically also given a good indication of costs and this is useful. Removing that, is less than useful and potentially surprising. Compare that to what you gain from this change.. nothing useful that I can see. Making variable assignments and function calls look the same buys you nothing, you're trying to make apples and oranges look like oranges and hide all the nice, useful, detail and distinction you get from having both assignments (oranges) and function calls (apples) and all that they imply. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Dec 04 2012
parent reply "Rob T" <rob ucora.com> writes:
On Tuesday, 4 December 2012 at 21:58:49 UTC, Regan Heath wrote:
 Exact costs, yes.  But syntactic properties can, and have 
 historically also given a good indication of costs and this is 
 useful.  Removing that, is less than useful and potentially 
 surprising.

 Compare that to what you gain from this change.. nothing useful 
 that I can see.

 Making variable assignments and function calls look the same 
 buys you nothing, you're trying to make apples and oranges look 
 like oranges and hide all the nice, useful, detail and 
 distinction you get from having both assignments (oranges) and 
 function calls (apples) and all that they imply.

 R
You can make functions and vars look different through a naming convention, and do even more if you choose. The enforcement of the empty () as essentially an enforced naming convention. --rt
Dec 05 2012
parent "Regan Heath" <regan netmail.co.nz> writes:
On Wed, 05 Dec 2012 16:49:22 -0000, Rob T <rob ucora.com> wrote:

 On Tuesday, 4 December 2012 at 21:58:49 UTC, Regan Heath wrote:
 Exact costs, yes.  But syntactic properties can, and have historically  
 also given a good indication of costs and this is useful.  Removing  
 that, is less than useful and potentially surprising.

 Compare that to what you gain from this change.. nothing useful that I  
 can see.

 Making variable assignments and function calls look the same buys you  
 nothing, you're trying to make apples and oranges look like oranges and  
 hide all the nice, useful, detail and distinction you get from having  
 both assignments (oranges) and function calls (apples) and all that  
 they imply.

 R
You can make functions and vars look different through a naming convention, and do even more if you choose. The enforcement of the empty () as essentially an enforced naming convention.
Yes! R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Dec 05 2012
prev sibling next sibling parent reply "Rob T" <rob ucora.com> writes:
There's more than just  property that operate like variables.

Should we restrict this as well?

struct stdio
{
     void opAssign(T)( T a_arg )
     {
        writeln( a_arg );
     }
}

main()
{
     stdio writeln;
     writeln = "hellow world";
}

Conceptually, I don't see why we have to impose a difference
between how variables are assigned and how functions are called.

A variable "=" assignment is simply a special case of a function
call that is written for you by the compiler.

The example of opAssign shows that for some time now, there's
been pressure to eliminate the difference in at least some cases,
and allow the programmer to implement their own version of the
assignment function call.

If you want to remove inconsistencies, then the way functions and
variables are manipulated should be unified.

If someone can honestly demonstrate a non-subjective reason why
there must be a difference between function call and variable
assignments, please show it. So far I've only seen arguments that
boil down to "I don't like it".

--rt
Dec 02 2012
parent Artur Skawina <art.08.09 gmail.com> writes:
On 12/02/12 19:48, Rob T wrote:
 There's more than just  property that operate like variables.
 
 Should we restrict this as well?
 
 struct stdio
 {
     void opAssign(T)( T a_arg )
     {
        writeln( a_arg );
     }
 }
 
 main()
 {
     stdio writeln;
     writeln = "hellow world";
 }
 
 Conceptually, I don't see why we have to impose a difference
 between how variables are assigned and how functions are called.
 
 A variable "=" assignment is simply a special case of a function
 call that is written for you by the compiler.
 
 The example of opAssign shows that for some time now, there's
 been pressure to eliminate the difference in at least some cases,
 and allow the programmer to implement their own version of the
 assignment function call.
 
 If you want to remove inconsistencies, then the way functions and
 variables are manipulated should be unified.

 If someone can honestly demonstrate a non-subjective reason why
 there must be a difference between function call and variable
 assignments, please show it. So far I've only seen arguments that
 boil down to "I don't like it".
Do you seriously think that there is no difference and would like to have to decypher code like void main() { import std.stdio, std.math; writeln(sqrt=81); } ? Having assignments act as calls for every random function is insane. It can be done and is ok where the programmers decides this makes sense. Your above stdio example is not such a case. [1] artur [1] But thanks for sharing it, I would have probably never thought of using a static opAssign otherwise... struct stdout { static void opAssign(T...)(T args) { import std.stdio; writeln(args); } } void main() { stdout = "It's a strange world"; }
Dec 02 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 12/02/2012 12:36 PM, Artur Skawina wrote:
 On 12/02/12 07:57, Jonathan M Davis wrote:
 On Sunday, December 02, 2012 07:49:52 deadalnix wrote:
 And what do you think about map!(x => x * x) = generator(x, y, z)
 ?
What's that even supposed to mean? map has been given no function argument either as UFCS or with a normal function call, so it's not being called. And even if it were, it wouldn't result in an lvalue, so putting it on the left of an assignment makes no sense. I have no idea what you're trying to do here.
void main() { import std.stdio; writeln!string = "Hello World!"; } // The explicit "!string" is only needed because of no IFTI, if 'writeln' was // a function instead of a template you could just call it like "writeln = "blah". Allowing that /by default/ does much more harm than good,
It does neither harm nor good.
 proper property enforcement is necessary. Function calls go via '()'.
Programmer can override
 when he knows better.
The first and last sentence are in mutual contradiction.
 UFCS doesn't change things. [1]

 artur

 [1] If you think the required '()' in UFCS chains look ugly, you're right, but
the
 right fix isn't to butcher the language. '()' carry important information.
They do not, otherwise compilation could not succeed.
 Having a mode where function calls are made w/o the parens would be a good
idea, but it
 should be limited to an explicit scope. ie something like
 "auto r = function {generator(x, y, z).map!(x => x * x)};", except 'function'
keyword
 can't be overloaded like that, it's too long, and ()-less calls isn't the only
change
 that could be done.
That is terrible.
Dec 02 2012
parent Artur Skawina <art.08.09 gmail.com> writes:
On 12/03/12 05:10, Timon Gehr wrote:
 On 12/02/2012 12:36 PM, Artur Skawina wrote:
 On 12/02/12 07:57, Jonathan M Davis wrote:
 On Sunday, December 02, 2012 07:49:52 deadalnix wrote:
 And what do you think about map!(x => x * x) = generator(x, y, z)
 ?
What's that even supposed to mean? map has been given no function argument either as UFCS or with a normal function call, so it's not being called. And even if it were, it wouldn't result in an lvalue, so putting it on the left of an assignment makes no sense. I have no idea what you're trying to do here.
void main() { import std.stdio; writeln!string = "Hello World!"; } // The explicit "!string" is only needed because of no IFTI, if 'writeln' was // a function instead of a template you could just call it like "writeln = "blah". Allowing that /by default/ does much more harm than good,
It does neither harm nor good.
As long as nobody is (ab)using it. int f(int a) { return sqrt = a; } is not much different from abusing op overloading and is an equally bad idea. It shouldn't be allowed by /default/, which not enforcing property will lead to. Somebody reading that 'f()' definition should be able to rely on sqrt being a variable, possibly of a user defined type, even with an overloaded assignment operator, which could have side effects. Assuming that the type designer made sensible choices is relatively safe, assuming that every user will do the right thing won't work. What would be the rationale for allowing this syntax for calling every random function? Other than not having to declare it as a property when required.
 proper property enforcement is necessary. Function calls go via '()'.
Programmer can override
 when he knows better.
The first and last sentence are in mutual contradiction.
No, they are not, because enforcement is a requirement for control. And that has to be with the producer, not the consumer (ie determined by the function declaration, not individually at every call site).
 [1] If you think the required '()' in UFCS chains look ugly, you're right, but
the
 right fix isn't to butcher the language. '()' carry important information.
They do not, otherwise compilation could not succeed.
not required != unimportant. The compiler could for example in many cases figure out by itself that a missing (const) cast is necessary for some code to compile. That does not mean that it should insert them implicitly, w/o making sure doing so is both harmless and won't cause confusion.
 Having a mode where function calls are made w/o the parens would be a good
idea, but it
 should be limited to an explicit scope. ie something like
 "auto r = function {generator(x, y, z).map!(x => x * x)};", except 'function'
keyword
 can't be overloaded like that, it's too long, and ()-less calls isn't the only
change
 that could be done.
That is terrible.
Yes, it *is* terrible - the point was that it can be done differently and this could be a start for discussion. That kind of semi-dsl also allows for locally lifting other restrictions like order of evaluation etc w/o butchering the rest of the language. artur
Dec 03 2012
prev sibling parent reply "jerro" <a a.com> writes:
 [1] If you think the required '()' in UFCS chains look ugly, 
 you're right, but the
 right fix isn't to butcher the language. '()' carry important 
 information. Having
 a mode where function calls are made w/o the parens would be a 
 good idea, but it
 should be limited to an explicit scope. ie something like
 "auto r = function {generator(x, y, z).map!(x => x * x)};", 
 except 'function' keyword
 can't be overloaded like that, it's too long, and ()-less calls 
 isn't the only change
 that could be done.
I think having some kind of pipe operator would be a better solution. But it's probably too late to add any of those now.
Jan 29 2013
parent "jerro" <a a.com> writes:
 I think having some kind of pipe operator would be a better 
 solution. But it's probably too late to add any of those now.
I'm sorry, I didn't realize I was replying to a two months old post.
Jan 29 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/2/12 1:49 AM, deadalnix wrote:
 On Tuesday, 20 November 2012 at 04:12:54 UTC, Andrei Alexandrescu wrote:
 On 11/19/12 5:23 PM, Rob T wrote:
 I don't have an answer, but there may be more to the picture than we
 think.
I agree. In particular I find it a specious argument to insist on religiously associating "()" with function calling and the lack thereof with variable access. I don't see myself, when seeing an expression like "generator(x, y, z).map!(x => x * x)()", going like "holy cow, good I saw those trailing parens, otherwise I would've sworn it was a variable". Trailing parens in UFCS chains are just warts, this is the reality. Let's deal with it. Andrei
And what do you think about map!(x => x * x) = generator(x, y, z) ?
I think that ought to be disallowed. Andrei
Dec 02 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-11-19 23:23, Rob T wrote:

 Also do not forget that we can not only drop the (), but also perform
 assignments to functions that take in one variable, but I'm not sure if
 the return must be void for that to work. It seems strange to allow
 arbitrarily dual function/variable constructs for functions, but being
 strange does not necessarily mean it is wrong.
The return value doesn't have to be void. I always return the new value from my setters, to allow chained assignments. If chained assignment can't be used the property hasn't emulated a variable properly. class Foo { private int bar_; property int bar () { return bar_; } property int bar (int value) { return bar_ = value; } } auto foo = new Foo; int a = foo.bar = 3; Of course the correct solution would be to implement a form of property rewrite in the compiler. Transforming the following code: int a = foo.bar = 3; To: foo.bar = 3; int a = foo.bar; If "foo.bar" is a method/ property. -- /Jacob Carlborg
Nov 20 2012
prev sibling parent reply "thedeemon" <dlang thedeemon.com> writes:
On Monday, 19 November 2012 at 21:44:35 UTC, Jonathan M Davis 
wrote:
 Excep that i don't think that it's really a question of style. 
 It's treating a
 function as if it were a variable, when it's not only not a 
 variable, but it's
 not even acting like one. It's implying that the code has one 
 set of semantics when it has another.
This is just an old habit to see identifier with parens as a function call and identifier without parens as a variable, so calling functions without parens seem too unconventional to you. However there are many languages which dropped this tradition and they are known for being expressive and concise, that's why people love them. Recently we saw an article from Walter about component programming which one could say was really about function composition. It's really convenient to write code in conveyor-style, this is what we see often in functional languages, as well as some dynamic OO ones. For example, the task of reversing words in a string may look like: "one two three".split.map{|s| s.reverse}.join(' ') in Ruby print . unwords . map reverse . words $ "one two three" in Haskell "one two three" |> split " " |> List.map reverse |> String.join " " |> print_string in OCaml and something similar and even without dots in Scala. Ease of chaining functions together is one of the things that make those languages so pleasant to work with. I love to have the same in current D and it would be a pity to lose it due to a clash with some old-fashioned tradition.
Nov 19 2012
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/20/12 2:48 AM, thedeemon wrote:
[snip]
 "one two three".split.map{|s| s.reverse}.join(' ')
 in Ruby

 print . unwords . map reverse . words $ "one two three"
 in Haskell

 "one two three" |> split " " |> List.map reverse |> String.join " " |>
 print_string
 in OCaml
 and something similar and even without dots in Scala.
 Ease of chaining functions together is one of the things that make those
 languages so pleasant to work with. I love to have the same in current D
 and it would be a pity to lose it due to a clash with some old-fashioned
 tradition.
A very good argument. Thanks! Andrei
Nov 20 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-11-20 08:48, thedeemon wrote:

 This is just an old habit to see identifier with parens as a function
 call and identifier without parens as a variable, so calling functions
 without parens seem too unconventional to you. However there are many
 languages which dropped this tradition and they are known for being
 expressive and concise, that's why people love them. Recently we saw an
 article from Walter about component programming which one could say was
 really about function composition. It's really convenient to write code
 in conveyor-style, this is what we see often in functional languages, as
 well as some dynamic OO ones. For example, the task of reversing words
 in a string may look like:
I completely agree.
 "one two three".split.map{|s| s.reverse}.join(' ')
 in Ruby
In this particular case you can use a shorter form of the map call: "one two three".split.map(&:reverse).join(' ')
 print . unwords . map reverse . words $ "one two three"
 in Haskell

 "one two three" |> split " " |> List.map reverse |> String.join " " |>
 print_string
 in OCaml
 and something similar and even without dots in Scala.
Wouldn't the Scala syntax look fairly similar to Ruby: "one two three".split.map(reverse).join(' ')
 Ease of chaining functions together is one of the things that make those
 languages so pleasant to work with. I love to have the same in current D
 and it would be a pity to lose it due to a clash with some old-fashioned
 tradition.
I completely agree again. -- /Jacob Carlborg
Nov 20 2012
parent reply deadalnix <deadalnix gmail.com> writes:
Le 20/11/2012 04:33, Jacob Carlborg a écrit :
 On 2012-11-20 08:48, thedeemon wrote:

 This is just an old habit to see identifier with parens as a function
 call and identifier without parens as a variable, so calling functions
 without parens seem too unconventional to you. However there are many
 languages which dropped this tradition and they are known for being
 expressive and concise, that's why people love them. Recently we saw an
 article from Walter about component programming which one could say was
 really about function composition. It's really convenient to write code
 in conveyor-style, this is what we see often in functional languages, as
 well as some dynamic OO ones. For example, the task of reversing words
 in a string may look like:
I completely agree.
 "one two three".split.map{|s| s.reverse}.join(' ')
 in Ruby
In this particular case you can use a shorter form of the map call: "one two three".split.map(&:reverse).join(' ')
 print . unwords . map reverse . words $ "one two three"
 in Haskell

 "one two three" |> split " " |> List.map reverse |> String.join " " |>
 print_string
 in OCaml
 and something similar and even without dots in Scala.
Wouldn't the Scala syntax look fairly similar to Ruby: "one two three".split.map(reverse).join(' ')
Note the map(reverse) and not map(&reverse)
 Ease of chaining functions together is one of the things that make those
 languages so pleasant to work with. I love to have the same in current D
 and it would be a pity to lose it due to a clash with some old-fashioned
 tradition.
I completely agree again.
Nov 20 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-11-21 07:55, deadalnix wrote:

 Note the map(reverse) and not map(&reverse)
I said "fairly similar" not "exactly the same" :) -- /Jacob Carlborg
Nov 20 2012
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 21 November 2012 at 07:44:36 UTC, Jacob Carlborg 
wrote:
 On 2012-11-21 07:55, deadalnix wrote:

 Note the map(reverse) and not map(&reverse)
I said "fairly similar" not "exactly the same" :)
I don't understand why dropping () is that a big deal when dropping & isn't.
Nov 21 2012
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11/21/2012 06:53 PM, deadalnix wrote:
 On Wednesday, 21 November 2012 at 07:44:36 UTC, Jacob Carlborg wrote:
 On 2012-11-21 07:55, deadalnix wrote:

 Note the map(reverse) and not map(&reverse)
I said "fairly similar" not "exactly the same" :)
I don't understand why dropping () is that a big deal when dropping & isn't.
Relative frequencies. Amount of visual noise. People are used to it.
Nov 21 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-11-21 18:53, deadalnix wrote:

 I don't understand why dropping () is that a big deal when dropping &
 isn't.
Now I'm really confused. What did you mean when you original wrote: "Note the map(reverse) and not map(&reverse)" -- /Jacob Carlborg
Nov 21 2012
parent "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 21 November 2012 at 18:07:42 UTC, Jacob Carlborg 
wrote:
 On 2012-11-21 18:53, deadalnix wrote:

 I don't understand why dropping () is that a big deal when 
 dropping &
 isn't.
Now I'm really confused. What did you mean when you original wrote: "Note the map(reverse) and not map(&reverse)"
I meant that because of the fact that function isn't called implicitly, it is possible to pass it directly without having the & . The & is a source of noise as the () are and introduce really complicated rules in the language to know if funName have to be executed or not. Scala's design is consistent on this point. D's isn't because we pursue conflicting goals. Those have been conflated in a messy implementation defined behavior ATM. We have to accept to break some code here or to stick with current implementation and accept that is is inconsistent and messy (and sometime leading to very weird possibilities like Timon Gehr demonstrated).
Nov 21 2012
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 19/11/2012 06:58, Andrei Alexandrescu a écrit :
 On 11/19/12 4:01 AM, monarch_dodra wrote:
 I kind of agree with Jonathan here.  property really shines when you
 want to "add" an attribute to a struct.
I kind of agree with him, too, but it would be a mistake to not reckon a change in dynamics. UFCS makes all those extra parens just awkward, and people will vote with their code regardless whether some particular viewpoint from some particular angle considers the approach backwards. Andrei
As aid bunch of time, I'm pretty sure we can have a clean semantic and still allow mosts use of parenthsesless call using opDispatch .
Nov 19 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/20/12 12:24 AM, deadalnix wrote:
 Le 19/11/2012 06:58, Andrei Alexandrescu a écrit :
 On 11/19/12 4:01 AM, monarch_dodra wrote:
 I kind of agree with Jonathan here.  property really shines when you
 want to "add" an attribute to a struct.
I kind of agree with him, too, but it would be a mistake to not reckon a change in dynamics. UFCS makes all those extra parens just awkward, and people will vote with their code regardless whether some particular viewpoint from some particular angle considers the approach backwards. Andrei
As aid bunch of time, I'm pretty sure we can have a clean semantic and still allow mosts use of parenthsesless call using opDispatch .
Could you please give more detail? On first sight this seems to complicate the majority case for the benefit of a few. Andrei
Nov 19 2012
parent deadalnix <deadalnix gmail.com> writes:
Le 19/11/2012 21:53, Andrei Alexandrescu a écrit :
 On 11/20/12 12:24 AM, deadalnix wrote:
 Le 19/11/2012 06:58, Andrei Alexandrescu a écrit :
 On 11/19/12 4:01 AM, monarch_dodra wrote:
 I kind of agree with Jonathan here.  property really shines when you
 want to "add" an attribute to a struct.
I kind of agree with him, too, but it would be a mistake to not reckon a change in dynamics. UFCS makes all those extra parens just awkward, and people will vote with their code regardless whether some particular viewpoint from some particular angle considers the approach backwards. Andrei
As aid bunch of time, I'm pretty sure we can have a clean semantic and still allow mosts use of parenthsesless call using opDispatch .
Could you please give more detail? On first sight this seems to complicate the majority case for the benefit of a few. Andrei
consider the following opDispatch : auto opDispatch(string name, T, U...)(T function() t, U args) { return mixin("t()." ~ name ~ "(args)"); } I ommited to support delegates and to do the right checks in order to make the example obvious. With such opDispatch, it is easy to get an autoevaluation for chained functions call via UFCS. () is only required on the last one. I don't see how it can complicate the current situation. The current situation is like crazy complicated, and nobody is sure of what can be expected to be the correct behavior in many corner cases.
Nov 19 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 19/11/2012 00:45, thedeemon a écrit :
 On Monday, 19 November 2012 at 08:23:43 UTC, Jonathan M Davis wrote:
 On Monday, November 19, 2012 09:16:29 Rob T wrote:
 My guess is that if  property gets enforced, we'll see a lot of
 functions with empty parameter lists being defined as  property
 for the sole reason to get rid of having to type in the ().
Which completely violates the concept of a property in the first place. It's intended to be an abstraction for a variable. Using property just to get rid of parens would be like naming types with verbs instead of nouns. It's completely backwards. - Jonathan M Davis
I very much like the combination of UFCS, ranges and parens-free style which allows writing code like iota(0, 1000000).map!(to!string).retro.take(50).retro[10].writeln; So I like Andrei's idea to force property only for those functions where it's absolutely necessary to fight ambiguity.
With opDispatch and clear semantic, the following is doable : iota(0, 1000000).map!(to!string).retro.take(50).retro[10].writeln(); No need for an ambiguous situation where function get called implicitly.
Nov 19 2012
prev sibling parent reply "Rob T" <rob ucora.com> writes:
On Monday, 19 November 2012 at 08:23:43 UTC, Jonathan M Davis 
wrote:
 Which completely violates the concept of a property in the 
 first place. It's
 intended to be an abstraction for a variable. Using  property 
 just to get rid
 of parens would be like naming types with verbs instead of 
 nouns. It's
 completely backwards.

 - Jonathan M Davis
I know what you are saying, but I know that most people will usually follow the path of least resistance, so if a lot of people really dislike typing in () all over the place and are given a way out, then they'll likely take it, so long as it won't matter in any significant way in terms of practicality. Another case that I would say violates the property concept, is a getter property function that returns a non-const ref, and reusing the same property function as a setter (for cases where there's nothing to be done when setting). It is less work when you can get away with defining one property function that looks like two, even though it may be bad in some way, I expect it will be done often. I suppose with property enforcement in place, the compiler can be adjusted to prevent non-const ref return values for property getters. That would also make it a bit more difficult to specify property just to get rid of typing (). The big question is what do we gain and what do we lose from enforcements like this? It has to be worth doing, or it should not be done, Personally, I think we're much better off not attempting to enforce coding style through restrictions that could be viewed as unnecessary. --rt
Nov 19 2012
next sibling parent reply "sclytrack" <sclytrack thailand.com> writes:
So is it official? We keep the d1 syntax for none property 
functions? Even the assignment?

So for the dynamic stuff opDispatch only (for properties and 
methods)? The ()() syntax remains for the dynamic delegate 
properties.
Nov 19 2012
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, November 19, 2012 12:31:02 sclytrack wrote:
 So is it official? We keep the d1 syntax for none property
 functions? Even the assignment?
No. It's not official. No decision has been made. For the moment, nothing has changed about property. It may very well change, but nothing has happened but some discussion on the matter, and while Andrei is suggesting may very well be what happens, not everyone agrees with his assessment. We'll have to wait and see. - Jonathan M Davis
Nov 19 2012
prev sibling parent reply "Minas Mina" <minas_mina1990 hotmail.co.uk> writes:
Isn't it possible to have parentheses optional only for UFCS?

E.g.

Allow:
I 5.writeln

Dissallow:

void f()
{
	writeln("hi");
}

f; // this currently works


I don't know if this is possible to implement.
Dec 04 2012
next sibling parent reply Nick Treleaven <ntrel-public yahoo.co.uk> writes:
On 04/12/2012 16:24, Minas Mina wrote:
 Isn't it possible to have parentheses optional only for UFCS?

 E.g.

 Allow:
 I 5.writeln

 Dissallow:

 void f()
 {
      writeln("hi");
 }

 f; // this currently works


 I don't know if this is possible to implement.
I expect it is, perhaps by disallowing calling a property function with no arguments.
Dec 04 2012
next sibling parent "Michael" <pr m1xa.com> writes:
 void f()
 {
     writeln("hi");
 }

 f; // this currently works


 I don't know if this is possible to implement.
I expect it is, perhaps by disallowing calling a property function with no arguments.
It's regular function called as property [getter] of module. without () only to property. function without () - property - for simple tasks. function/procedure/action with () - for resource-intensive tasks.
Dec 04 2012
prev sibling parent "Michael" <pr m1xa.com> writes:
 void f()
 {
     writeln("hi");
 }

 f; // this currently works


 I don't know if this is possible to implement.
I expect it is, perhaps by disallowing calling a property function with no arguments.
It's regular function called as property [getter] of module. without () only to property. function without () - property - for simple tasks. function/procedure/action with () - for resource-intensive tasks.
Dec 04 2012
prev sibling next sibling parent "Rob T" <rob ucora.com> writes:
On Tuesday, 4 December 2012 at 16:24:27 UTC, Minas Mina wrote:
 Isn't it possible to have parentheses optional only for UFCS?

 E.g.

 Allow:
 I 5.writeln

 Dissallow:

 void f()
 {
 	writeln("hi");
 }

 f; // this currently works


 I don't know if this is possible to implement.
module main; void f() { writeln("hi"); } main.f; // OK or not? If we're to make the empty braces optional, we have to ask this question: What will enforcing the empty braces buy you? Based on the comments so far, all that it does is tell you at a glance that the symbol is a function call. Without the braces you'll have to dig a little deeper into the code to figure it out. So the () effectively serves the purpose of a naming convention for functions. However as was pointed out in this thread, there are a few real situations where even with () enforcement, you still won't necessarily know what the symbol represents without digging into the code, for example if property is enforced. There are arguments in favor of property enforcement, which is to encourage the programmer to think in terms of making a function behave like a variable and nothing else. It also discourages dropping the () elsewhere. The argument against property enforcement, is that it enforces a coding style on the programmer, which may be subjective, and not providing any real gain. What "bad" thing does () enforcement do? Based the comments, it seems that a lot of people really dislike the empty braces when chaining together multiple function calls, i.e., it looks ugly and is more effort for apparently no real gain, so it does not matter if they are UFCS calls or not, it's just ugly when chaining. The arguments against dropping the () when chaining, is that you loose the ability to see at a glance what is a function call and what is not, although with the exception of enforced property functions. I think the above sums up the arguments for and against, but maybe not. --rt
Dec 04 2012
prev sibling next sibling parent "Araq" <rumpf_a gmx.de> writes:
On Tuesday, 4 December 2012 at 16:24:27 UTC, Minas Mina wrote:
 Isn't it possible to have parentheses optional only for UFCS?
This is exactly what Nimrod does. ;-) The () can also be omitted in calls used as a statement (not as an expression). BTW Nimrod calls it "method call syntax"; there is hardly anything "uniform" in having the first argument in a special position...
Dec 04 2012
prev sibling next sibling parent "Rob T" <rob ucora.com> writes:
On Tuesday, 4 December 2012 at 16:24:27 UTC, Minas Mina wrote:
 Isn't it possible to have parentheses optional only for UFCS?

 E.g.

 Allow:
 I 5.writeln

 Dissallow:

 void f()
 {
 	writeln("hi");
 }

 f; // this currently works


 I don't know if this is possible to implement.
module main; void f() { writeln("hi"); } main.f; // OK or not? I think the argument for vs against is simply a coding style issue, some like dropping empty braces, some do not. --rt
Dec 04 2012
prev sibling next sibling parent reply "Rob T" <rob ucora.com> writes:
On Tuesday, 4 December 2012 at 16:24:27 UTC, Minas Mina wrote:
 Isn't it possible to have parentheses optional only for UFCS?

 E.g.

 Allow:
 I 5.writeln

 Dissallow:

 void f()
 {
 	writeln("hi");
 }

 f; // this currently works


 I don't know if this is possible to implement.
module main; void f() { writeln("hi"); } main.f; // OK or not? I think the argument for vs against is simply a coding style issue, some like dropping empty braces, some do not. --rt
Dec 04 2012
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 4 December 2012 at 18:28:55 UTC, Rob T wrote:
 On Tuesday, 4 December 2012 at 16:24:27 UTC, Minas Mina wrote:
 Isn't it possible to have parentheses optional only for UFCS?

 E.g.

 Allow:
 I 5.writeln

 Dissallow:

 void f()
 {
 	writeln("hi");
 }

 f; // this currently works


 I don't know if this is possible to implement.
module main; void f() { writeln("hi"); } main.f; // OK or not? I think the argument for vs against is simply a coding style issue, some like dropping empty braces, some do not. --rt
It is also a ambiguity issue and the extra need of & to not call the function (which also introduce ambiguity).
Dec 05 2012
parent reply "Rob T" <rob ucora.com> writes:
On Wednesday, 5 December 2012 at 18:32:16 UTC, deadalnix wrote:
 I think the argument for vs against is simply a coding style
 issue, some like dropping empty braces, some do not.

 --rt
It is also a ambiguity issue
The () acts like a naming convention, and with or without enforcement you are free to choose whatever naming convention you desire, thus reducing ambiguity.
 and the extra need of & to not call the function (which also 
 introduce ambiguity).
If you dislike it, rather than use &, I suppose you can add on the () instead. In fact you can specify () everywhere if you prefer. --rt
Dec 05 2012
parent "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 5 December 2012 at 20:27:18 UTC, Rob T wrote:
 On Wednesday, 5 December 2012 at 18:32:16 UTC, deadalnix wrote:
 I think the argument for vs against is simply a coding style
 issue, some like dropping empty braces, some do not.

 --rt
It is also a ambiguity issue
The () acts like a naming convention, and with or without enforcement you are free to choose whatever naming convention you desire, thus reducing ambiguity.
 and the extra need of & to not call the function (which also 
 introduce ambiguity).
If you dislike it, rather than use &, I suppose you can add on the () instead. In fact you can specify () everywhere if you prefer.
I'll do like I've not read anything and let you rethink about that.
Dec 05 2012
prev sibling next sibling parent "Rob T" <rob ucora.com> writes:
On Tuesday, 4 December 2012 at 16:24:27 UTC, Minas Mina wrote:
 Isn't it possible to have parentheses optional only for UFCS?

 E.g.

 Allow:
 I 5.writeln

 Dissallow:

 void f()
 {
 	writeln("hi");
 }

 f; // this currently works


 I don't know if this is possible to implement.
module main; void f() { writeln("hi"); } main.f; // OK or not? I think the argument for vs against is simply a coding style issue, some like dropping empty braces, some do not. --rt
Dec 04 2012
prev sibling next sibling parent "Rob T" <rob ucora.com> writes:
On Tuesday, 4 December 2012 at 16:24:27 UTC, Minas Mina wrote:
 Isn't it possible to have parentheses optional only for UFCS?

 E.g.

 Allow:
 I 5.writeln

 Dissallow:

 void f()
 {
 	writeln("hi");
 }

 f; // this currently works


 I don't know if this is possible to implement.
module main; void f() { writeln("hi"); } main.f; // OK or not? I think the argument for vs against is simply a coding style issue, some like dropping empty braces, some do not. --rt
Dec 04 2012
prev sibling next sibling parent "Rob T" <rob ucora.com> writes:
On Tuesday, 4 December 2012 at 16:24:27 UTC, Minas Mina wrote:
 Isn't it possible to have parentheses optional only for UFCS?

 E.g.

 Allow:
 I 5.writeln

 Dissallow:

 void f()
 {
 	writeln("hi");
 }

 f; // this currently works


 I don't know if this is possible to implement.
module main; void f() { writeln("hi"); } main.f; // OK or not? I think the argument for vs against is simply a coding style issue, some like dropping empty braces, some do not. --rt
Dec 04 2012
prev sibling next sibling parent "Araq" <rumpf_a gmx.de> writes:
On Tuesday, 4 December 2012 at 16:24:27 UTC, Minas Mina wrote:
 Isn't it possible to have parentheses optional only for UFCS?
That's exactly what Nimrod does ;-). It also allows to leave out the () for calls used as a statement (not as an expression). BTW Nimrod calls it "method call syntax" as there is hardly anything "uniform" about putting the first argument in a special position.
Dec 04 2012
prev sibling parent "Mike Parker" <aldacron gmail.com> writes:
On Tuesday, 4 December 2012 at 16:24:27 UTC, Minas Mina wrote:
 Isn't it possible to have parentheses optional only for UFCS?

 E.g.

 Allow:
 I 5.writeln

 Dissallow:

 void f()
 {
 	writeln("hi");
 }

 f; // this currently works


 I don't know if this is possible to implement.
+1 5.writeln is going to be translated by the compiler as writeln(5) anyway, so I think this is a great compromise.
Dec 04 2012
prev sibling parent "eles" <eles eles.com> writes:
On Monday, 19 November 2012 at 06:53:46 UTC, Andrei Alexandrescu 
wrote:
 On 11/19/12 1:16 AM, Jonathan M Davis wrote:
 On Monday, November 19, 2012 07:02:03 Rob T wrote:
I think UFCS changes the playfield quite a lot. Code using UFCS looks a whole lot crappier with a bunch of arbitrary extra parens.
As I've been saying: make parens optional only if the function is followed by a dot. Otherwise, make parens compulsory for functions: function1.function2.function3(); //allowed function1(); //allowed function1; // forbidden property-ies should be forbidden to use paranthesis, no matter the context.
Jan 29 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/19/12 1:02 AM, Rob T wrote:
 So what's up with  property?
It's a mistake on top of another. We need to redesign it to such that the keyword ' property' is only required in cases that otherwise would be ambiguous (functions returning functions). Andrei
Nov 18 2012
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Monday, 19 November 2012 at 06:52:11 UTC, Andrei Alexandrescu 
wrote:
 We need to redesign it to such that the keyword ' property' is 
 only required in cases that otherwise would be ambiguous 
 (functions returning functions).
There's a fairly easy way to do this, thanks to the property word: 1) Any function without property remains exactly the same as it is now. Parens are *not* required on them. 2) Any function with property is rewritten into a call immediately. Therefore, putting () is naturally an error or delegate call because of the return value. property int foo() {} foo; // rewritten into foo() transparently foo(); // since foo is already foo(), this becomes foo()() - an error because you cannot call an int like a function The only potential for code breakage here is on stuff marked property, which if you have been marking it on semantic properties already (NOT on places where you just wanted appease the -property switch's idiotic rules), should be fine. If in doubt, leave property off. That leaves things exactly as they are.
Nov 19 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/19/12 8:18 AM, Adam D. Ruppe wrote:
 On Monday, 19 November 2012 at 06:52:11 UTC, Andrei Alexandrescu wrote:
 We need to redesign it to such that the keyword ' property' is only
 required in cases that otherwise would be ambiguous (functions
 returning functions).
There's a fairly easy way to do this, thanks to the property word:
[snip] Would you please start a DIP with a paste of this idea? Andrei
Nov 19 2012
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Monday, 19 November 2012 at 15:01:36 UTC, Andrei Alexandrescu 
wrote:
 Would you please start a DIP with a paste of this idea?
here it is: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP21 I tried to implement this a while ago and hit some pain after some early success. The pain was trying to get assignments to work without breaking other cases like returning ref. My plan was to make any reference to a property change to a CallExp or whatever. But if you do that and it is on the left hand side of an assignment, you do the wrong thing. foo = foo + 1; should generally become: foo(foo() + 1); but if there isn't a setter, we should leave it as foo() = foo() + 1; and finding the setter is a bit of a pain. Then, of course, we ideally want foo += 1 to work too.. Maybe someone who knows the compiler better than me will make it look easy though.
Nov 19 2012
next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Monday, 19 November 2012 at 18:02:06 UTC, Adam D. Ruppe wrote:
 On Monday, 19 November 2012 at 15:01:36 UTC, Andrei 
 Alexandrescu wrote:
 Would you please start a DIP with a paste of this idea?
here it is: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP21
Thanks a lot for doing this! It's a pity that the last bigger discussion didn't lead anywhere, I don't think there was much disagreement. Hopefully, having a DIP to discuss will catalyze the process a bit. David
Nov 19 2012
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 19/11/2012 10:02, Adam D. Ruppe a écrit :
 On Monday, 19 November 2012 at 15:01:36 UTC, Andrei Alexandrescu wrote:
 Would you please start a DIP with a paste of this idea?
here it is: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP21 I tried to implement this a while ago and hit some pain after some early success. The pain was trying to get assignments to work without breaking other cases like returning ref. My plan was to make any reference to a property change to a CallExp or whatever. But if you do that and it is on the left hand side of an assignment, you do the wrong thing. foo = foo + 1; should generally become: foo(foo() + 1); but if there isn't a setter, we should leave it as foo() = foo() + 1; and finding the setter is a bit of a pain. Then, of course, we ideally want foo += 1 to work too..
This make it impossible to only define a getter only when one want to return by reference.
 Maybe someone who knows the compiler better than me will make it look
 easy though.
Nov 19 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, November 19, 2012 21:31:09 deadalnix wrote:
 Le 19/11/2012 10:02, Adam D. Ruppe a =C3=A9crit :
 On Monday, 19 November 2012 at 15:01:36 UTC, Andrei Alexandrescu wr=
ote:
 Would you please start a DIP with a paste of this idea?
=20 here it is: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP21 =20 I tried to implement this a while ago and hit some pain after some =
early
 success. The pain was trying to get assignments to work without bre=
aking
 other cases like returning ref.
=20
 My plan was to make any reference to a  property change to a CallEx=
p or
 whatever. But if you do that and it is on the left hand side of an
 assignment, you do the wrong thing.
=20
 foo =3D foo + 1;
=20
 should generally become:
=20
 foo(foo() + 1);
=20
 but if there isn't a setter, we should leave it as foo() =3D foo() =
+ 1;
 and finding the setter is a bit of a pain. Then, of course, we idea=
lly
 want foo +=3D 1 to work too..
=20 This make it impossible to only define a getter only when one want to=
 return by reference.
Returning by reference generally already defeats the purpose of definin= g a=20 property function in the first place. Certainly, if you return by ref, = it=20 _definitely_ defeats the purpose of only defining a getter. By returnin= g by ref=20 from a getter, you've not only implicitly declared a setter, but you've= made=20 it impossible to verify anything about what's being set, because it's g= oing=20 through the ref rather than through an actual setter. - Jonathan M Davis
Nov 19 2012
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 20 November 2012 at 05:31:09 UTC, deadalnix wrote:
 This make it impossible to only define a getter only when one 
 want to return by reference.
If there isn't a setter, you don't change things. If setter is present: foo = foo + 1; // becomes: foo(foo() + 1); If setter is not present: foo = foo + 1; // becomes: foo() = foo() + 1; If foo returns an rvalue, this is a natural error. If it returns ref, it works fine.
Nov 20 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-11-19 19:02, Adam D. Ruppe wrote:
 On Monday, 19 November 2012 at 15:01:36 UTC, Andrei Alexandrescu wrote:
 Would you please start a DIP with a paste of this idea?
here it is: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP21 I tried to implement this a while ago and hit some pain after some early success. The pain was trying to get assignments to work without breaking other cases like returning ref. My plan was to make any reference to a property change to a CallExp or whatever. But if you do that and it is on the left hand side of an assignment, you do the wrong thing. foo = foo + 1; should generally become: foo(foo() + 1); but if there isn't a setter, we should leave it as foo() = foo() + 1; and finding the setter is a bit of a pain. Then, of course, we ideally want foo += 1 to work too..
It would be really nice if we could implement property rewriting in the compiler.
 Maybe someone who knows the compiler better than me will make it look
 easy though.
Should this be allowed for functions that isn't marked with property: foo = 3; -- /Jacob Carlborg
Nov 20 2012
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 20 November 2012 at 12:44:44 UTC, Jacob Carlborg 
wrote:
 Should this be allowed for functions that isn't marked with 
  property:

 foo = 3;
Hell no!
Nov 20 2012
parent "Regan Heath" <regan netmail.co.nz> writes:
On Tue, 20 Nov 2012 13:20:10 -0000, monarch_dodra <monarchdodra gmail.com>  
wrote:

 On Tuesday, 20 November 2012 at 12:44:44 UTC, Jacob Carlborg wrote:
 Should this be allowed for functions that isn't marked with  property:

 foo = 3;
Hell no!
+1 I think this "feature" should just be removed, and property implemented fully/correctly. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Nov 20 2012
prev sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 20 November 2012 at 12:44:44 UTC, Jacob Carlborg 
wrote:
 Should this be allowed for functions that isn't marked with 
  property:

 foo = 3;
Yes. We should *only* be changing the way property is implemented. (Namely, actually implementing it!) Don't want to break existing code. The new changes must be opt in. If there's both an property setter and a regular function, the property should be used here.
Nov 20 2012
next sibling parent reply "Regan Heath" <regan netmail.co.nz> writes:
On Tue, 20 Nov 2012 13:26:15 -0000, Adam D. Ruppe  
<destructionator gmail.com> wrote:

 On Tuesday, 20 November 2012 at 12:44:44 UTC, Jacob Carlborg wrote:
 Should this be allowed for functions that isn't marked with  property:

 foo = 3;
Yes. We should *only* be changing the way property is implemented. (Namely, actually implementing it!) Don't want to break existing code. The new changes must be opt in.
Usually I'd agree but this is a case of a wart we should just remove IMO. The fix for breaking cases is simple, add property.
 If there's both an  property setter and a regular function, the property  
 should be used here.
Agreed. But it's waay clearer whats going on if property is required to call functions using this syntax. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Nov 20 2012
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 20 November 2012 at 13:50:10 UTC, Regan Heath wrote:
 Usually I'd agree but this is a case of a wart we should just 
 remove IMO.  The fix for breaking cases is simple, add 
  property.
meh, I sometimes use it, but if overloading on property works, that's easy enough to allow both ways. I use it in some big chaining things: Element.make("div").className("foo").value = "bar"; vs auto element = Element.make("div"); element.className = "foo"; element.value = "bar"; Using one or the other depending on if I have a variable name there anyway. This would be arguably *better* with separation, but I don't have the level of hatred for one function used both ways (on setter nor getter) the way a lot of people do.
Nov 20 2012
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
BTW I've been pasting some of my posts into the wiki thing

http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP21#section4


Kinda sloppy to just paste, but this way everything on my mind is 
in one place so we don't have to reread the thread to get it 
together.

Of course, being a wiki, feel free to do the same with anything 
you want to note.
Nov 20 2012
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 20 November 2012 at 14:13:51 UTC, Adam D. Ruppe wrote:
 On Tuesday, 20 November 2012 at 13:50:10 UTC, Regan Heath wrote:
 Usually I'd agree but this is a case of a wart we should just 
 remove IMO.  The fix for breaking cases is simple, add 
  property.
meh, I sometimes use it, but if overloading on property works, that's easy enough to allow both ways. I use it in some big chaining things: Element.make("div").className("foo").value = "bar"; vs auto element = Element.make("div"); element.className = "foo"; element.value = "bar";
That's a good point. If the property is a "setter", then both "value = bla" and "value(bla)" is legal. If the property is a getter, then only "=" works. But I think it would be fine if "value(bla)" were tanslated to "value = bla" in that case. However, if you allow "foo = rhs" => "foo(rhs)" on a non-propety, then code like this becomes legal: writeln = 5; And that's bullshit.
Nov 20 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/20/2012 02:49 PM, Regan Heath wrote:
 On Tue, 20 Nov 2012 13:26:15 -0000, Adam D. Ruppe
 <destructionator gmail.com> wrote:

 On Tuesday, 20 November 2012 at 12:44:44 UTC, Jacob Carlborg wrote:
 Should this be allowed for functions that isn't marked with  property:

 foo = 3;
Yes. We should *only* be changing the way property is implemented. (Namely, actually implementing it!) Don't want to break existing code. The new changes must be opt in.
Usually I'd agree but this is a case of a wart we should just remove IMO. The fix for breaking cases is simple, add property.
 If there's both an  property setter and a regular function, the
 property should be used here.
Agreed. But it's waay clearer whats going on if property is required to call functions using this syntax. R
Not really. property T front(T)(T[] arr) { return arr[0]; } [1,2,3,4].front; front = [1,2,3,4];
Nov 20 2012
parent reply deadalnix <deadalnix gmail.com> writes:
Le 20/11/2012 12:18, Timon Gehr a écrit :
 On 11/20/2012 02:49 PM, Regan Heath wrote:
 On Tue, 20 Nov 2012 13:26:15 -0000, Adam D. Ruppe
 <destructionator gmail.com> wrote:

 On Tuesday, 20 November 2012 at 12:44:44 UTC, Jacob Carlborg wrote:
 Should this be allowed for functions that isn't marked with  property:

 foo = 3;
Yes. We should *only* be changing the way property is implemented. (Namely, actually implementing it!) Don't want to break existing code. The new changes must be opt in.
Usually I'd agree but this is a case of a wart we should just remove IMO. The fix for breaking cases is simple, add property.
 If there's both an  property setter and a regular function, the
 property should be used here.
Agreed. But it's waay clearer whats going on if property is required to call functions using this syntax. R
Not really. property T front(T)(T[] arr) { return arr[0]; } [1,2,3,4].front; front = [1,2,3,4];
I conclude that property should be limited to member function or UFCS calls. Otherwize, we get really weird stuffs going on.
Nov 20 2012
parent "Regan Heath" <regan netmail.co.nz> writes:
On Wed, 21 Nov 2012 06:07:51 -0000, deadalnix <deadalnix gmail.com> wrot=
e:

 Le 20/11/2012 12:18, Timon Gehr a =E9crit :
 On 11/20/2012 02:49 PM, Regan Heath wrote:
 On Tue, 20 Nov 2012 13:26:15 -0000, Adam D. Ruppe
 <destructionator gmail.com> wrote:

 On Tuesday, 20 November 2012 at 12:44:44 UTC, Jacob Carlborg wrote:=
 Should this be allowed for functions that isn't marked with  =
  property:

 foo =3D 3;
Yes. We should *only* be changing the way property is implemented.=
 (Namely, actually implementing it!)

 Don't want to break existing code. The new changes must be opt in.
Usually I'd agree but this is a case of a wart we should just remove=
 IMO. The fix for breaking cases is simple, add  property.

 If there's both an  property setter and a regular function, the
 property should be used here.
Agreed. But it's waay clearer whats going on if property is require=
d
 to call functions using this syntax.

 R
Not really. property T front(T)(T[] arr) { return arr[0]; } [1,2,3,4].front; front =3D [1,2,3,4];
I conclude that property should be limited to member function or UFCS=
=
 calls. Otherwize, we get really weird stuffs going on.
Such was my assumption in this case :p R -- = Using Opera's revolutionary email client: http://www.opera.com/mail/
Nov 21 2012
prev sibling parent reply "Rob T" <rob ucora.com> writes:
On Tuesday, 20 November 2012 at 13:26:17 UTC, Adam D. Ruppe wrote:
 On Tuesday, 20 November 2012 at 12:44:44 UTC, Jacob Carlborg 
 wrote:
 Should this be allowed for functions that isn't marked with 
  property:

 foo = 3;
Yes. We should *only* be changing the way property is implemented. (Namely, actually implementing it!) Don't want to break existing code. The new changes must be opt in.
Here's another way to test if the idea is sound, by asking a few questions: For some time, we've had the unrestricted ability to drop empty "()" and perform assignments to any function with appropriate sig. Has there been a chorus of complaints about having it? Any flood of problems caused by it? More importantly, how many of us are now making good use out of it without even a seconds thought? How many of us would really miss it if taken out? I still think there's a lot more to the picture, but I cannot yet pin it down well enough to say what it is. I'll try and share my thoughts, so that maybe someone more knowledgeable than me can figure it out. What is really bugging me, is that I know there's something more generalized going on here that we may have an opportunity to take advantage of, before things get cast in "unbreakable" stone, so to speak. I've been asking myself some questions, off the wall stuff, not necessarily possible for D due to practical limitations, but perhaps possible for E: 1) Why must a variable operate as it does and why must a function operate as it does? Are the two "things" really all that much different? I can successfully imagine that a variable is a function wrapper around a data store. 2) We're allowing only some functions to operate like variables, and this is because not all functions are allowed to operate in this way due to their parameter signature. Specifically, if the function has more than one parameter, it cannot be used as if it were a variable. Example: // We can do this void Foo( int ){ ... }; int Foo(){ ... }; Foo = 5; int Y = Foo; // so why not something like this? void Foo( int, string, float ){ ... }; ( int, string, float )Foo(){ ... }; Foo = { 1, "test", 3.456 }; { someint, somestring, sonefloat } = Foo; Why must we be limited to a single return and a single assignment value? (I recall this topic was brought up before, and I know we can use struct to emulate a similar effect) 3) If some functions can operate like variables, then why must no variable be able to operate like some functions? This is not allowed in D: int x, y; x(1); y = x(); y(x()); Why must this be so? 4) Which syntax or constructs are easier to understand, and which are not, given the context they are used in? If we had choice, will the context prefer one syntax over another in terms of clarity? If we don't have choice, then the context may enforce poor clarity in some cases. 5) We really enjoy the power we get from generic templates, yet the generic abilities of templates may possibly be lessened considerably because of the incompatibility between variables and functions, and I would also say classes and structs, although with UFCS the situation has improved (which may be why we like having them so much). 6) What advantage do we get by making variables and functions incompatible with each other (in terms with how they are manipulated or operated on), and what advantages could we get if we made them fully compatible (or at least more compatible). Hopefully some of these questions will provide food for some thought on the property matter. --rt
Nov 20 2012
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
Just a quick thought... it's not like a = 10 has no way to 
trigger a function anyway.

opAssign does it. Is that evil? This discussion kinda reminds me 
of some of the C++ arguments over operator overloading. They 
argue overloaded operators are evil because they don't look like 
function calls... but I think most of us agree that is generally 
useful.

D's properties of course aren't exactly the same but I think 
there's some similarities there that matter.
Nov 20 2012
prev sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 20 November 2012 at 18:06:22 UTC, Rob T wrote:
 Here's another way to test if the idea is sound, by asking a 
 few questions:
After thinking about it a bit more, I think there may be two conflicting notions: a) The use of optional parenthesis. b) The property switch, which allows a function to emulate an attribute, namelly, allow writting "bla = a.foo;" or "a.foo = 5;", when "foo" isn't actually an attribute of a. I *could* see parenthesis being optional, but I'll never accept "a.foo = 5" calling "a.foo(5)" if "foo" isn't attribute qualified.
Nov 20 2012
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, November 20, 2012 19:48:01 monarch_dodra wrote:
 On Tuesday, 20 November 2012 at 18:06:22 UTC, Rob T wrote:
 Here's another way to test if the idea is sound, by asking a
 few questions:
After thinking about it a bit more, I think there may be two conflicting notions: a) The use of optional parenthesis. b) The property switch, which allows a function to emulate an attribute, namelly, allow writting "bla = a.foo;" or "a.foo = 5;", when "foo" isn't actually an attribute of a.
Yes, you basically have folks who want to have strictly defined properties simply want to leave off parens (especially when they're using UFCS and already forced to provide a template argument - e.g. with map or filter or whatnot). On some level, they can coexist, and on some level, they're conflicting notions. Given the fact that this subject is extremely devisive, I suspect that the best that we can hope for at this point is for lax property enforcement - that is that it's enforced that property functions are used as properties but there is no enforcement that non- property functions be called with parens. We might be able to further restrict them so that they can't be used with the setter syntax (making it so that they must be property for that to work), but with UFCS and the use of templated functions taking predicates, dropping parens is way too popular to disallow it, much as I personally hate the idea. - Jonathan M Davis
Nov 20 2012
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 20 November 2012 at 19:06:22 UTC, Jonathan M Davis 
wrote:
 Given the fact that this subject is extremely devisive, I 
 suspect that the
 best that we can hope for at this point is for lax property 
 enforcement
property shouldn't be about enforcement. This is the fundamental flaw in the -property switch. While I think you and I are talking about the same goal, this is an important distinction to make: the fix isn't syntax. It is a semantic rewrite. After referencing a property is rewritten to be a call, the syntax will just work: property int foo() {} int a = foo(); // the error here is NOT "you must not use () on properties". It is "type int is not callable" This is something that's bothered me about the property debate since day one: we spend all this time talking about syntax.... but that's a side effect, not the core question.
Nov 20 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, November 20, 2012 20:12:56 Adam D. Ruppe wrote:
 On Tuesday, 20 November 2012 at 19:06:22 UTC, Jonathan M Davis
 
 wrote:
 Given the fact that this subject is extremely devisive, I
 suspect that the
 best that we can hope for at this point is for lax property
 enforcement
property shouldn't be about enforcement. This is the fundamental flaw in the -property switch. While I think you and I are talking about the same goal, this is an important distinction to make: the fix isn't syntax. It is a semantic rewrite. After referencing a property is rewritten to be a call, the syntax will just work: property int foo() {} int a = foo(); // the error here is NOT "you must not use () on properties". It is "type int is not callable" This is something that's bothered me about the property debate since day one: we spend all this time talking about syntax.... but that's a side effect, not the core question.
It's the same result. property means that the function is treated as a variable, so it doesn't make sense that parens be used. If the error treats it like a variable to the point that it complains about trying to use parens on the variable rather than the fact that you tried to use parens on an property function, all the better. - Jonathan M Davis
Nov 20 2012
prev sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 20 November 2012 at 19:12:58 UTC, Adam D. Ruppe wrote:
 On Tuesday, 20 November 2012 at 19:06:22 UTC, Jonathan M Davis 
 wrote:
 Given the fact that this subject is extremely devisive, I 
 suspect that the
 best that we can hope for at this point is for lax property 
 enforcement
property shouldn't be about enforcement. This is the fundamental flaw in the -property switch. While I think you and I are talking about the same goal, this is an important distinction to make: the fix isn't syntax. It is a semantic rewrite. After referencing a property is rewritten to be a call, the syntax will just work: property int foo() {} int a = foo(); // the error here is NOT "you must not use () on properties". It is "type int is not callable"
Yes
 This is something that's bothered me about the  property debate 
 since day one: we spend all this time talking about syntax.... 
 but that's a side effect, not the core question.
+1
Nov 20 2012
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 11/20/12, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 I suspect that the
 best that we can hope for at this point is for lax property enforcement -
 that is that it's enforced that  property functions are used as properties but
 there is no enforcement that non- property functions be called with parens.
Here's a good reason why the latter isn't the best idea: http://d.puremagic.com/issues/show_bug.cgi?id=2159 The reporter made the mistake of issuing a function call instead of taking an address of a function, which in turn invoked a different function overload with the temporary result.
Dec 01 2012
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2012-11-19 06:52:11 +0000, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 On 11/19/12 1:02 AM, Rob T wrote:
 So what's up with  property?
It's a mistake on top of another. We need to redesign it to such that the keyword ' property' is only required in cases that otherwise would be ambiguous (functions returning functions).
…or functions returning a type with an opCall. What about template functions with a parametrized return type that will sometime be ambiguous and sometime not depending on the template parameters? -- Michel Fortin michel.fortin michelf.ca http://michelf.ca/
Nov 19 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/19/12 12:30 PM, Michel Fortin wrote:
 On 2012-11-19 06:52:11 +0000, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 On 11/19/12 1:02 AM, Rob T wrote:
 So what's up with  property?
It's a mistake on top of another. We need to redesign it to such that the keyword ' property' is only required in cases that otherwise would be ambiguous (functions returning functions).
…or functions returning a type with an opCall. What about template functions with a parametrized return type that will sometime be ambiguous and sometime not depending on the template parameters?
Let's put all of these cases in a DIP so we can analyze them. Thanks, Andrei
Nov 19 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
Why don't we just outright disallow expression-statements?

After all,

      2 + 3;

should not be a valid statement, and so

      foo.property;

should not be, either.
Nov 19 2012
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 19 November 2012 at 18:21:55 UTC, Mehrdad wrote:
 Why don't we just outright disallow expression-statements?

 After all,

      2 + 3;

 should not be a valid statement, and so

      foo.property;

 should not be, either.
Hmmm I would say if it's const/immutable and pure then it would be an error (Side effects considered after all), otherwise popFront may not work (it is a property I believe...right?). So let's assume I make some struct to call the PC Speaker (for whatever reason) then the following would break. struct PCSpeaker { int dingsCalled; void ding() property { dingsCalled++; //some low level calls } } However if it was... void ding() property const pure We know there's no side effects (and it can't modify the struct), which then 'ding' could be an error on it's own (Although without a return value that would make the signature completely useless).
Nov 19 2012
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 19 November 2012 at 18:58:21 UTC, Era Scarecrow wrote:
 On Monday, 19 November 2012 at 18:21:55 UTC, Mehrdad wrote:
 Why don't we just outright disallow expression-statements?

 After all,

     2 + 3;

 should not be a valid statement, and so

     foo.property;

 should not be, either.
Hmmm I would say if it's const/immutable and pure then it would be an error (Side effects considered after all), otherwise popFront may not work (it is a property I believe...right?).
... wrong ;) front is a property. popFront is a method.
  So let's assume I make some struct to call the PC Speaker (for 
 whatever reason) then the following would break.

 struct PCSpeaker {
   int dingsCalled;
   void ding()  property {
     dingsCalled++;
     //some low level calls
   }
 }

  However if it was...

   void ding()  property const pure

  We know there's no side effects (and it can't modify the 
 struct), which then 'ding' could be an error on it's own 
 (Although without a return value that would make the signature 
 completely useless).
You could argue that since a property-function is meant to emulate an attribute, that calling one and doing nothing is *always* wrong, regardless of side effect. I mean, in the sense that doing the side effect would make no sense if there is no consumer for the side effect in question. Back to retro: I think that it actually could be an attribute. In that case, when you write: a.retro; then there is no consumer, and it creates a compile error. After thinking about more, I think a great definition of property would be "a function that returns a value that *must* be consumed". This would give it more power than the mere parenthesis, no-parenthesis status: Imagine "chain" property-attributed. In that case: chain(a, b); This would fail to compile, because there is no consumer for chain, regardless of side effect...
Nov 19 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
On Monday, 19 November 2012 at 20:00:27 UTC, monarch_dodra wrote:
 You could argue that since a property-function is meant to 
 emulate an attribute, that calling one and doing nothing is 
 *always* wrong, regardless of side effect.
That's EXACTLY what I'm saying. foo.property; is ALWAYS wrong semantically speaking, regardless of what it _could_ or _happens_ to do if it was/is defined. So even if popFront() was a property, my point would be that it should not be a property in the first place. It's like saying you should be able to add integers and function pointers just because they're both integers underneath. Sure, the machine can do it, but we disallow it because it makes no sense. Ditto here.
Nov 19 2012
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 18/11/2012 22:52, Andrei Alexandrescu a écrit :
 On 11/19/12 1:02 AM, Rob T wrote:
 So what's up with  property?
It's a mistake on top of another. We need to redesign it to such that the keyword ' property' is only required in cases that otherwise would be ambiguous (functions returning functions). Andrei
It isn't the only ambiguous case.
Nov 19 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/20/12 12:28 AM, deadalnix wrote:
 Le 18/11/2012 22:52, Andrei Alexandrescu a écrit :
 On 11/19/12 1:02 AM, Rob T wrote:
 So what's up with  property?
It's a mistake on top of another. We need to redesign it to such that the keyword ' property' is only required in cases that otherwise would be ambiguous (functions returning functions). Andrei
It isn't the only ambiguous case.
That's why it's good to enumerate them all in http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP21. Thanks, Andrei
Nov 19 2012
parent reply deadalnix <deadalnix gmail.com> writes:
Le 19/11/2012 21:55, Andrei Alexandrescu a écrit :
 On 11/20/12 12:28 AM, deadalnix wrote:
 Le 18/11/2012 22:52, Andrei Alexandrescu a écrit :
 On 11/19/12 1:02 AM, Rob T wrote:
 So what's up with  property?
It's a mistake on top of another. We need to redesign it to such that the keyword ' property' is only required in cases that otherwise would be ambiguous (functions returning functions). Andrei
It isn't the only ambiguous case.
That's why it's good to enumerate them all in http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP21. Thanks, Andrei
I'm not sure how it fit in the DIP but &funName is ambiguous when funName return a reference. In general, mixes of returning callables or references, properties, auto calling functions and &syntax does a really bad mix.
Nov 19 2012
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 20 November 2012 at 06:06:21 UTC, deadalnix wrote:
 I'm not sure how it fit in the DIP but &funName is ambiguous 
 when funName return a reference.
We can just define this away: &funName if it isn't a property is the address of the function. If it is a property, ALL operations work on the return value, so it is rewritten as &(funName()).
Nov 20 2012
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 20 November 2012 at 13:35:14 UTC, Adam D. Ruppe wrote:
 On Tuesday, 20 November 2012 at 06:06:21 UTC, deadalnix wrote:
 I'm not sure how it fit in the DIP but &funName is ambiguous 
 when funName return a reference.
We can just define this away: &funName if it isn't a property is the address of the function.
So this is impossible to get the address of the returned reference.
 If it is a  property, ALL operations work on the return value, 
 so it is rewritten as &(funName()).
I agree that this is ho it should work.
Nov 20 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/20/2012 09:56 PM, deadalnix wrote:
 On Tuesday, 20 November 2012 at 13:35:14 UTC, Adam D. Ruppe wrote:
 On Tuesday, 20 November 2012 at 06:06:21 UTC, deadalnix wrote:
 I'm not sure how it fit in the DIP but &funName is ambiguous when
 funName return a reference.
We can just define this away: &funName if it isn't a property is the address of the function.
So this is impossible to get the address of the returned reference.
&funName()
 If it is a  property, ALL operations work on the return value, so it
 is rewritten as &(funName()).
I agree that this is ho it should work.
+1.
Nov 20 2012
parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 20 November 2012 at 21:19:20 UTC, Timon Gehr wrote:
 On 11/20/2012 09:56 PM, deadalnix wrote:
 On Tuesday, 20 November 2012 at 13:35:14 UTC, Adam D. Ruppe 
 wrote:
 On Tuesday, 20 November 2012 at 06:06:21 UTC, deadalnix wrote:
 I'm not sure how it fit in the DIP but &funName is ambiguous 
 when
 funName return a reference.
We can just define this away: &funName if it isn't a property is the address of the function.
So this is impossible to get the address of the returned reference.
&funName()
So now funName and funName are not equivalent anymore. Special cases should be removed, not added.
 If it is a  property, ALL operations work on the return 
 value, so it
 is rewritten as &(funName()).
I agree that this is ho it should work.
+1.
Nov 20 2012
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, December 02, 2012 01:16:40 Andrej Mitrovic wrote:
 On 11/20/12, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 I suspect that the
 best that we can hope for at this point is for lax property enforcement -
 that is that it's enforced that  property functions are used as properties
 but there is no enforcement that non- property functions be called with
 parens.
Here's a good reason why the latter isn't the best idea: http://d.puremagic.com/issues/show_bug.cgi?id=2159 The reporter made the mistake of issuing a function call instead of taking an address of a function, which in turn invoked a different function overload with the temporary result.
I'd _love_ to make it illegal to call non-property functions without parens, and there are definitely folks around here who agree with me, including some on the Phobos dev team (e.g. Steven has always agreed with me when this has come up), but there are enough folks around here here who like to call functions without parens - especially with UFCS and templated functions like map or filter - that I don't think that that's going to fly at this point. Maybe if Andrei agreed it could happen, but he's hated the idea of property practically from the get-go, and when you combine that with the facts that strengthening property enforcement as originally intended would break a lot of code at this point and that Walter absolutely hates breaking people's code for pratically any reason whatsoever, I expect that Walter would be against it too. And with both of them against it, it just wouldn't happen. The workaround for the bug in question is to not overload functions that take function pointers with an overload that takes something other than a function pointer or delegate. Even that's not perfect, because a function could return a function pointer or delegate, but at this point, I just don't see Andrei and Walter agreeing to the level of property enforcement required to stop it, even if they had agreed to it in the past. UFCS seems to be the feature that puts the nail in the coffin of that idea, because people don't want to do stuff like range.filter!(a => a.func() < 2)() but would rather do range.filter!(a => a.func() < 2). - Jonathan M Davis
Dec 01 2012
next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 2 December 2012 at 01:04:03 UTC, Jonathan M Davis 
wrote:
 On Sunday, December 02, 2012 01:16:40 Andrej Mitrovic wrote:
 On 11/20/12, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 I suspect that the
 best that we can hope for at this point is for lax property 
 enforcement -
 that is that it's enforced that  property functions are used 
 as properties
 but there is no enforcement that non- property functions be 
 called with
 parens.
Here's a good reason why the latter isn't the best idea: http://d.puremagic.com/issues/show_bug.cgi?id=2159 The reporter made the mistake of issuing a function call instead of taking an address of a function, which in turn invoked a different function overload with the temporary result.
I'd _love_ to make it illegal to call non-property functions without parens, and there are definitely folks around here who agree with me, including some on the Phobos dev team (e.g. Steven has always agreed with me when this has come up), but there are enough folks around here here who like to call functions without parens - especially with UFCS and templated functions like map or filter - that I don't think that that's going to fly at this point.
As said before a lot of such usages can be made valid with a sane semantic using opDispatch. BTW, I can't edit in the wiki? When I try to do so, it says me that deadalnix is an invalid username. If I need to register, I didn't found out how.
Dec 01 2012
parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 12/2/12, deadalnix <deadalnix gmail.com> wrote:
 BTW, I can't edit in the wiki? When I try to do so, it says me
 that deadalnix is an invalid username. If I need to register, I
 didn't found out how.
It requires a silly CamelCase style username. You can try and edit the new wiki though: http://dwiki.kimsufi.thecybershadow.net/Main_Page
Dec 02 2012
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 01 Dec 2012 20:03:21 -0500, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 I'd _love_ to make it illegal to call non-property functions without  
 parens,
 and there are definitely folks around here who agree with me, including  
 some on
 the Phobos dev team (e.g. Steven has always agreed with me when this has  
 come
 up), but there are enough folks around here here who like to call  
 functions
 without parens - especially with UFCS and templated functions like map or
 filter - that I don't think that that's going to fly at this point.
Oh, shit. I missed another important property discussion. OK, I will say my peace: The issue I have with not implementing this is takes power away from the designer. There are three intentions when creating a function w/ regards to properties: 1. You intend the function to be called without parentheses to clarify it is a property. 2. You intend the function to be only called with parentheses to clarify it is a function. 3. You don't care whether it's called with parentheses or not, because the name of the function is clearly a property or a function. These distinctions are important because of the human meaning of the function. i.e. x.read() vs. x.read. The former looks to me like "read using x", the latter looks like "is x read." With property, the idea was to implement 1 and 2, and leave nothing for Things like map or filter, which clearly aren't properties by their name/usage. I had a compromise that void parameterless functions could be unambiguously called without parentheses. For example, if x.read() doesn't return a value, then the statement: x.read; Can't really be misinterpreted as "is x read" because the code isn't using the (implied) result. So that is why I always thought, make non-property functions require parentheses. But here we are almost 4? years later and still have the same situation. I give. As long as we can't call arbitrary functions as setters, I think the other failures of allowing the choice of removing parentheses are far The proposed DIP does not look bad, I say do it. -Steve
Jan 27 2013
next sibling parent reply Robert <jfanatiker gmx.at> writes:
 property use:

I'd like to point out, that regardless of the "with parens/without
parens" stuff, marking properties with  property makes sense. So that
tools and frameworks can recognize them as such. This also implies that
fields that are meant as properties should be declared  property and the
compiler should generate getter/setter so it behaves exactly like a
manually created property. May I add this to DIP21?

Having the compiler lower the following:

 property int a;

to

private int __a;

 property int a() {
return __a;
}
 property int a(int new_a) {
  __a=new_a;
  return __a;
}

would make properties and property declared fields really exchangeable,
namely you can no longer take the reference of an  property field, just
like you can't take the address of a property with get/set.

Best regards,

Robert

On Sun, 2013-01-27 at 22:24 -0500, Steven Schveighoffer wrote:
 On Sat, 01 Dec 2012 20:03:21 -0500, Jonathan M Davis <jmdavisProg gmx.com>  
 wrote:
 
 I'd _love_ to make it illegal to call non-property functions without  
 parens,
 and there are definitely folks around here who agree with me, including  
 some on
 the Phobos dev team (e.g. Steven has always agreed with me when this has  
 come
 up), but there are enough folks around here here who like to call  
 functions
 without parens - especially with UFCS and templated functions like map or
 filter - that I don't think that that's going to fly at this point.
Oh, shit. I missed another important property discussion. OK, I will say my peace: The issue I have with not implementing this is takes power away from the designer. There are three intentions when creating a function w/ regards to properties: 1. You intend the function to be called without parentheses to clarify it is a property. 2. You intend the function to be only called with parentheses to clarify it is a function. 3. You don't care whether it's called with parentheses or not, because the name of the function is clearly a property or a function. These distinctions are important because of the human meaning of the function. i.e. x.read() vs. x.read. The former looks to me like "read using x", the latter looks like "is x read." With property, the idea was to implement 1 and 2, and leave nothing for Things like map or filter, which clearly aren't properties by their name/usage. I had a compromise that void parameterless functions could be unambiguously called without parentheses. For example, if x.read() doesn't return a value, then the statement: x.read; Can't really be misinterpreted as "is x read" because the code isn't using the (implied) result. So that is why I always thought, make non-property functions require parentheses. But here we are almost 4? years later and still have the same situation. I give. As long as we can't call arbitrary functions as setters, I think the other failures of allowing the choice of removing parentheses are far The proposed DIP does not look bad, I say do it. -Steve
Jan 28 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-28 12:44, Robert wrote:
  property use:

 I'd like to point out, that regardless of the "with parens/without
 parens" stuff, marking properties with  property makes sense. So that
 tools and frameworks can recognize them as such.
I completely agree. I have created a struct called "attribute" only to be used as an attribute for other types that should only be attributes: struct attribute {} attribute struct foo {} Even though attribute in this case doesn't to anything it shows the intent clearly. Same thing why I like explicit interfaces and abstract classes compared with C++.
 This also implies that
 fields that are meant as properties should be declared  property and the
 compiler should generate getter/setter so it behaves exactly like a
 manually created property. May I add this to DIP21?

 Having the compiler lower the following:

  property int a;

 to

 private int __a;

  property int a() {
 return __a;
 }
  property int a(int new_a) {
    __a=new_a;
    return __a;
 }
I would love that. But the setter should return void and the compiler should to property rewrites. -- /Jacob Carlborg
Jan 28 2013
next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 28 January 2013 at 12:31:35 UTC, Jacob Carlborg wrote:
 On 2013-01-28 12:44, Robert wrote:
  property use:

 I'd like to point out, that regardless of the "with 
 parens/without
 parens" stuff, marking properties with  property makes sense. 
 So that
 tools and frameworks can recognize them as such.
I completely agree. I have created a struct called "attribute" only to be used as an attribute for other types that should only be attributes: struct attribute {} attribute struct foo {} Even though attribute in this case doesn't to anything it shows the intent clearly. Same thing why I like explicit interfaces and abstract classes compared with C++.
 This also implies that
 fields that are meant as properties should be declared 
  property and the
 compiler should generate getter/setter so it behaves exactly 
 like a
 manually created property. May I add this to DIP21?

 Having the compiler lower the following:

  property int a;

 to

 private int __a;

  property int a() {
 return __a;
 }
  property int a(int new_a) {
   __a=new_a;
   return __a;
 }
I would love that. But the setter should return void and the compiler should to property rewrites.
Returning void instead of int in the example break assignment chaining a = b = c. Besides, how such implicitly defined functions may call user defined code (check input validity, call events, etc.)?
Jan 28 2013
next sibling parent reply "Dicebot" <m.strashun gmail.com> writes:
On Monday, 28 January 2013 at 14:00:16 UTC, Maxim Fomin wrote:
 Returning void instead of int in the example break assignment 
 chaining a = b = c. Besides, how such implicitly defined 
 functions may call user defined code (check input validity, 
 call events, etc.)?
It should not if evaluating the value of (b = c) will call getter for b.
Jan 28 2013
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 28 January 2013 at 14:09:20 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 14:00:16 UTC, Maxim Fomin wrote:
 Returning void instead of int in the example break assignment 
 chaining a = b = c. Besides, how such implicitly defined 
 functions may call user defined code (check input validity, 
 call events, etc.)?
It should not if evaluating the value of (b = c) will call getter for b.
Why getter and not setter? Expression a = b = c = d should call getter for d and setter for rest of them. And if c setter returns void the chain breaks. struct S { int _priv; property void /*int*/foo(int i) //uncommment to fix { _priv = i; //return i; } property int foo() { return _priv; } } void main() { int a, b, c; a = b = c; S s1, s2, s3; s1.foo = s2.foo = s3.foo = 1; }
Jan 28 2013
parent reply "Dicebot" <m.strashun gmail.com> writes:
On Monday, 28 January 2013 at 14:28:30 UTC, Maxim Fomin wrote:
 On Monday, 28 January 2013 at 14:09:20 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 14:00:16 UTC, Maxim Fomin wrote:
 Returning void instead of int in the example break assignment 
 chaining a = b = c. Besides, how such implicitly defined 
 functions may call user defined code (check input validity, 
 call events, etc.)?
It should not if evaluating the value of (b = c) will call getter for b.
Why getter and not setter? Expression a = b = c = d should call getter for d and setter for rest of them. And if c setter returns void the chain breaks.
"a = b" calls setter "(a = b)" calls setter first, getter second "x = b = c" is same as "x = (b = c)" thus calls setter, then getter and then setter again I don't know how it is done know, but that is quite logical C-like approach based on the fact that result of expression (a = b) is equal to a.
Jan 28 2013
next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Monday, 28 January 2013 at 14:38:19 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 14:28:30 UTC, Maxim Fomin wrote:
 On Monday, 28 January 2013 at 14:09:20 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 14:00:16 UTC, Maxim Fomin wrote:
 Returning void instead of int in the example break 
 assignment chaining a = b = c. Besides, how such implicitly 
 defined functions may call user defined code (check input 
 validity, call events, etc.)?
It should not if evaluating the value of (b = c) will call getter for b.
Why getter and not setter? Expression a = b = c = d should call getter for d and setter for rest of them. And if c setter returns void the chain breaks.
"a = b" calls setter "(a = b)" calls setter first, getter second "x = b = c" is same as "x = (b = c)" thus calls setter, then getter and then setter again I don't know how it is done know, but that is quite logical C-like approach based on the fact that result of expression (a = b) is equal to a.
It is not that obvious, as the result of a = b is also equal to b.
Jan 28 2013
parent "Dicebot" <m.strashun gmail.com> writes:
On Monday, 28 January 2013 at 14:44:15 UTC, deadalnix wrote:
 It is not that obvious, as the result of a = b is also equal to 
 b.
AFAIR it was defined strictly in C standard to be one two. Do not remember which one and do not have my trustful standard pdf nearby.
Jan 28 2013
prev sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 28 January 2013 at 14:38:19 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 14:28:30 UTC, Maxim Fomin wrote:
 On Monday, 28 January 2013 at 14:09:20 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 14:00:16 UTC, Maxim Fomin wrote:
 Returning void instead of int in the example break 
 assignment chaining a = b = c. Besides, how such implicitly 
 defined functions may call user defined code (check input 
 validity, call events, etc.)?
It should not if evaluating the value of (b = c) will call getter for b.
Why getter and not setter? Expression a = b = c = d should call getter for d and setter for rest of them. And if c setter returns void the chain breaks.
"a = b" calls setter
Agree.
 "(a = b)" calls setter first, getter second
How it can call setter for a if b is not evaluated? This expression is rewritten to setter function call with argument that getter provides.
 "x = b = c" is same as "x = (b = c)" thus calls setter, then 
 getter and then setter again
It should be rewritten to a.setter(b.setter(c.getter()))
 I don't know how it is done know, but that is quite logical 
 C-like approach based on the fact that result of expression (a 
 = b) is equal to a.
Yes, that is why if setter for "a" defaults to void and not to typeof(b) assignment chaining is broken.
Jan 28 2013
next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 28 January 2013 at 15:05:21 UTC, Maxim Fomin wrote:
 On Monday, 28 January 2013 at 14:38:19 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 14:28:30 UTC, Maxim Fomin wrote:
 On Monday, 28 January 2013 at 14:09:20 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 14:00:16 UTC, Maxim Fomin 
 wrote:
 Returning void instead of int in the example break 
 assignment chaining a = b = c. Besides, how such implicitly 
 defined functions may call user defined code (check input 
 validity, call events, etc.)?
It should not if evaluating the value of (b = c) will call getter for b.
Why getter and not setter? Expression a = b = c = d should call getter for d and setter for rest of them. And if c setter returns void the chain breaks.
"a = b" calls setter
Agree.
Correction: assuming b is a variable, not property.
Jan 28 2013
prev sibling parent reply "Dicebot" <m.strashun gmail.com> writes:
On Monday, 28 January 2013 at 15:05:21 UTC, Maxim Fomin wrote:
 It should be rewritten to a.setter(b.setter(c.getter()))
That is exactly the problem. "a = b = c" should be rewritten as: b.set(c.get()); a.set(b.get()); // or a.set(c.get()); do not remember C rules
Jan 28 2013
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 28 January 2013 at 15:31:48 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 15:05:21 UTC, Maxim Fomin wrote:
 It should be rewritten to a.setter(b.setter(c.getter()))
That is exactly the problem. "a = b = c" should be rewritten as: b.set(c.get()); a.set(b.get()); // or a.set(c.get()); do not remember C rules
From ISO C Assignment operators chapter: "An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after the assignment,111) but is not an lvalue. The type of an assignment expression is the type the left operand would have after lvalue conversion. The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced.". So, in right-associative expression a = b = c, at first subexpression b = c is evaluated to b.set(c.get). Than value of this expression (note, that evaluated expression is not b, it is b = c) is assigned to a. How it can be done if b.set() returns void? Than expression a = (b = c) is evaluated to a.set( b = c) which is (a.setter(b.setter(c.getter)) c, b = c which is not a = b = c in the presence of properties.
Jan 28 2013
parent reply "Dicebot" <m.strashun gmail.com> writes:
On Monday, 28 January 2013 at 16:50:37 UTC, Maxim Fomin wrote:
 Than value of this expression (note, that evaluated expression 
 is not b, it is b = c) is assigned to a.
Quoting you (that was exactly part of standard I was referring too): "assignment expression has the value of the left operand" Left operand for (b = c) is b. Thus (b = c) has value of b. Value of b is b.getter(). Thus compiler is re-writing it wrong if we copy C rules.
 b.setter cannot be called prior to b.getter as in your example 

 expression a = c, b = c which is not a = b = c in the presence 
 of properties.
What sequence rules are you speaking about?
Jan 28 2013
next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 28 January 2013 at 16:55:40 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 16:50:37 UTC, Maxim Fomin wrote:
 Than value of this expression (note, that evaluated expression 
 is not b, it is b = c) is assigned to a.
Quoting you (that was exactly part of standard I was referring too): "assignment expression has the value of the left operand" Left operand for (b = c) is b. Thus (b = c) has value of b. Value of b is b.getter(). Thus compiler is re-writing it wrong if we copy C rules.
You are mixing value of expression and expression itself. If assignment expression has value of right operand, it does not mean that in complex assignment like a = b = c , right part of second assignment disappears and it becomes a = b. It is still a = b = c , and a is assigned to value of the whole expression b = c, not just value of b. This means it is a.setter((b = c)) = > a.setter(b.setter(c.getter)). Note, that original program does exactly what is required by ISO C.
 b.setter cannot be called prior to b.getter as in your example 

 expression a = c, b = c which is not a = b = c in the presence 
 of properties.
What sequence rules are you speaking about?
About that side effects are sequenced after evaluation, but it is actually irrelevant, because b.getter is not called.
Jan 28 2013
prev sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 28 January 2013 at 16:55:40 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 16:50:37 UTC, Maxim Fomin wrote:
 Than value of this expression (note, that evaluated expression 
 is not b, it is b = c) is assigned to a.
Quoting you (that was exactly part of standard I was referring too): "assignment expression has the value of the left operand" Left operand for (b = c) is b. Thus (b = c) has value of b. Value of b is b.getter(). Thus compiler is re-writing it wrong if we copy C rules.
Applying your logic: Left operand for a = (b = c) is a. Thus a has value of (b = c). Value of b = c is b.setter(c.getter()).
Jan 28 2013
parent reply "Dicebot" <m.strashun gmail.com> writes:
On Monday, 28 January 2013 at 17:20:13 UTC, Maxim Fomin wrote:
 ...
Those are C rules, do not forget it. Thus value of (b = c) IS equivalent to value of b when lvalues are considered. And you are perfectly allowed to forget about c and do a = b after b = c was evaluated. It is plain old data, after all, if b = c is not interchangeable with b, something is wrong. At least I see nothing in standard that proves your statement.
 Applying your logic:

 Left operand for a = (b = c) is a. Thus a has value of (b = c). 
 Value of b = c is b.setter(c.getter()).
You are applying it wrong. Thing of it as of recursion. 1) evaluate "a = b = c" 2) evaluate a.set( (b = c).get() ), result of 1 will be a.get() ( if needed ) 3) evaluate "b = c" 4) evaluate b.set( c.get() ), result of 3 will be b.get() ( if needed ) 5) combine: a.set( b.set( c.get() ), b.get() ) Note that evaluation order for comma expression is defined, so "c.get() ), b.get()" is valid and correct code.
Jan 28 2013
parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 28 January 2013 at 17:41:07 UTC, Dicebot wrote:
 On Monday, 28 January 2013 at 17:20:13 UTC, Maxim Fomin wrote:
 ...
Those are C rules, do not forget it. Thus value of (b = c) IS equivalent to value of b when lvalues are considered. And you are perfectly allowed to forget about c and do a = b after b = c was evaluated. It is plain old data, after all, if b = c is not interchangeable with b, something is wrong. At least I see nothing in standard that proves your statement.
You are still breaking expression a = b = c and mixing terms of value of expression and expression itself.
 Applying your logic:

 Left operand for a = (b = c) is a. Thus a has value of (b = 
 c). Value of b = c is b.setter(c.getter()).
You are applying it wrong. Thing of it as of recursion.
I applied exactly as you did.
 1) evaluate "a = b = c"
 2) evaluate a.set( (b = c).get() ), result of 1 will be a.get() 
 ( if needed )
.get() is wrong here. Expression is a = b = c, not a = ( (b = c).get ))
 3) evaluate "b = c"
 4) evaluate b.set( c.get() ), result of 3 will be b.get() ( if 
 needed )
 5) combine: a.set( b.set( c.get() ), b.get() )
This breaks requirement from quoted paragraph that side effects are sequenced after value computations on both operands: computing value of b (b.get) happened after updating value (b.set). In Bugzilla there were close to this case like following (do not struct S { int a; int b; int c; } ... S s1, s2; s1 = { 1, s1.a 2 } Compiler was wrongly applied side effects before evaluating s1.a (it should be zero, not 1).
 Note that evaluation order for comma expression is defined, so 
 "c.get() ), b.get()" is valid and correct code.
Well, discussion went repetitive - I still insists that a = b = c should be evaluated as it is currently a.set(b=c) = > program also behaves as I understand rules: using System; using System.Collections.Generic; using System.Linq; using System.Text; class S { int _i; public int i { get { Console.WriteLine("getter"); return _i; } set { Console.WriteLine("setter"); _i = value; } } } namespace ConsoleApplication1 { class Program { static void Main(string[] args) { S s1 = new S() , s2 = new S(), s3 = new S(); s1.i = s2.i = s3.i; } } } getter setter setter
Jan 28 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
They don't. If you want such behaviour, you would write your own setter
getter, with  property attribute, just like you do now.

Best regards,

Robert

On Mon, 2013-01-28 at 15:00 +0100, Maxim Fomin wrote:
 Besides, how such implicitly defined 
 functions may call user defined code (check input validity, call 
 events, etc.)?
Jan 28 2013
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Jan 2013 09:00:15 -0500, Maxim Fomin <maxim maxim-fomin.ru>  
wrote:

 On Monday, 28 January 2013 at 12:31:35 UTC, Jacob Carlborg wrote:
 On 2013-01-28 12:44, Robert wrote:
 Having the compiler lower the following:

  property int a;

 to

 private int __a;

  property int a() {
 return __a;
 }
  property int a(int new_a) {
   __a=new_a;
   return __a;
 }
This can be done without compiler help. But we need property as a primitive to allow it.
 I would love that. But the setter should return void and the compiler  
 should to property rewrites.
Returning void instead of int in the example break assignment chaining a = b = c. Besides, how such implicitly defined functions may call user defined code (check input validity, call events, etc.)?
I think Jacob's point is that a = b = c would lower to: b = c; a = b; But I think it would be wasteful in the given case. __a is already in the register, I think actually the return __a is a noop. In other cases, where the property value may be a large struct or whatnot, not returning the new value from a setter would make sense. It would be nice if the compiler made the right choice depending on whether you returned a value from the property or not. -Steve
Jan 28 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-28 17:21, Steven Schveighoffer wrote:

 I think Jacob's point is that a = b = c would lower to:

 b = c;
 a = b;
This is how the semantics should be. This also shows a clear complete example: http://forum.dlang.org/thread/uxhgbxdsselokcdkvltx forum.dlang.org?page=14#post-ke6l44:242mfh:241:40digitalmars.com
 But I think it would be wasteful in the given case.  __a is already in
 the register, I think actually the return __a is a noop.

 In other cases, where the property value may be a large struct or
 whatnot, not returning the new value from a setter would make sense.

 It would be nice if the compiler made the right choice depending on
 whether you returned a value from the property or not.
Then it's up to the compiler to implement them, I don't need to know the details in the optimizations it can do. -- /Jacob Carlborg
Jan 28 2013
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Jan 2013 15:00:41 -0500, Jacob Carlborg <doob me.com> wrote:

 On 2013-01-28 17:21, Steven Schveighoffer wrote:
 But I think it would be wasteful in the given case.  __a is already in
 the register, I think actually the return __a is a noop.

 In other cases, where the property value may be a large struct or
 whatnot, not returning the new value from a setter would make sense.

 It would be nice if the compiler made the right choice depending on
 whether you returned a value from the property or not.
Then it's up to the compiler to implement them, I don't need to know the details in the optimizations it can do.
Like I said, the synthesizing of properties can be done via a library. The compiler simply needs to call the getter when the setter returns void, or return the setter's return value when it returns a value. -Steve
Jan 29 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Jan 2013 15:00:41 -0500, Jacob Carlborg <doob me.com> wrote:

 On 2013-01-28 17:21, Steven Schveighoffer wrote:
 But I think it would be wasteful in the given case.  __a is already in
 the register, I think actually the return __a is a noop.

 In other cases, where the property value may be a large struct or
 whatnot, not returning the new value from a setter would make sense.

 It would be nice if the compiler made the right choice depending on
 whether you returned a value from the property or not.
Then it's up to the compiler to implement them, I don't need to know the details in the optimizations it can do.
Like I said, the synthesizing of properties can be done via a library. The compiler simply needs to call the getter when the setter returns void, or return the setter's return value when it returns a value. -Steve
Jan 29 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-01-28 15:00, Maxim Fomin wrote:

 Returning void instead of int in the example break assignment chaining a
 = b = c. Besides, how such implicitly defined functions may call user
 defined code (check input validity, call events, etc.)?
No, the compiler should do a rewrite, as follows: class Foo { int bar_; property int bar () { return bar_; } property void bar (int value) { bar_ = value; } } auto foo = new Foo; int a = foo.bar = 3; The above line should be rewritten as: foo.bar = 3; int a = foo.bar; The compiler also need to rewrite the following: struct Bar { int a; } class Foo { Bar bar_; property Bar bar () { return bar_; } property void bar (Bar value) { bar_ = value; } } auto foo = new Foo; foo.bar.a = 3; The above line should be rewritten to: auto __tmp = foo.bar; __tmp.a = 3; foo.bar = __tmp; If not, the value of "foo.bar.a" hasn't really changed since you returned a copy by value. If you instead return by reference you can bypass the setter using the getter. -- /Jacob Carlborg
Jan 28 2013
parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 28 January 2013 at 19:55:48 UTC, Jacob Carlborg wrote:
 On 2013-01-28 15:00, Maxim Fomin wrote:

 Returning void instead of int in the example break assignment 
 chaining a
 = b = c. Besides, how such implicitly defined functions may 
 call user
 defined code (check input validity, call events, etc.)?
No, the compiler should do a rewrite, as follows: class Foo { int bar_; property int bar () { return bar_; } property void bar (int value) { bar_ = value; } } auto foo = new Foo; int a = foo.bar = 3; The above line should be rewritten as: foo.bar = 3; int a = foo.bar;
No, it should be rewritten as foo.bar = 3, int a = 3 or int a = foo.bar._set(3). Your example calls getter, which breaks C and D as was said in this thread in previous posts.
 The compiler also need to rewrite the following:

 struct Bar
 {
     int a;
 }

 class Foo
 {
     Bar bar_;

      property Bar bar () { return bar_; }
      property void bar (Bar value) { bar_ = value; }
 }

 auto foo = new Foo;
 foo.bar.a = 3;

 The above line should be rewritten to:

 auto __tmp = foo.bar;
 __tmp.a = 3;
 foo.bar = __tmp;

 If not, the value of "foo.bar.a" hasn't really changed since 
 you returned a copy by value. If you instead return by 
 reference you can bypass the setter using the getter.
This is reasonable.
Jan 29 2013
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, January 28, 2013 13:31:34 Jacob Carlborg wrote:
 Having the compiler lower the following:
 
  property int a;
 
 to
 
 private int __a;
 
  property int a() {
 return __a;
 }
  property int a(int new_a) {
 
 __a=new_a;
 return __a;
 
 }
I would love that. But the setter should return void and the compiler should to property rewrites.
Both should work. It's more efficient to chain assignments if the setter returns a value, but chaining should still work if it returns void. It would just be lowered differently in that case. - Jonathan M Davis
Jan 28 2013
prev sibling parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Monday, 28 January 2013 at 03:24:09 UTC, Steven Schveighoffer 
wrote:
 There are three intentions when creating a function w/ regards 
 to properties:

 1. You intend the function to be called without parentheses to 
 clarify it is a property.
 2. You intend the function to be only called with parentheses 
 to clarify it is a function.
 3. You don't care whether it's called with parentheses or not, 
 because the name of the function is clearly a property or a 
 function.
This is a good point. Possibly since I'm the author of the following proposal, but also because I hope it will garner greater consideration than it has so far, this is how you would do these with my suggested language features single-instance structs and opGet: The new syntax changes: struct __foo {} __foo foo; to: foo struct {} This makes single-instance structs as easy to write as lambda functions. Combining them with two new operator definitions opGet and... let me see... opDo should cover it... it would look like this: struct Goo { int _n; foo struct { int opGet() { return _n; } // Exactly like opCall, but may not be used with parentheses } } Goo g; g.foo(); // Error A struct may have exactly one of opGet, opCall, and opDo. foo struct { int opGet() { ... } int opDo() { ... } // Error: a struct may not have both opGet and opDo } opDo does exactly the opposite of opGet: it mandates the uses of parentheses instead of prohibits them. opCall, on the other hand, permits either one freely. foo struct { int opDo() { return 4; } } foo; // Error: foo must be called with parentheses Note how the single-instance struct does not store data of its own, but is used for its value as a namespace and its ability to overload variables. That doesn't mean you *can't* store data in it. It's just like any other struct except that is has what I was thinking of calling a Highlander type: There can be only one!
Jan 28 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, December 02, 2012 12:36:53 Artur Skawina wrote:
 [1] If you think the required '()' in UFCS chains look ugly, you're right,
 but the right fix isn't to butcher the language.
I agree, but those who think that seem to be outnumbered by those who don't want to have to use the parens - particularly with functions which already require a template argument. - Jonathan M Davis
Dec 02 2012
prev sibling next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
I had been trying to advance the phase to the next.
Now, an experimental pull request is here.
https://github.com/D-Programming-Language/dmd/pull/1311

----
This change can distinguish almost usages between property and non-property
syntax

int func() { return 1; }
void func(int n) { }
 property int prop() { return 2; }
 property void prop(int n) { }
void main() {
  // Without -property switch, all lines can compile.
  // With -property switch:
  func();     // OK -> OK
  func(1);    // OK -> OK
  func;       // OK -> OK [*]
  func = 1;   // OK -> NG (fixed!)
  prop();     // OK -> NG (fixed!)
  prop(1);    // OK -> NG (fixed!)
  prop;       // OK -> OK
  prop = 1;   // OK -> OK
}

First exception is [*], keeping the line is necessary to allow UFCS chain
without redundant parentheses (e.g. r.map!(a=>a*2).array). It is acceptable
to me, at least.

----
I also implemented that calling function pointer which returned by property
function.

 property foo(){ return (int n) => n * 2; }
auto n = foo(10);  // `foo` is resolved to property function call in advance
assert(n == 20);

But, we cannot support it immediately, because it will *always* introduce
breaking of existing code.

- If enable always this feature, propfunc() is implicitly translated to
(propfunc())(),
  then much existing correct code without "-property" switch will break.
- If enable this only when -property switch is specified, a code propfunc()
will have
  _two_ meanings. When propfunc returns a function pointer,
  * If -property is on, propfunc() is translated to propfunc()(), then
    call returned function pointer and returns its result.
  * If -property is off, propfunc() is jsut call property function, then
    returns function pointer.

Changing compilation behavior by compile switch is bad.
Then it is the second exception.

----
The third exception is in AddressExpression (&exp).

In current, both &func and &propfunc return their function pointers. Some
peoples argues
that the latter should return an address of the returned value of propfunc
after implementing more property enforcement, but I'm difficult to accept
that.

The root cause is: AddressExpression is just only one built-in feature for
getting an exact type of property function (Note that typeof(propfunc)
returns the type of propfunc result).

If compiler will always translate the code &propfunc to &(propfunc()),
we will lost a way to get an exact type of propfunc, and then
std.traits.FunctionTypeOf will never work for propfunc.

To resolve the issue, I have proposed a small enhancement for
AddressExpression.
http://d.puremagic.com/issues/show_bug.cgi?id=9062

It will distinguish &propfunc and &(propfunc), the former returns a
function poiinter of propfunc, and the latter returns an address of
propfunc result.

The real example about that is here.
https://github.com/D-Programming-Language/phobos/pull/968/files#L0L1136

----
How about that?

Kenji Hara
Dec 02 2012
parent "sclytrack" <sclytrack thailand.warm> writes:
 int func() { return 1; }
 void func(int n) { }
  property int prop() { return 2; }
  property void prop(int n) { }
 void main() {
   // Without -property switch, all lines can compile.
   // With -property switch:
   func();     // OK -> OK
   func(1);    // OK -> OK
   func;       // OK -> OK [*]
   func = 1;   // OK -> NG (fixed!)
   prop();     // OK -> NG (fixed!)
   prop(1);    // OK -> NG (fixed!)
   prop;       // OK -> OK
   prop = 1;   // OK -> OK
 }
DIP21: Fixing property Nice but DIP21 does not discuss dynamic D.
Dec 03 2012
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 12/03/12 03:23, kenji hara wrote:
 I had been trying to advance the phase to the next.
 Now, an experimental pull request is here.
 https://github.com/D-Programming-Language/dmd/pull/1311
 
 ----
 This change can distinguish almost usages between property and non-property
syntax 
 
 int func() { return 1; }
 void func(int n) { }
  property int prop() { return 2; }
  property void prop(int n) { }
 void main() {
   // Without -property switch, all lines can compile.
   // With -property switch:
   func();     // OK -> OK
   func(1);    // OK -> OK
   func;       // OK -> OK [*]
   func = 1;   // OK -> NG (fixed!)
   prop();     // OK -> NG (fixed!)
   prop(1);    // OK -> NG (fixed!)
   prop;       // OK -> OK
   prop = 1;   // OK -> OK
 }
 
 First exception is [*], keeping the line is necessary to allow UFCS chain
without redundant parentheses (e.g. r.map!(a=>a*2).array). It is acceptable to
me, at least.
Reasonable middle-term compromise; can't really disallow ()-ess calls w/o something else to migrate to, which doesn't exist yet.
 I also implemented that calling function pointer which returned by property
function.
 
  property foo(){ return (int n) => n * 2; }
 auto n = foo(10);  // `foo` is resolved to property function call in advance
 assert(n == 20);
 
 But, we cannot support it immediately, because it will *always* introduce
breaking of existing code.
 
 - If enable always this feature, propfunc() is implicitly translated to
(propfunc())(),
   then much existing correct code without "-property" switch will break.
 - If enable this only when -property switch is specified, a code propfunc()
will have
   _two_ meanings. When propfunc returns a function pointer,
   * If -property is on, propfunc() is translated to propfunc()(), then
     call returned function pointer and returns its result.
   * If -property is off, propfunc() is jsut call property function, then
     returns function pointer.
 
 Changing compilation behavior by compile switch is bad.
'Bad' doesn't begin to describe it. It's unacceptable, as such a compiler switch would create a different language. So it has to be the first option. Which isn't that bad as the "correct" term isn't really appropriate here. This /is/ a change that will break legacy code, but the failures should happen mostly at compile time and the fix is both trivial and backwards compatible. Delaying these kind of changes would only make things worse.
 The third exception is in AddressExpression (&exp).
 
 In current, both &func and &propfunc return their function pointers. Some
peoples argues
 that the latter should return an address of the returned value of propfunc
after implementing more property enforcement, but I'm difficult to accept that.
 
 The root cause is: AddressExpression is just only one built-in feature for
getting an exact type of property function (Note that typeof(propfunc) returns
the type of propfunc result).
 
 If compiler will always translate the code &propfunc to &(propfunc()), 
 we will lost a way to get an exact type of propfunc, and then
std.traits.FunctionTypeOf will never work for propfunc.
 
 To resolve the issue, I have proposed a small enhancement for
AddressExpression.
 http://d.puremagic.com/issues/show_bug.cgi?id=9062 
 
 It will distinguish &propfunc and &(propfunc), the former returns a function
poiinter of propfunc, and the latter returns an address of propfunc result.
No, extremely bad idea; parens shouldn't make any difference. &cast(function)prop // or 'cast(delegate)', as appropriate
 The real example about that is here.
 https://github.com/D-Programming-Language/phobos/pull/968/files#L0L1136 
 
 ----
 How about that?
The property situation is as bad as it is in part because the migration was handled wrongly. What should have happened is that the 'property' compiler switch should have enabled legacy code to compile and property enforcement should have been on by default, to the extent supported by the compiler. Doing it the other way meant that people are writing incorrect code even today. [1] Your changes seem to go in the right direction. Committing to such property enforcement will however be necessary, as keeping the current optional status forever won't work, because of issues like the ones you list above. artur [1] Yeah, "incorrect" means /just/ "incompatible with property enforcement". But the alternative is /no/ enforcement, and if you believe that to be the right approach then every trace of property should go.
Dec 06 2012