January 24, 2013
On Thursday, 24 January 2013 at 08:35:01 UTC, Walter Bright wrote:
> This has turned into a monster. We've taken 2 or 3 wrong turns somewhere.
>
> Perhaps we should revert to a simple set of rules.
>
> 1. Empty parens are optional. If there is an ambiguity with the return value taking (), the () go on the return value.
>
> 2. the:
>    f = g
> rewrite to:
>    f(g)
> only happens if f is a function that only has overloads for () and (one argument). No variadics.
>
> 3. Parens are required for calling delegates or function pointers.
>
> 4. No more @property.

Under the proposed rules, which of the lines in the output of the following program will be the same?

---
import std.stdio;

int globalInt = 42;
auto ref g() {
    return globalInt;
};
auto globalG = &g;

auto ref f() {
    return globalG;
}

void main() {
    writeln("&globalInt: ", &globalInt);
    writeln("globalInt: ", globalInt);
    writeln("&globalG: ", &globalG);
    writeln("globalG: ", globalG);
    writeln("---");
    writeln("&f: ", &f);
    writeln("&f(): ", &f());
    writeln("&g: ", &g);
    writeln("&g(): ", &g());
}
---

Also, don't forget that @property was actually introduced to solve specific syntactic issues, not just because somebody didn't like the laxness of the previous rules.

Now, yes, the current implementation in DMD doesn't solve the issues, while introducing new issues by disallowing parameterless function calls altogether. But I think the last larger discussion on the topic some two to three months ago produced a set of @property rules that would actually work. I think there is a summary in DIP21.

Anyway, I think you should turn your proposal into a DIP, and better sooner than later so that the details on the edge cases, impact in terms of breaking code, … aren't lost in an endless forum discussion.

David
January 24, 2013
Am 24.01.2013 09:34, schrieb Walter Bright:
> This has turned into a monster. We've taken 2 or 3 wrong turns somewhere.
> 
> Perhaps we should revert to a simple set of rules.

I think Adam D. Ruppe has proposed this in the past and, although I don't really like omitting parentheses on ordinary function calls in general (apart from UFCS template functions), it's clear, simple and I think everyone could be happy with it:

1. Normal function calls _may_ omit parentheses, but "a = b" is _not_ interpreted as "a(b)"
2. @property functions can _not_ be called with parentheses and "a = b" _is_ interpreted as "a(b)"
3. Calling a normal function always returns its return value

> 
> 1. Empty parens are optional. If there is an ambiguity with the return value taking (), the () go on
> the return value.

This sounds like a recipe for disaster. Thinking about generic code calling functions... it would surely be very surprising to see how f() sometimes does not return ReturnType!f, but something completely different. It would also break all existing code that currently expects f() to simply return its return value. More importantly, adding or removing an opCall or changing the return type of a function would possibly silently change the meaning of code that calls the function.

IMO it is also utterly unexpected/counter-intuitive for a seeming function call not to return its return value, but call it and return the result.

> 
> 2. the:
>    f = g
> rewrite to:
>    f(g)
> only happens if f is a function that only has overloads for () and (one argument). No variadics.

I can live with omitted parentheses (*). However, what's really ugly is picking the unintended form
in case of a setter (i.e. both, "obj.prop(value)" instead of "obj.prop = value;", or "countElements
= obj;" instead of "obj.countElements()").

And in my experience, people /will/ mix the different forms all over the place. So although I know that some people have a different opinion, I still find it a very useful thing to be able to force correct usage up to a certain degree - stylistically and to avoid ambiguities (not only for the compiler, but also for a human reader). Adam's proposal solves this nicely and it's about as simple as it gets.

(*) IMO they are kind of ugly semantically if they are omitted for anything else than properties or UFCS-template functions, but you may well call that a matter of taste

> 
> 3. Parens are required for calling delegates or function pointers.
> 
> 4. No more @property.


January 24, 2013
On 01/24/13 12:50, mist wrote:
> But looking at other comments this does not seem popular :(

Language design is not a popularity contest.

artur
January 24, 2013
On 24 January 2013 08:34, Walter Bright <newshound2@digitalmars.com> wrote:

> This has turned into a monster. We've taken 2 or 3 wrong turns somewhere.
>
> Perhaps we should revert to a simple set of rules.
>
> 1. Empty parens are optional. If there is an ambiguity with the return
> value taking (), the () go on the return value.
>
> 2. the:
>    f = g
> rewrite to:
>    f(g)
> only happens if f is a function that only has overloads for () and (one
> argument). No variadics.
>
> 3. Parens are required for calling delegates or function pointers.
>
> 4. No more @property.
>


As much as I want to agree, I also feel this comes as too little, too late to come to this conclusion now.


-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';


January 24, 2013
> As much as I want to agree, I also feel this comes as too little, too late to come to this conclusion now.
>

+1

And therefor we should take out @property ASAP :-)


January 24, 2013
On Thursday, 24 January 2013 at 08:35:01 UTC, Walter Bright wrote:
> This has turned into a monster. We've taken 2 or 3 wrong turns somewhere.
>

I'm so happy to read this !!!!

> Perhaps we should revert to a simple set of rules.
>
> 1. Empty parens are optional. If there is an ambiguity with the return value taking (), the () go on the return value.
>
> 2. the:
>    f = g
> rewrite to:
>    f(g)
> only happens if f is a function that only has overloads for () and (one argument). No variadics.
>
> 3. Parens are required for calling delegates or function pointers.
>
> 4. No more @property.

I'm so unhappy to read this :(((((((

Ok let me be more constructive. The current state of thing have 2 issues : on is that non properties are conflated with properties, and the other is that setter is conflated with getter.

You solution isn't good because it conflate things even more. Here is my proposal :

For regular functions :
1. funName is the function itself :
  void funName() {}
  static assert(is(typeof(funName) == void function())); // Pass.
  funName has no address, it is equivalent to enum function void() funName = {};
  &funName become a NOOP and is deprecated, for compatibility reasons. It is not ambiguous as funName has no address anyway.

2. funName() call the function.

Rationale : function as variable or defined in the source now behave the same way (expect the deprecated & behavior). It makes it easier to write generic code, and in general consistency is a plus (easier to learn the language, less dark corner case to consider, easier interaction with other features).

3. @getter is an attribute. A function marked @getter is automatically executed : () is added automatically :
    @getter void funName() {}
    funName; // function get executed.
    funName(); // Error, void is not callable.

4. @getter can be used as UFCS.
   @getter void funName(T t) {}
   T t; t.funName; // function gets executed.
   funName(t); // Error, funName require 1 argument, 0 given.

5. @setter is an attribute. A setter method can *only* be used in rhs of an expression. The assigned value is used as argument.
   @setter void funName(T t) {}
   T t; funName = t; // function gets executed.
   funName(t); // Error, funName must be used in an assign expression.

6. @setter can as well be used as UFCS :
   @getter void funName(T t, U u) {}
   T t; U u; t.funName = u; // function gets executed.
   t.funName(u); // Error, funName must be used in an assign expression.

7a. A function can be defined as both @setter and @getter, and cumulate both behavior.
7b. @property is deprecated and redefined as @setter *and* @getter for a transitional period.

8. method behave as functions :
    class A { void foo() {} }
    A a;
    static assert(is(typeof(a.foo) : void delegate())); // Pass.
    &a.foo; // deprecated NOOP for compatibility.
    a.foo(); // call a.foo

9. UFCS without () are delegate like construct :
    void foo(T t) {}
    T t; t.foo; // Is a struct with a function pointer and t. (equivalent to a delegate). The struct member's type is the same as the first argument. If a copy is necessary postblit is called - but will not be called at function call. If foo take a reference, a pointer is stored.
    t.foo(); // call foo with t as parameter.

10. To allow chain of UFCS calls without () everywhere, an opDispatch is defined in object.d : the function/delegate get's called and the result is used as parameter for foo. This eliminate the need for () on all functions of an UFCS chain expect the last one, which is a price to pay for cleanly defined, unambiguous semantic.

Waiting for the shitstorm . . .
January 24, 2013
On 2013-01-24 14:01, bearophile wrote:
> Jacob Carlborg:
>
>> It would break tons of code.
>
> How much work does it take to change that makes and compilation scripts
> to compile that code using a "-noproperty" switch?

No one can answer that.

> I think this silly fear of breaking user code was one of the main causes
> of the failure of @property in the first place. If you introduce a new
> feature, then you need to introduce it cleanly since the beginning,
> otherwise you will make a mess. So future D feature must be introduced
> in a much more clean way in future, or not introduced at all.

I agree with you but Walter is very afraid of breaking code.

-- 
/Jacob Carlborg
January 24, 2013
No, god no. This would break code AGAIN and still not fix the problems, instead introducing new ones!

I think any property proposal that talks about parenthesis in the definition is wrong. With a good definition, the existing type system will handle the parenthesis.

@property int foo() { return 10; }

foo(); // the correct error is "type int is not callable"

This is the key point:

A property is NOT a function as far as user code is concerned. That's just an implementation detail.

As far as user code is concerned, a property IS its return value.


If you implement that, leaving all the other rules in the language exactly the same, we'll actually fix some problems without breaking the overwhelming bulk of existing code.


Fixing the rest of the problems is then about getting op*Assign to work right.



Functions not marked @property should NOT change AT ALL from what we have now. I am against removing the existing optional parenthesis rule, and I am against removing the @property decoration.

Fix it this time, don't break it in a different place.
January 24, 2013
On 2013-01-24 14:01, mist wrote:

> And yet it must have been done at some point. With some year-ahead
> announcement or anything like that, but it was a horrible design error
> in first place which needs to be fixed.

Yes, it was a horrible design error but it didn't break any code because the -property flag is optional.

-- 
/Jacob Carlborg
January 24, 2013
On Thursday, 24 January 2013 at 12:13:57 UTC, Bernard Helyer wrote:
> On Thursday, 24 January 2013 at 08:35:01 UTC, Walter Bright wrote:
>
> @property functions may be called with no parens or with assignment as
> the singular argument. Non @property functions may not.
>
> There. No complications. The only complications come from D's history.

I would say: kill -property, not @property.