On Sun, 11 Jan 2009 07:50:03 +0300, Andrei Alexandrescu 
<seewebsiteforem...@erdani.org> wrote:

Miles wrote:
Daniel Keep wrote:
Yes, property syntax can simplify some cases, but this isn't one of them.
 One good distinction properties and normal functions ought to make is
that functions should never be called without (), and properties should
never have () unless it has a function type.
 Current syntax allows crazy things like:
 ----------
        exit = 1;       // it is not an assignment
        x = toString = getenv = "PATH";       // creepy, but valid D
        if (fork == 1)  // not comparing the value of a variable
----------

Walter and I see eye to eye that a possible solution would be to only allow the a = b syntax as an alternative for a(b) only if there's also a function a(). All of the above can be fixed within that framework.


It was criticized many times by different people as being a too complex and 
obscure rule.

First, you allow to omit empty pair of braces. Now you understand that it was a 
bad idea as it bring to many problems and ambiguities. But instead of /fixing/ 
the source of the issues, you are trying to /reduce/ number of those issues (by 
narrowing range of cases where omitting parens allowed). That's a wrong way to 
go. You can reduce them, but you can't eliminate them entirely this way.

It doesn't allow authors to define what is callable with property syntax and 
what is not. For example, I know many people that never use default function 
arguments because they cause too many problems with inheritance (some of them 
come from languages that doesn't allow them at all). Instead, the define two 
distinct functions:

class Foo
{
   int bar(int i)
   {
       // do something more intelligent here
       return i;
   }

   int bar()
   {
       // call main function with default arguments.
       // Default arguments may be overridden in derived class.
       return bar(42);
   }
}

And a Pandora's Box is open:

Foo foo = new Foo();
foo.bar = -1;

One more case - properties can not return references:

class Foo
{
   ref int bar()
   {
       return _bar;
   }

   private int _bar;
}

Foo foo = new Foo();
foo.bar = -1;

test.d(17): function test.Foo.bar () does not match parameter types (int)
test.d(17): Error: expected 0 arguments, not 1

Nevertheless, let's assume it is a bug and it will be fixed (one more case 
where optional parens feature causes a compiler bug).
Then, what does the following code do:

class Foo
{
   ref int bar()
   {
       return _bar;
   }

   void bar(int i)
   {
       _bar = i;
   }

   private int _bar;
}

Foo foo = new Foo();
foo.bar = -1; // which one of the functions is called? Both are suitable.

Compare it with the following one:

class Foo
{
   void bar(int i = 0) {}       
   void bar() {}
}

Foo foo = new Foo();
foo.bar(); // which one is called?

DMC result for reference:
       a.foo();
             ^
test.cpp(20) : Error: ambiguous reference to symbol
Had: A::foo()
and: A::foo(int )

Besides, it has nothing to do with issue below:

Also, currently, in D, if you have a property of a delegate type, you
will have a mess.
 ----------
        int func2() { return 42; }
        /* this is a property */
        int function() prop() {
                return &func2;
        }
        
        void main() {
                auto x = prop;          // ok, x is a func ptr
                auto y = prop();        // unexpected: y is not int :-(
                static assert (is(typeof(y) == int));
        }
----------
 With properties, you forbid the above syntaxes.

Well the above syntaxes could be forbidden other ways too.


Andrei

They should not be forbidden, they should be allowed!

Imagine a struct that emulates virtual behavior with methods as first-class 
objects:

struct Message
{
   string text;

   void delegate() show() // property getter
   {
       return _showDg;
   }

   void show(void delegate(ref Message message) dg) // property setter
   {
       _showDg = () { dg(this); }
   }

   private void delegate() _showDg;
}

auto showDg1 = (ref Message msg) { writefln(msg.text); } // output to stdout
auto showDg2 = (ref Message msg) { MessageBox(0, "Message", msg.text, 0); } // 
show a message box

Message message;
message.text = "Hello World";

message.show = showDg1;
message.show()(); // works but requires two pair of braces

message.show = showDg2;
message.show();   // this is a goal

How would you /allow/ that? Why don't you see that non-mandatory parens bring 
more troubles than it /tries/ to solve.

Reply via email to