www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Properties: problems

reply John C <johnch_atms hotmail.com> writes:
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).
Jul 29 2009
parent reply Chad J <chadjoan __spam.is.bad__gmail.com> writes:
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.
Jul 29 2009
next sibling parent reply John C <johnch_atms hotmail.com> writes:
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.
Jul 30 2009
next sibling parent Benji Smith <dlanguage benjismith.net> writes:
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
Jul 30 2009
prev sibling parent Chad J <chadjoan __spam.is.bad__gmail.com> writes:
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.
Jul 31 2009
prev sibling parent John C <johnch_atms hotmail.com> writes:
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).
Jul 30 2009