www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Uniform Function Call syntax for properties

reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
Someone was asking about UFC syntax for properties on d.learn, and I  
realized, we have a huge ambiguity here.

Given a function:

 property int foo(int x)

Is this a global setter or a getter on an int?

i.e.

int y = foo = 3;

or

int y = (3).foo;

???

I know arrays have an issue with property setters, see a bug report I  
filed a while back:

http://d.puremagic.com/issues/show_bug.cgi?id=3857

But that seems like a totally unambiguous case (a global property function  
with two parameters is obviously a setter on the first parameter in UFC).

The getter seems much more problematic.  Does anyone have a solution  
besides adding more syntax?  Should we disallow global properties to avoid  
ambiguity?

-Steve
Oct 08 2010
next sibling parent reply Stanislav Blinov <blinov loniir.ru> writes:
  08.10.2010 16:55, Steven Schveighoffer пишет:
 Someone was asking about UFC syntax for properties on d.learn, and I 
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?

 i.e.

 int y = foo = 3;

 or

 int y = (3).foo;

 ???

 I know arrays have an issue with property setters, see a bug report I 
 filed a while back:

 http://d.puremagic.com/issues/show_bug.cgi?id=3857

 But that seems like a totally unambiguous case (a global property 
 function with two parameters is obviously a setter on the first 
 parameter in UFC).

 The getter seems much more problematic.  Does anyone have a solution 
 besides adding more syntax?  Should we disallow global properties to 
 avoid ambiguity?
What if we make properties have first parameter as ref/ref const if it's meant to be part of UFC? This way we can keep module-scope properties and easily make UFC properties for existing types: property int foo(int x) { /*...*/ } // module-scope setter property int foo() { /*...*/ } // module-scope getter property int foo(ref int x, int v) { /*...*/ } // UFC 'setter' for int property int foo(ref int x) { /*...*/ } // or int foo(ref const int x) - UFS 'getter' for int There's a caveat, though, as having ref/ref const would disallow doing thigs like 3.foo() (which makes perfect sense for 'setters', but not for getters.
Oct 08 2010
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Fri, 08 Oct 2010 17:26:41 +0400, Stanislav Blinov <blinov loniir.ru> =
 =

wrote:

   08.10.2010 16:55, Steven Schveighoffer =D0=C9=DB=C5=D4:
 Someone was asking about UFC syntax for properties on d.learn, and I =
=
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?

 i.e.

 int y =3D foo =3D 3;

 or

 int y =3D (3).foo;

 ???

 I know arrays have an issue with property setters, see a bug report I=
=
 filed a while back:

 http://d.puremagic.com/issues/show_bug.cgi?id=3D3857

 But that seems like a totally unambiguous case (a global property  =
 function with two parameters is obviously a setter on the first  =
 parameter in UFC).

 The getter seems much more problematic.  Does anyone have a solution =
=
 besides adding more syntax?  Should we disallow global properties to =
=
 avoid ambiguity?
What if we make properties have first parameter as ref/ref const if =
 it's meant to be part of UFC? This way we can keep module-scope  =
 properties and easily make UFC properties for existing types:

  property int foo(int x) { /*...*/ } // module-scope setter
  property int foo() { /*...*/ } // module-scope getter
  property int foo(ref int x, int v) { /*...*/ } // UFC 'setter' for in=
t
  property int foo(ref int x) { /*...*/ } // or int foo(ref const int x=
) =
 - UFS 'getter' for int

 There's a caveat, though, as having ref/ref const would disallow doing=
=
 thigs like 3.foo() (which makes perfect sense for 'setters', but not f=
or =
 getters.
property int set(this int x, int y) { x =3D y; } property int get(this const(int) x) { return x; } int a =3D 1; a.set(42); // a is 42 now 3.set(42); // fails to compile, 3 is of type const(int)
Oct 08 2010
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 08 Oct 2010 09:30:59 -0400, Denis Koroskin <2korden gmail.com>  
wrote:


  property int set(this int x, int y)
 {
      x = y;
 }


  property int get(this const(int) x)
 {
      return x;
 }

 int a = 1;
 a.set(42); // a is 42 now
 3.set(42); // fails to compile, 3 is of type const(int)
Using this is a good idea, but I don't think we should automatically ref the value. Also this is already a symbol name, can't we just use it? What I think might be a good idea is to *name* the target this, and then just allow the normal adornments to describe the type. i.e.: property int set(ref int this, int y) {} will work only for lvalues, whereas property int set(int this, int y) {} works for rvalues also. The What do you think? -Steve
Oct 08 2010
parent Stanislav Blinov <blinov loniir.ru> writes:
  08.10.2010 17:46, Steven Schveighoffer пишет:
 On Fri, 08 Oct 2010 09:30:59 -0400, Denis Koroskin <2korden gmail.com> 
 wrote:


  property int set(this int x, int y)
 {
      x = y;
 }


  property int get(this const(int) x)
 {
      return x;
 }

 int a = 1;
 a.set(42); // a is 42 now
 3.set(42); // fails to compile, 3 is of type const(int)
Using this is a good idea, but I don't think we should automatically ref the value. Also this is already a symbol name, can't we just use it? What I think might be a good idea is to *name* the target this, and then just allow the normal adornments to describe the type. i.e.: property int set(ref int this, int y) {} will work only for lvalues, whereas property int set(int this, int y) {} works for rvalues also. The What do you think?
Looks tasty, and besides that's exactly how class/struct methods actually look.
Oct 08 2010
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/8/10 7:55 CDT, Steven Schveighoffer wrote:
 Someone was asking about UFC syntax for properties on d.learn, and I
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?
Good question. Andrei
Oct 08 2010
parent reply Sean Kelly <sean invisibleduck.org> writes:
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 10/8/10 7:55 CDT, Steven Schveighoffer wrote:
 Someone was asking about UFC syntax for properties on d.learn, and I
 realized, we have a huge ambiguity here.
 
 Given a function:
 
  property int foo(int x)
 
 Is this a global setter or a getter on an int?
Good question.
Setter. Consider "a = b = c".
Oct 09 2010
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 10 Oct 2010 00:09:23 +0400, Sean Kelly <sean invisibleduck.org>  
wrote:

 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 10/8/10 7:55 CDT, Steven Schveighoffer wrote:
 Someone was asking about UFC syntax for properties on d.learn, and I
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?
Good question.
Setter. Consider "a = b = c".
I think you missed the point. Which of the two is it: int x = 42; auto y = x.foo(); // transformed into "auto y = foo(x);", getter or foo = 42; // transformed into "foo(42);", setter Both match.
Oct 09 2010
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Sat, 09 Oct 2010 16:28:32 -0400, Denis Koroskin <2korden gmail.com>  
wrote:

 On Sun, 10 Oct 2010 00:09:23 +0400, Sean Kelly <sean invisibleduck.org>  
 wrote:

 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 10/8/10 7:55 CDT, Steven Schveighoffer wrote:
 Someone was asking about UFC syntax for properties on d.learn, and I
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?
Good question.
Setter. Consider "a = b = c".
I think you missed the point. Which of the two is it: int x = 42; auto y = x.foo(); // transformed into "auto y = foo(x);", getter or foo = 42; // transformed into "foo(42);", setter Both match.
I agree that there is ambiguity here, but does it why does foo have to be only a getter or only a setter? Why can't it behave like either, depending on its implementation and use?
Oct 09 2010
next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 10 Oct 2010 05:58:00 +0400, Robert Jacques <sandford jhu.edu>  
wrote:

 On Sat, 09 Oct 2010 16:28:32 -0400, Denis Koroskin <2korden gmail.com>  
 wrote:

 On Sun, 10 Oct 2010 00:09:23 +0400, Sean Kelly <sean invisibleduck.org>  
 wrote:

 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 10/8/10 7:55 CDT, Steven Schveighoffer wrote:
 Someone was asking about UFC syntax for properties on d.learn, and I
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?
Good question.
Setter. Consider "a = b = c".
I think you missed the point. Which of the two is it: int x = 42; auto y = x.foo(); // transformed into "auto y = foo(x);", getter or foo = 42; // transformed into "foo(42);", setter Both match.
I agree that there is ambiguity here, but does it why does foo have to be only a getter or only a setter? Why can't it behave like either, depending on its implementation and use?
Because you may want to have both, but you can't because their syntax overlap.
Oct 09 2010
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Sat, 09 Oct 2010 22:03:56 -0400, Denis Koroskin <2korden gmail.com>  
wrote:

 On Sun, 10 Oct 2010 05:58:00 +0400, Robert Jacques <sandford jhu.edu>  
 wrote:

 On Sat, 09 Oct 2010 16:28:32 -0400, Denis Koroskin <2korden gmail.com>  
 wrote:

 On Sun, 10 Oct 2010 00:09:23 +0400, Sean Kelly  
 <sean invisibleduck.org> wrote:

 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 10/8/10 7:55 CDT, Steven Schveighoffer wrote:
 Someone was asking about UFC syntax for properties on d.learn, and I
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?
Good question.
Setter. Consider "a = b = c".
I think you missed the point. Which of the two is it: int x = 42; auto y = x.foo(); // transformed into "auto y = foo(x);", getter or foo = 42; // transformed into "foo(42);", setter Both match.
I agree that there is ambiguity here, but does it why does foo have to be only a getter or only a setter? Why can't it behave like either, depending on its implementation and use?
Because you may want to have both, but you can't because their syntax overlap.
Okay I'm confused. How do their syntax overlap? And which syntaxes do you think are overlapping? All the following 'lowerings' look fine/unambiguous to me: foo = 42; => foo(42); y = x.foo; => y = x.foo(); => y = foo(x); foo = foo = x.foo; => foo = foo = x.foo(); => foo = foo = foo(x); => foo = foo(foo(x)); => foo(foo(foo(x)));
Oct 09 2010
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 10 Oct 2010 08:44:59 +0400, Robert Jacques <sandford jhu.edu>  
wrote:

 On Sat, 09 Oct 2010 22:03:56 -0400, Denis Koroskin <2korden gmail.com>  
 wrote:

 On Sun, 10 Oct 2010 05:58:00 +0400, Robert Jacques <sandford jhu.edu>  
 wrote:

 On Sat, 09 Oct 2010 16:28:32 -0400, Denis Koroskin <2korden gmail.com>  
 wrote:

 On Sun, 10 Oct 2010 00:09:23 +0400, Sean Kelly  
 <sean invisibleduck.org> wrote:

 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 10/8/10 7:55 CDT, Steven Schveighoffer wrote:
 Someone was asking about UFC syntax for properties on d.learn, and  
 I
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?
Good question.
Setter. Consider "a = b = c".
I think you missed the point. Which of the two is it: int x = 42; auto y = x.foo(); // transformed into "auto y = foo(x);", getter or foo = 42; // transformed into "foo(42);", setter Both match.
I agree that there is ambiguity here, but does it why does foo have to be only a getter or only a setter? Why can't it behave like either, depending on its implementation and use?
Because you may want to have both, but you can't because their syntax overlap.
Okay I'm confused. How do their syntax overlap? And which syntaxes do you think are overlapping? All the following 'lowerings' look fine/unambiguous to me: foo = 42; => foo(42); y = x.foo; => y = x.foo(); => y = foo(x); foo = foo = x.foo; => foo = foo = x.foo(); => foo = foo = foo(x); => foo = foo(foo(x)); => foo(foo(foo(x)));
I wasn't talking about ambiguity. I told that you can't assign different behavior to foo = 42; and y = x.foo; Both are resolving to the same symbol. E.g. I'd like to write a setter, "foo = 42;": private int _foo; int foo(int x) { debug writeln("foo = ", x); _foo = x; return x; } But the following code also triggers the setter above: y = 42.foo(); // prints "foo = 42;", sets private variable _foo to 42, and returns that value That's completely unexpected. Imagine yourself writing class Foo with method bar, and a user who highjacks a hole in the language, creates class bar, and invokes method Foo on it. That's what it looks like at this moment.
Oct 09 2010
parent "Robert Jacques" <sandford jhu.edu> writes:
On Sun, 10 Oct 2010 00:58:39 -0400, Denis Koroskin <2korden gmail.com>  
wrote:

 On Sun, 10 Oct 2010 08:44:59 +0400, Robert Jacques <sandford jhu.edu>  
 wrote:

 On Sat, 09 Oct 2010 22:03:56 -0400, Denis Koroskin <2korden gmail.com>  
 wrote:

 On Sun, 10 Oct 2010 05:58:00 +0400, Robert Jacques <sandford jhu.edu>  
 wrote:

 On Sat, 09 Oct 2010 16:28:32 -0400, Denis Koroskin  
 <2korden gmail.com> wrote:

 On Sun, 10 Oct 2010 00:09:23 +0400, Sean Kelly  
 <sean invisibleduck.org> wrote:

 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 10/8/10 7:55 CDT, Steven Schveighoffer wrote:
 Someone was asking about UFC syntax for properties on d.learn,  
 and I
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?
Good question.
Setter. Consider "a = b = c".
I think you missed the point. Which of the two is it: int x = 42; auto y = x.foo(); // transformed into "auto y = foo(x);", getter or foo = 42; // transformed into "foo(42);", setter Both match.
I agree that there is ambiguity here, but does it why does foo have to be only a getter or only a setter? Why can't it behave like either, depending on its implementation and use?
Because you may want to have both, but you can't because their syntax overlap.
Okay I'm confused. How do their syntax overlap? And which syntaxes do you think are overlapping? All the following 'lowerings' look fine/unambiguous to me: foo = 42; => foo(42); y = x.foo; => y = x.foo(); => y = foo(x); foo = foo = x.foo; => foo = foo = x.foo(); => foo = foo = foo(x); => foo = foo(foo(x)); => foo(foo(foo(x)));
I wasn't talking about ambiguity. I told that you can't assign different behavior to foo = 42; and y = x.foo; Both are resolving to the same symbol. E.g. I'd like to write a setter, "foo = 42;": private int _foo; int foo(int x) { debug writeln("foo = ", x); _foo = x; return x; } But the following code also triggers the setter above: y = 42.foo(); // prints "foo = 42;", sets private variable _foo to 42, and returns that value That's completely unexpected.
Actually, that's completely expected, in my humble opinion. Yes, it will be a bit confusing to people new to D, perhaps even to those familiar with UFC, that behavior is perfectly natural.
 Imagine yourself writing class Foo with method bar, and a user who  
 highjacks a hole in the language, creates class bar, and invokes method  
 Foo on it. That's what it looks like at this moment.
Well, hijacking won't be possible since D's got really good function hijacking detection. Also, how can Foo be both a method and a class?
Oct 10 2010
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 09 Oct 2010 21:58:00 -0400, Robert Jacques <sandford jhu.edu>  
wrote:

 On Sat, 09 Oct 2010 16:28:32 -0400, Denis Koroskin <2korden gmail.com>  
 wrote:

 On Sun, 10 Oct 2010 00:09:23 +0400, Sean Kelly <sean invisibleduck.org>  
 wrote:

 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 10/8/10 7:55 CDT, Steven Schveighoffer wrote:
 Someone was asking about UFC syntax for properties on d.learn, and I
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?
Good question.
Setter. Consider "a = b = c".
I think you missed the point. Which of the two is it: int x = 42; auto y = x.foo(); // transformed into "auto y = foo(x);", getter or foo = 42; // transformed into "foo(42);", setter Both match.
I agree that there is ambiguity here, but does it why does foo have to be only a getter or only a setter? Why can't it behave like either, depending on its implementation and use?
Because then we are back to writeln = 42; -Steve
Oct 13 2010
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Wed, 13 Oct 2010 14:34:14 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:
 On Sat, 09 Oct 2010 21:58:00 -0400, Robert Jacques <sandford jhu.edu>  
 wrote:

 On Sat, 09 Oct 2010 16:28:32 -0400, Denis Koroskin <2korden gmail.com>  
 wrote:

 On Sun, 10 Oct 2010 00:09:23 +0400, Sean Kelly  
 <sean invisibleduck.org> wrote:

 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 10/8/10 7:55 CDT, Steven Schveighoffer wrote:
 Someone was asking about UFC syntax for properties on d.learn, and I
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?
Good question.
Setter. Consider "a = b = c".
I think you missed the point. Which of the two is it: int x = 42; auto y = x.foo(); // transformed into "auto y = foo(x);", getter or foo = 42; // transformed into "foo(42);", setter Both match.
I agree that there is ambiguity here, but does it why does foo have to be only a getter or only a setter? Why can't it behave like either, depending on its implementation and use?
Because then we are back to writeln = 42; -Steve
:) I see that despite not valid code for what, over a year now?, writeln = 42 still persists. That said, how exactly are we back to the verb = value "problem"? The rearrangement ambiguity was never the expressed reason for introducing property. In fact, despite all the passionate posts about how wrong "verb = value" looks, it took a very specific syntax ambiguity with delegates/opCall to warrant language inclusion. And given the practical problems property has been running into, it kinda makes me wish I had run across the uniform access principle (http://www.eiffel.com/general/column/2005/Sept_October.html) back during the debates.
Oct 13 2010
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 13 Oct 2010 20:57:54 -0400, Robert Jacques <sandford jhu.edu>  
wrote:

 On Wed, 13 Oct 2010 14:34:14 -0400, Steven Schveighoffer  
 <schveiguy yahoo.com> wrote:
 Because then we are back to writeln = 42;

 -Steve
:) I see that despite not valid code for what, over a year now?, writeln = 42 still persists.
IMO, that's because the head squeaky wheel is not really fond of properties :) It will eventually be fixed.
 That said, how exactly are we back to the verb = value "problem"?
Because you can use properties in ways they weren't meant to be used. Specifically, you can use a getter as a setter or vice versa. I admit it's not exactly the same problem, but it's a very similar issue.
 The rearrangement ambiguity was never the expressed reason for  
 introducing  property. In fact, despite all the passionate posts about  
 how wrong "verb = value" looks, it took a very specific syntax ambiguity  
 with delegates/opCall to warrant language inclusion. And given the  
 practical problems  property has been running into, it kinda makes me  
 wish I had run across the uniform access principle  
 (http://www.eiffel.com/general/column/2005/Sept_October.html) back  
 during the debates.
I must have said this a hundred thousand times. It has to do with the power of the author to define usage. When you let the user define usage, confusion ensues. To me, the delegate issue is a nice bonus, and if that's what pushed property acceptance over the edge, so be it. Without the restrictions, the author loses the power to define usage, and he resorts to creating more verbose language like getFoo instead of just foo. Welcome to Java. -Steve
Oct 14 2010
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 14 Oct 2010 09:42:34 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 On Wed, 13 Oct 2010 20:57:54 -0400, Robert Jacques <sandford jhu.edu>  
 wrote:

 On Wed, 13 Oct 2010 14:34:14 -0400, Steven Schveighoffer  
 <schveiguy yahoo.com> wrote:
 Because then we are back to writeln = 42;

 -Steve
:) I see that despite not valid code for what, over a year now?, writeln = 42 still persists.
IMO, that's because the head squeaky wheel is not really fond of properties :) It will eventually be fixed.
 That said, how exactly are we back to the verb = value "problem"?
Because you can use properties in ways they weren't meant to be used. Specifically, you can use a getter as a setter or vice versa. I admit it's not exactly the same problem, but it's a very similar issue.
 The rearrangement ambiguity was never the expressed reason for  
 introducing  property. In fact, despite all the passionate posts about  
 how wrong "verb = value" looks, it took a very specific syntax  
 ambiguity with delegates/opCall to warrant language inclusion. And  
 given the practical problems  property has been running into, it kinda  
 makes me wish I had run across the uniform access principle  
 (http://www.eiffel.com/general/column/2005/Sept_October.html) back  
 during the debates.
I must have said this a hundred thousand times. It has to do with the power of the author to define usage. When you let the user define usage, confusion ensues. To me, the delegate issue is a nice bonus, and if that's what pushed property acceptance over the edge, so be it. Without the restrictions, the author loses the power to define usage, and he resorts to creating more verbose language like getFoo instead of just foo. Welcome to Java. -Steve
First, to avoid confusion, I'd like to separate inappropriate usage at the binary level from textual/syntax level. For example, casting, compile-time reflection and .tupleof are all ways to circumvent the fundamental restrictions of a library in order to achieve inappropriate binary access, while alias and 'with()' allow (harmless?) syntactical changes, changing a library's effective API. The decision between what is and isn't inappropriate syntax is generally made by either the language designer or by your project's style guide. Indeed, libraries that define extensive changes in a language's appropriate syntax are often referred to as being domain specific languages instead of a simple libraries, modules or packages. And part of the reason for this nomenclature change is that DSLs, unlike libraries, tend to compose poorly and require varying levels of programmer buy-in. This is one reason why none of the DSL/macro features implemented and/or proposed for D are pervasive; they all have a very specific and defined radius of comprehension and scope. Which brings us to the concept of methods behaving syntactically as fields. The three solutions put forth so far are: methods-as-properties, which allow methods to behave like methods or fields; property, which force specific methods to behave only as fields; and the uniform access principle, which allows methods _and_ fields to behave like either methods or fields. Both MAP and UAP are language level syntax changes, while property gives libraries pervasive DSL-lite abilities. The main advantages of MAP and UAP is that they allow the project team to better select a coding style that suites them. On the downside, neither MAP nor UAP are mainstream concepts, so it can take people time to adapt, and more coding style choice inevitably breeds more coding style wars (i.e. names_with_underscores vs CamelCase, csHangarian vbNotation, sVNs vs longVariableNames, etc.). property, on the other hand, moves the coding style choice to the library author, which, on the plus side, is similar to coding style, which may not be appropriate for all users for all time. (read: poor user buy-in) Worse, an author's style choice will enviably conflict with either the project's style guidelines or a second author's library, leading to user code which has to constantly change styles. (read: poor composition) And the composition problem only worsens for generic code. I fully agree that the ability to define the acceptable syntactic usage is critical to avoiding confusion, I simply believe that putting that responsibility in that hands of a project's style guide provides the best consistency and is the most inclusive. Furthermore, I would point out that ultimately the author serves the user; they are his/her customer and good libraries don't unnecessarily restrict their users. Indeed, one of D's best feature is the collection of things, both great and small, that lets it get out of the way of the coding process. BTW: That article on the uniform access principal has an interesting sidebar on how Eiffel satisfied two very different sets of programmers who desired mutually exclusive syntaxes. (http://www.eiffel.com/general/column/2005/Sept_October.html)
Oct 14 2010
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 14 Oct 2010 20:28:45 -0400, Robert Jacques <sandford jhu.edu>  
wrote:
 First, to avoid confusion, I'd like to separate inappropriate usage at  
 the binary level from textual/syntax level. For example, casting,  
 compile-time reflection and .tupleof are all ways to circumvent the  
 fundamental restrictions of a library in order to achieve inappropriate  
 binary access, while alias and 'with()' allow (harmless?) syntactical  
 changes, changing a library's effective API. The decision between what  
 is and isn't inappropriate syntax is generally made by either the  
 language designer or by your project's style guide. Indeed, libraries  
 that define extensive changes in a language's appropriate syntax are  
 often referred to as being domain specific languages instead of a simple  
 libraries, modules or packages. And part of the reason for this  
 nomenclature change is that DSLs, unlike libraries, tend to compose  
 poorly and require varying levels of programmer buy-in. This is one  
 reason why none of the DSL/macro features implemented and/or proposed  
 for D are pervasive; they all have a very specific and defined radius of  
 comprehension and scope.
as well you can rename anything you want. Hell, for most D projects you have the source, just rename it! But if you want your code to be readable, you should follow the convention that the author intended, because that's how everyone else will read it and understand it.
 Which brings us to the concept of methods behaving syntactically as  
 fields. The three solutions put forth so far are: methods-as-properties,  
 which allow methods to behave like methods or fields;  property, which  
 force specific methods to behave only as fields; and the uniform access  
 principle, which allows methods _and_ fields to behave like either  
 methods or fields. Both MAP and UAP are language level syntax changes,  
 while  property gives libraries pervasive DSL-lite abilities. The main  
 advantages of MAP and UAP is that they allow the project team to better  
 select a coding style that suites them. On the downside, neither MAP nor  
 UAP are mainstream concepts, so it can take people time to adapt, and  
 more coding style choice inevitably breeds more coding style wars (i.e.  
 names_with_underscores vs CamelCase, csHangarian vbNotation, sVNs vs  
 longVariableNames, etc.).  property, on the other hand, moves the coding  
 style choice to the library author, which, on the plus side, is similar  

 single coding style, which may not be appropriate for all users for all  
 time. (read: poor user buy-in) Worse, an author's style choice will  
 enviably conflict with either the project's style guidelines or a second  
 author's library, leading to user code which has to constantly change  
 styles. (read: poor composition) And the composition problem only  
 worsens for generic code.
Couldn't disagree more. An API without appropriate function names == fail. And the call style is part of the function name, like it or not. People see x = y, they think field. People see x(y) they think function. No matter the camel casing, or spacing between parentheses, or prefixes to the function name, or whether the curly brace is on the next line or not. It amazes me how many times we have to go over this.
 I fully agree that the ability to define the acceptable syntactic usage  
 is critical to avoiding confusion, I simply believe that putting that  
 responsibility in that hands of a project's style guide provides the  
 best consistency and is the most inclusive. Furthermore, I would point  
 out that ultimately the author serves the user; they are his/her  
 customer and good libraries don't unnecessarily restrict their users.  
 Indeed, one of D's best feature is the collection of things, both great  
 and small, that lets it get out of the way of the coding process.
I want the *compiler* to tell me when I incorrectly used a property, not a style guide (which requires a person for interpretation). -Steve
Oct 14 2010
parent "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 14 Oct 2010 22:22:19 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 On Thu, 14 Oct 2010 20:28:45 -0400, Robert Jacques <sandford jhu.edu>  
 wrote:
 First, to avoid confusion, I'd like to separate inappropriate usage at  
 the binary level from textual/syntax level. For example, casting,  
 compile-time reflection and .tupleof are all ways to circumvent the  
 fundamental restrictions of a library in order to achieve inappropriate  
 binary access, while alias and 'with()' allow (harmless?) syntactical  
 changes, changing a library's effective API. The decision between what  
 is and isn't inappropriate syntax is generally made by either the  
 language designer or by your project's style guide. Indeed, libraries  
 that define extensive changes in a language's appropriate syntax are  
 often referred to as being domain specific languages instead of a  
 simple libraries, modules or packages. And part of the reason for this  
 nomenclature change is that DSLs, unlike libraries, tend to compose  
 poorly and require varying levels of programmer buy-in. This is one  
 reason why none of the DSL/macro features implemented and/or proposed  
 for D are pervasive; they all have a very specific and defined radius  
 of comprehension and scope.
as well you can rename anything you want. Hell, for most D projects you have the source, just rename it! But if you want your code to be readable, you should follow the convention that the author intended, because that's how everyone else will read it and understand it.
 Which brings us to the concept of methods behaving syntactically as  
 fields. The three solutions put forth so far are:  
 methods-as-properties, which allow methods to behave like methods or  
 fields;  property, which force specific methods to behave only as  
 fields; and the uniform access principle, which allows methods _and_  
 fields to behave like either methods or fields. Both MAP and UAP are  
 language level syntax changes, while  property gives libraries  
 pervasive DSL-lite abilities. The main advantages of MAP and UAP is  
 that they allow the project team to better select a coding style that  
 suites them. On the downside, neither MAP nor UAP are mainstream  
 concepts, so it can take people time to adapt, and more coding style  
 choice inevitably breeds more coding style wars (i.e.  
 names_with_underscores vs CamelCase, csHangarian vbNotation, sVNs vs  
 longVariableNames, etc.).  property, on the other hand, moves the  
 coding style choice to the library author, which, on the plus side, is  

 choose a single coding style, which may not be appropriate for all  
 users for all time. (read: poor user buy-in) Worse, an author's style  
 choice will enviably conflict with either the project's style  
 guidelines or a second author's library, leading to user code which has  
 to constantly change styles. (read: poor composition) And the  
 composition problem only worsens for generic code.
Couldn't disagree more. An API without appropriate function names == fail. And the call style is part of the function name, like it or not. People see x = y, they think field. People see x(y) they think function. No matter the camel casing, or spacing between parentheses, or prefixes to the function name, or whether the curly brace is on the next line or not. It amazes me how many times we have to go over this.
 I fully agree that the ability to define the acceptable syntactic usage  
 is critical to avoiding confusion, I simply believe that putting that  
 responsibility in that hands of a project's style guide provides the  
 best consistency and is the most inclusive. Furthermore, I would point  
 out that ultimately the author serves the user; they are his/her  
 customer and good libraries don't unnecessarily restrict their users.  
 Indeed, one of D's best feature is the collection of things, both great  
 and small, that lets it get out of the way of the coding process.
I want the *compiler* to tell me when I incorrectly used a property, not a style guide (which requires a person for interpretation). -Steve
I think you have misunderstood something. It is partly my fault, as I used naming styles as an example. More pertinent examples would be function calls vs operator overloading, or prefix (= x y) vs infix (x = y) vs postfix (x y =) notation. These are issues which are normally the purview of the language designer. When the language designer opens up field / method syntax to programmer control, the assumption that x = y means fields ceases to be axiomatic and becomes a programming convention/style. Similarly, that x(y) indicates a function call can also become a programming convention/style. Other programming languages, for example Eiffel, have proven the usefulness of field/method styles other than those of the C-family. In fact Eiffel does not syntactically differentiate stored values (aka fields) from computed values (aka methods), giving it a slightly functional feel. Given a method of control, be it by the Universal-Access-Principal, Method-as-Properties or property, users/authors will all write code in their own preferred style. And although each of these styles is internally logical and self-consistent, unlike names_with_underscores and CamelCaseNames, they may violate each others internal assumptions. So, yes, property allows the authors to define a compiler enforceable way to use a property. And that's great when your preferred style and the author's match. But it also means you're forced to write the equivalent of 'writeln = 42' when your preferred style and the author's don't match.
Oct 17 2010
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
news:op.vj9cunrweav7ka localhost.localdomain...
 Someone was asking about UFC syntax for properties on d.learn, and I 
 realized, we have a huge ambiguity here.

 Given a function:

  property int foo(int x)

 Is this a global setter or a getter on an int?

 i.e.

 int y = foo = 3;

 or

 int y = (3).foo;

 ???

 I know arrays have an issue with property setters, see a bug report I 
 filed a while back:

 http://d.puremagic.com/issues/show_bug.cgi?id=3857

 But that seems like a totally unambiguous case (a global property function 
 with two parameters is obviously a setter on the first parameter in UFC).

 The getter seems much more problematic.  Does anyone have a solution 
 besides adding more syntax?  Should we disallow global properties to avoid 
 ambiguity?
Ugh, it seems D still doesn't quite understand the concept of a property. Here: property int foo() // Obviously getter property void foo(int x) // Obviously setter No other form makes any sence as a property. Frankly, I'm very surprised, and dissapointed, that anything else is even allowed. The only *possible* exception being: property int foo(int x) // Combined getter/setter, if we decide that's needed It doesn't make any sense for a property getter to have a parameter (unless it's one parameter and it's used to set a new value). And it doesn't make any sence for a setter to have anthing other than exactly one parameter. Just disallow it. What could possibly be the point anyway? If it's got parameters it's a function call, not a variable. Additionally, with that understanding in place, this: property void foo(int x) {...} (3).foo(); Is probably the one place where UFC syntax should never be allowed, because it's obviously a setter, and since when does this ever make any sence: int x; (3).x; // Set x to 3?? WTF??
Oct 08 2010
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, October 08, 2010 13:56:14 Nick Sabalausky wrote:
 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message
 news:op.vj9cunrweav7ka localhost.localdomain...
 
 Someone was asking about UFC syntax for properties on d.learn, and I
 realized, we have a huge ambiguity here.
 
 Given a function:
 
  property int foo(int x)
 
 Is this a global setter or a getter on an int?
 
 i.e.
 
 int y = foo = 3;
 
 or
 
 int y = (3).foo;
 
 ???
 
 I know arrays have an issue with property setters, see a bug report I
 filed a while back:
 
 http://d.puremagic.com/issues/show_bug.cgi?id=3857
 
 But that seems like a totally unambiguous case (a global property
 function with two parameters is obviously a setter on the first
 parameter in UFC).
 
 The getter seems much more problematic.  Does anyone have a solution
 besides adding more syntax?  Should we disallow global properties to
 avoid ambiguity?
Ugh, it seems D still doesn't quite understand the concept of a property. Here: property int foo() // Obviously getter property void foo(int x) // Obviously setter No other form makes any sence as a property. Frankly, I'm very surprised, and dissapointed, that anything else is even allowed. The only *possible* exception being: property int foo(int x) // Combined getter/setter, if we decide that's needed It doesn't make any sense for a property getter to have a parameter (unless it's one parameter and it's used to set a new value). And it doesn't make any sence for a setter to have anthing other than exactly one parameter. Just disallow it. What could possibly be the point anyway? If it's got parameters it's a function call, not a variable.
I agree 100%.
 
 Additionally, with that understanding in place, this:
 
  property void foo(int x)  {...}
 (3).foo();
 
 Is probably the one place where UFC syntax should never be allowed, because
 it's obviously a setter, and since when does this ever make any sence:
 
 int x;
 (3).x; // Set x to 3?? WTF??
If literals are considered const or immutable, then this takes care of itself, since then the type system would then disallow it. - Jonathan M Davis
Oct 08 2010
parent "Nick Sabalausky" <a a.a> writes:
"Jonathan M Davis" <jmdavisProg gmx.com> wrote in message 
news:mailman.483.1286572389.858.digitalmars-d puremagic.com...
 On Friday, October 08, 2010 13:56:14 Nick Sabalausky wrote:
 Additionally, with that understanding in place, this:

  property void foo(int x)  {...}
 (3).foo();

 Is probably the one place where UFC syntax should never be allowed, 
 because
 it's obviously a setter, and since when does this ever make any sence:

 int x;
 (3).x; // Set x to 3?? WTF??
If literals are considered const or immutable, then this takes care of itself, since then the type system would then disallow it.
Maybe hunger is blinding me ATM, but don't see how. Unless it would also prevent this: void bar(int a) {...} bar(3); // Cannot implicitly cast away immutable But that would obviously be a bad thing. And even at that, there's still this that would need to be prevented: property void foo(int x) {...} int x = cast(int)3; x.foo; // Set foo to 3 with stupid syntax
Oct 08 2010
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 08 Oct 2010 16:56:14 -0400, Nick Sabalausky <a a.a> wrote:

 Ugh, it seems D still doesn't quite understand the concept of a property.
 Here:

  property int foo()  // Obviously getter
  property void foo(int x)  // Obviously setter

 No other form makes any sence as a property. Frankly, I'm very surprised,
 and dissapointed, that anything else is even allowed. The only *possible*
 exception being:

  property int foo(int x) // Combined getter/setter, if we decide that's
 needed

 It doesn't make any sense for a property getter to have a parameter  
 (unless
 it's one parameter and it's used to set a new value). And it doesn't make
 any sence for a setter to have anthing other than exactly one parameter.
 Just disallow it. What could possibly be the point anyway? If it's got
 parameters it's a function call, not a variable.
Property setters can have two parameters, one is the item used to set it, and one is the rvalue to use when setting. In objects, the first parameter is the hidden this parameter. With UFC, the parameter is explicit. Unless you feel builtin arrays should never have properties? The only exception are global properties which are not set on anything. And this is the problem. I think the syntax discussed in the other part of this thread is probably a good way to disambiguate the issues. -Steve
Oct 09 2010
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/9/10 13:33 CDT, Steven Schveighoffer wrote:
 On Fri, 08 Oct 2010 16:56:14 -0400, Nick Sabalausky <a a.a> wrote:

 Ugh, it seems D still doesn't quite understand the concept of a property.
 Here:

  property int foo() // Obviously getter
  property void foo(int x) // Obviously setter

 No other form makes any sence as a property. Frankly, I'm very surprised,
 and dissapointed, that anything else is even allowed. The only *possible*
 exception being:

  property int foo(int x) // Combined getter/setter, if we decide that's
 needed

 It doesn't make any sense for a property getter to have a parameter
 (unless
 it's one parameter and it's used to set a new value). And it doesn't make
 any sence for a setter to have anthing other than exactly one parameter.
 Just disallow it. What could possibly be the point anyway? If it's got
 parameters it's a function call, not a variable.
Property setters can have two parameters, one is the item used to set it, and one is the rvalue to use when setting. In objects, the first parameter is the hidden this parameter. With UFC, the parameter is explicit. Unless you feel builtin arrays should never have properties? The only exception are global properties which are not set on anything. And this is the problem. I think the syntax discussed in the other part of this thread is probably a good way to disambiguate the issues. -Steve
One possibility is to simply say that property int foo(T x); always means a getter for T. This is because if you want to define a global with getter and setter you can always write a type with assignment and alias this. Andrei
Oct 09 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/9/10 13:33 CDT, Steven Schveighoffer wrote:
 On Fri, 08 Oct 2010 16:56:14 -0400, Nick Sabalausky <a a.a> wrote:

 Ugh, it seems D still doesn't quite understand the concept of a property.
 Here:

  property int foo() // Obviously getter
  property void foo(int x) // Obviously setter

 No other form makes any sence as a property. Frankly, I'm very surprised,
 and dissapointed, that anything else is even allowed. The only *possible*
 exception being:

  property int foo(int x) // Combined getter/setter, if we decide that's
 needed

 It doesn't make any sense for a property getter to have a parameter
 (unless
 it's one parameter and it's used to set a new value). And it doesn't make
 any sence for a setter to have anthing other than exactly one parameter.
 Just disallow it. What could possibly be the point anyway? If it's got
 parameters it's a function call, not a variable.
Property setters can have two parameters, one is the item used to set it, and one is the rvalue to use when setting. In objects, the first parameter is the hidden this parameter. With UFC, the parameter is explicit. Unless you feel builtin arrays should never have properties? The only exception are global properties which are not set on anything. And this is the problem. I think the syntax discussed in the other part of this thread is probably a good way to disambiguate the issues. -Steve
One possibility is to simply say that property int foo(T x); always means a getter for T. This is because if you want to define a global with getter and setter you can always write a type with assignment and alias this. Andrei
Oct 09 2010
parent "Denis Koroskin" <2korden gmail.com> writes:
On Sat, 09 Oct 2010 23:37:51 +0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 10/9/10 13:33 CDT, Steven Schveighoffer wrote:
 On Fri, 08 Oct 2010 16:56:14 -0400, Nick Sabalausky <a a.a> wrote:

 Ugh, it seems D still doesn't quite understand the concept of a  
 property.
 Here:

  property int foo() // Obviously getter
  property void foo(int x) // Obviously setter

 No other form makes any sence as a property. Frankly, I'm very  
 surprised,
 and dissapointed, that anything else is even allowed. The only  
 *possible*
 exception being:

  property int foo(int x) // Combined getter/setter, if we decide that's
 needed

 It doesn't make any sense for a property getter to have a parameter
 (unless
 it's one parameter and it's used to set a new value). And it doesn't  
 make
 any sence for a setter to have anthing other than exactly one  
 parameter.
 Just disallow it. What could possibly be the point anyway? If it's got
 parameters it's a function call, not a variable.
Property setters can have two parameters, one is the item used to set it, and one is the rvalue to use when setting. In objects, the first parameter is the hidden this parameter. With UFC, the parameter is explicit. Unless you feel builtin arrays should never have properties? The only exception are global properties which are not set on anything. And this is the problem. I think the syntax discussed in the other part of this thread is probably a good way to disambiguate the issues. -Steve
One possibility is to simply say that property int foo(T x); always means a getter for T. This is because if you want to define a global with getter and setter you can always write a type with assignment and alias this. Andrei
I respectfully disagree. I strongly believe writing getters and setters should be a) consistent with each other and b) consistent with class/struct properties.
Oct 09 2010