View mode: basic / threaded / horizontal-split · Log in · Help
July 29, 2009
Properties: problems
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
Re: Properties: problems
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
Re: Properties: problems
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
Re: Properties: problems
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
Re: Properties: problems
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
Re: Properties: problems
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.
Top | Discussion index | About this forum | D home