Properties

Denis Koroskin 2korden at gmail.com
Sat Jan 10 22:35:13 PST 2009


On Sun, 11 Jan 2009 07:50:03 +0300, Andrei Alexandrescu <SeeWebsiteForEmail at 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.



More information about the Digitalmars-d mailing list