Thread overview
Properties: problems
Jul 29, 2009
John C
Jul 29, 2009
Chad J
Jul 30, 2009
John C
Jul 31, 2009
Benji Smith
Jul 31, 2009
Chad J
Jul 30, 2009
John C
July 29, 2009
Here's a couple of annoying problems I encounter quite often with D's properties. Would having some form of property syntax fix them?

1) Array extensions:

  class Person {

    string name_;

    string name() {
      return name_;
    }

  }

  auto person = getPerson();
  auto firstAndLast = person.name.split(' ');

The above line currently requires parentheses after 'name' to compile.

2) Indexing:

  struct Map(K, V) {

    void opIndexAssign(V value, K key) { ... }
    V opIndex(K key) { ... }

  }

  class WebClient {

    private Map!(string, string) headers_;

    Map!(string, string) headers() {
      return headers_;
    }

  }

  auto client = new WebClient();
  client.headers["User-Agent"] = "MyWebClient";

The compiler says client.headers() is not an lvalue (adding 'ref' in D2 changes nothing).
July 29, 2009
John C wrote:
> Here's a couple of annoying problems I encounter quite often with D's properties. Would having some form of property syntax fix them?
> 
> 1) Array extensions:
> 
>   class Person {
> 
>     string name_;
> 
>     string name() {
>       return name_;
>     }
> 
>   }
> 
>   auto person = getPerson();
>   auto firstAndLast = person.name.split(' ');
> 
> The above line currently requires parentheses after 'name' to compile.
> 

This one is weird.  After defining getPerson() I was able to rewrite the last line into this and make it compile:

	auto firstAndLast = split(person.name," ");

Note that you need qoutes, not just ' '.
But even

	auto firstAndLast = person.name.split(" ");

does not compile.
main2.d(36): Error: function expected before (), not
split(person.name()) of type immutable(char)[][]

This is probably a compiler bug.

I don't think property syntax is truly necessary for this example.  You are fortunate enough to be using strings, which are passed by reference.

> 2) Indexing:
> 
>   struct Map(K, V) {
> 
>     void opIndexAssign(V value, K key) { ... }
>     V opIndex(K key) { ... }
> 
>   }
> 
>   class WebClient {
> 
>     private Map!(string, string) headers_;
> 
>     Map!(string, string) headers() {
>       return headers_;
>     }
> 
>   }
> 
>   auto client = new WebClient();
>   client.headers["User-Agent"] = "MyWebClient";
> 
> The compiler says client.headers() is not an lvalue (adding 'ref' in D2
> changes nothing).

This is nearly the same thing as the "a.b.c = 3;" example given in the "a.b.c = 3;" thread.  The .b is your .headers.  It's slightly more forgiving though, since you are calling a function on the returned struct and not accessing a field.  The setter never needs to be called in your example.

I'll use the compiler's rewritting technique to show you what it looks like:

client.headers["User-Agent"] = "MyWebClient";
client.headers.opIndexAssign("User-Agent","MyWebClient");
client.headers().opIndexAssign("User-Agent","MyWebClient");

client.headers() creates a /new/ Map!(...) struct, so the opIndexAssign
will not be called on the one you want it to be called on.

Adding 'ref' should change that.  That sounds like a bug.

In this specific example, property syntax is not truly necessary.  That ref returns were added should make this doable.
July 30, 2009
Chad J wrote:
> John C wrote:
>> Here's a couple of annoying problems I encounter quite often with D's
>> properties. Would having some form of property syntax fix them?
>>
>> 1) Array extensions:
>>
>>   class Person {
>>
>>     string name_;
>>
>>     string name() {
>>       return name_;
>>     }
>>
>>   }
>>
>>   auto person = getPerson();
>>   auto firstAndLast = person.name.split(' ');
>>
>> The above line currently requires parentheses after 'name' to compile.
>>
> 
> This one is weird.  After defining getPerson() I was able to rewrite the
> last line into this and make it compile:
> 
> 	auto firstAndLast = split(person.name," ");

Yes, that's D's special array syntax, where free functions can be called as if they were "methods" of an array.

> 
> Note that you need qoutes, not just ' '.

My mistake.

> But even
> 
> 	auto firstAndLast = person.name.split(" ");
> 
> does not compile.
> main2.d(36): Error: function expected before (), not
> split(person.name()) of type immutable(char)[][]
> 
> This is probably a compiler bug.

This is my point. The compiler can't tell that "name" is a property, so it expects parentheses "name()" to work. That's the problem.

> 
> I don't think property syntax is truly necessary for this example.  You
> are fortunate enough to be using strings, which are passed by reference.

Sorry, I don't see how this statement is relevant at all.
July 30, 2009
Chad J wrote:
> John C wrote:
> 
>> 2) Indexing:
>>
>>   struct Map(K, V) {
>>
>>     void opIndexAssign(V value, K key) { ... }
>>     V opIndex(K key) { ... }
>>
>>   }
>>
>>   class WebClient {
>>
>>     private Map!(string, string) headers_;
>>
>>     Map!(string, string) headers() {
>>       return headers_;
>>     }
>>
>>   }
>>
>>   auto client = new WebClient();
>>   client.headers["User-Agent"] = "MyWebClient";
>>
>> The compiler says client.headers() is not an lvalue (adding 'ref' in D2
>> changes nothing).
> 
> This is nearly the same thing as the "a.b.c = 3;" example given in the
> "a.b.c = 3;" thread.  The .b is your .headers.  It's slightly more
> forgiving though, since you are calling a function on the returned
> struct and not accessing a field.  The setter never needs to be called
> in your example.
> 
> I'll use the compiler's rewritting technique to show you what it looks like:
> 
> client.headers["User-Agent"] = "MyWebClient";
> client.headers.opIndexAssign("User-Agent","MyWebClient");
> client.headers().opIndexAssign("User-Agent","MyWebClient");
> 
> client.headers() creates a /new/ Map!(...) struct, so the opIndexAssign
> will not be called on the one you want it to be called on.
> 
> Adding 'ref' should change that.  That sounds like a bug.
> 
> In this specific example, property syntax is not truly necessary.  That
> ref returns were added should make this doable.

It actually works if the "ref" is attached not to the WebClient.headers property, but to the Map.opIndex operator (and opIndexAssign is removed, or course).
July 31, 2009
John C wrote:
> Chad J wrote:
>> John C wrote:
>>> Here's a couple of annoying problems I encounter quite often with D's
>>> properties. Would having some form of property syntax fix them?
>>>
>>> 1) Array extensions:
>>>
>>>   class Person {
>>>
>>>     string name_;
>>>
>>>     string name() {
>>>       return name_;
>>>     }
>>>
>>>   }
>>>
>>>   auto person = getPerson();
>>>   auto firstAndLast = person.name.split(' ');
>>>
>>> The above line currently requires parentheses after 'name' to compile.
>>>
>>
>> This one is weird.  After defining getPerson() I was able to rewrite the
>> last line into this and make it compile:
>>
>>     auto firstAndLast = split(person.name," ");
> 
> Yes, that's D's special array syntax, where free functions can be called as if they were "methods" of an array.

Yeah, this is one of those nasty cases where several different features (optional parentheses on functions & automatic extension method syntax on arrays) work ok in isolation, but where they have weird wonky behavior when combined. I've seen this one before.

--benji
July 31, 2009
John C wrote:
> Chad J wrote:
>> John C wrote:
>>> Here's a couple of annoying problems I encounter quite often with D's properties. Would having some form of property syntax fix them?
>>>
>>> 1) Array extensions:
>>>
>>>   class Person {
>>>
>>>     string name_;
>>>
>>>     string name() {
>>>       return name_;
>>>     }
>>>
>>>   }
>>>
>>>   auto person = getPerson();
>>>   auto firstAndLast = person.name.split(' ');
>>>
>>> The above line currently requires parentheses after 'name' to compile.
>>>
>>
>> This one is weird.  After defining getPerson() I was able to rewrite the last line into this and make it compile:
>>
>>     auto firstAndLast = split(person.name," ");
> 
> Yes, that's D's special array syntax, where free functions can be called as if they were "methods" of an array.
> 
>>
>> Note that you need qoutes, not just ' '.
> 
> My mistake.
> 
>> But even
>>
>>     auto firstAndLast = person.name.split(" ");
>>
>> does not compile.
>> main2.d(36): Error: function expected before (), not
>> split(person.name()) of type immutable(char)[][]
>>
>> This is probably a compiler bug.
> 
> This is my point. The compiler can't tell that "name" is a property, so it expects parentheses "name()" to work. That's the problem.
> 

I'm saying this actually should work in current D2.

>>
>> I don't think property syntax is truly necessary for this example.  You are fortunate enough to be using strings, which are passed by reference.
> 
> Sorry, I don't see how this statement is relevant at all.

It's the pointed answer to your question:

>>> Here's a couple of annoying problems I encounter quite often with D's properties. Would having some form of property syntax fix them?

They should work already, so property syntax can't possibly fix them. At least not on a conceptual level.  On a practical level, it is quite possible that property syntax would improve the situation, if only because the information is provided to the compiler in a much more direct manner.