<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Dec 17, 2012, at 1:06 AM, <a href="mailto:endlessroad1991@gmail.com">endlessroad1991@gmail.com</a> wrote:</div><blockquote type="cite"><div class="gmail_extra"><div class="gmail_quote">On Sat, Dec 15, 2012 at 2:50 AM, John McCall <span dir="ltr"><<a href="mailto:rjmccall@apple.com" target="_blank">rjmccall@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">
<div><div class="im"><div>On Dec 13, 2012, at 10:01 PM, <a href="mailto:endlessroad1991@gmail.com" target="_blank">endlessroad1991@gmail.com</a> wrote:</div><blockquote type="cite"><div class="gmail_quote">On Thu, Dec 13, 2012 at 4:23 PM, John McCall <span dir="ltr"><<a href="mailto:rjmccall@apple.com" target="_blank">rjmccall@apple.com</a>></span> wrote:<br>


<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"><div><div>On Dec 12, 2012, at 11:45 PM, <a href="mailto:endlessroad1991@gmail.com" target="_blank">endlessroad1991@gmail.com</a> wrote:</div>


<blockquote type="cite"><div>Thanks, that's a very detailed and thorough comment.</div><div> </div><div>MSDN page for __declspec(property): <a href="http://msdn.microsoft.com/en-us/library/yhfk0thd.aspx" target="_blank">http://msdn.microsoft.com/en-us/library/yhfk0thd.aspx</a></div>



<div>we can declare "array-like" property:</div><div>        __declspec(property(get=GetX, put=PutX)) int x[][];</div><div>and access it with indices:</div><div>        var = obj->x[expr1][expr2];</div><div>


it will be translated into:</div>
<div>        var = obj->GetX(expr1, expr2);</div><div> </div><div>And that's what "ParamCount" in "PropertyAttr" is for.</div><div>We don't know how many params until we parse to "int x[][]", so we have to modify the Attr when we get here.</div>


</blockquote><div><br></div></div><div>That documentation says you can declare this as "int x[]" and it permits an arbitrary amount of subscripts, but apparently you can *also* add multiple []s.  It would be good to understand the requirements and limitations of this language feature as implemented in MSVC.  In particular:</div>


<div><br></div><div>1.  Can you directly template these declarations? (template <class T> _declspec(property) T foo;)</div></blockquote><div>No </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">


<div><div>1a.  Are any of the following answers different if T is dependent, and if so, are those likely to be bugs or actually intended?</div><div>1b.  What if you have template <class T> struct A { _declspec(property) T foo; }; and then instantiate the template at T=int[]?</div>


</div></blockquote><div>Yes, this works fine. </div></div></blockquote><div><br></div></div><div>Does it add an expected index argument?</div><div class="im">  template <class T> struct A {</div><div>    int *getFoo() { .. }</div>
<div>    int getFoo(int index) { ... }</div><div>    _declspec(property(get=getFoo)) T foo;</div><div>  };</div><div><br></div><div>  int test(A<int[]> &a) {</div><div>    return a.foo[0];</div><div>  }</div><div>
<br></div><div>Does this call getFoo() or getFoo(int)?</div></div></blockquote><div>Doesn't compile. Return type of getters must be exactly the same as property type. </div></div></div></blockquote><div><br></div>Does it not compile at template-parse time, at instantiation time, or at time of first use?  In other words, does it not compile if you just have the template definition but don't use it?  What about if you have the template definition, and you instantiate it at some type, but you don't use the property declaration?</div><div><br></div><div><blockquote type="cite"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid; position: static; z-index: auto; ">
<div><div class="im"><br><blockquote type="cite"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid; position: static; z-index: auto; ">


<div><div>2.  What's the relationship between []s and the number of indices?</div><div>2a.  Given _declspec(property) int x[], can you in fact use multiple indices with it, like foo.x[2][3]?</div></div></blockquote>

<div>No </div></div></blockquote><div><br></div></div><div>Okay, that actually explicitly contradicts MS's own documentation that you linked above.  Make sure you test this with an unscriptable element type — like int, not int*.</div>
</div></blockquote><div>If getter with more/less parameters is defined, you can. Otherwise, you can't.</div></div></div></blockquote><div><br></div>Interesting.</div><div><br><blockquote type="cite"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid; position: static; z-index: auto; ">
<div><div class="im"><br><blockquote type="cite"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid; position: static; z-index: auto; ">
<div>2b.  If so, what happens if the "element type" is itself subscriptable?</div>

<div>2b.i. _declspec(property) std::vector<int> x[] and foo.x[0][1]?</div></blockquote><div>No </div></div></blockquote><div><br></div></div><div>What do you mean by "no" here?  Are you saying this program was rejected?  What's the error?</div>
</div></blockquote><div>Doesn't compile. Error says "GetX() doesn't accept 2 arguments", just like std::vector<int> is not subscriptable. </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid; position: static; z-index: auto; ">
<div><div class="im"><br><blockquote type="cite"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">


<div>2b.ii. _declspec(property) int *x[] and foo.x[0][1]?</div></blockquote><div>Yes, this works fine. </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid; position: static; z-index: auto; ">


<div><div>2c.  Do parentheses change these answers at all?</div><div>2c.i. _declspec(property) int* x[] and (foo.x[0])[1]?</div></div></blockquote><div>Yes, this works fine.</div></div></blockquote><div><br></div></div><div>
What about _declspec(property) int x[][] and (foo.x[0])[1]?</div></div></blockquote><div>Compiles and runs as expected. </div></div></div></blockquote><div><br></div><div>Okay.</div><br><blockquote type="cite"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid; position: static; z-index: auto; ">
<div><div><div class="im"><br><blockquote type="cite"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">


<div>2c.ii. For that matter, given _declspec(property) int x[], is (foo.x)[0] legal at all?</div></blockquote><div>Yes, this works fine.</div></div></blockquote><div><br></div></div>Okay, good.</div><div><div class="im">
<br><blockquote type="cite"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">

<div>2d.  Given _declspec(property) int x[][], can you use fewer subscripts than that?  Can you still use more?</div></blockquote><div>Answer for both questions is NO.</div></div></blockquote><div><br></div></div>Good.</div>
<div><div class="im"><br><blockquote type="cite"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">


<div>3.  Are there restrictions on the element type?</div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">
<div>3a.  Can it be a reference?</div></blockquote><div>Yes </div></div></blockquote><div><br></div></div><div>Okay.  If I have _declspec(property(get=getFoo)) int &foo, can I do</div><div>  x.foo = 7</div><div>with the semantics of x.getFoo() = 7?</div>
</div></div></blockquote><div>No. Seems that it's not that smart. All assignments will be translated into setters.</div></div></div></blockquote><div><br></div>Well, that does make it simple.</div><div> </div><div><blockquote type="cite"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid; position: static; z-index: auto; ">
<div><div><div class="im"><br><blockquote type="cite"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">


<div>3b.  Can it be a bounded array type?  (_declspec(property) int x[][10])</div></blockquote><div>No. Seems that whatever you put in the brackets will be ignored, and treated as a param to getter/setter. </div></div></blockquote>
<div><br></div></div>Okay.</div><div><div class="im"><br><blockquote type="cite"><div class="gmail_quote">

<blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid; position: static; z-index: auto; "><div>3c.  Can it be an unbounded array type if you use, e.g., a typedef?  (typedef int intarr[]; _declspec(property) intarr x;, or intarr x[] for that matter.)  Does this change the behavior of subscripting?</div>


</blockquote><div>Surprisingly, in this situation, the [] in intarr is still interpreted as a param to getter/setter. </div></div></blockquote><div><br></div></div><div>Alright.  My question above about template arguments is designed to figure out whether this is a hack for non-dependent type sugar, or whether it works through anything that extends the type this way.</div>
<div class="im"><div><br></div><blockquote type="cite"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">


<div><div>4.  What exactly does the element type do there?  Is it just for type-checking the property against the accessors?</div><div>4a.  I'd been assuming that the accessors were selected by overload resolution at access time using the name given/inferred in the property attribute.  Is this not true?  Are they selected/filtered by initial type-checking somehow?</div>


</div></blockquote><div>It is true. You can define "T GetV(int, int)" and "T GetV(double, double)". And getter will choose the best match like normal overload functions.</div></div></blockquote><div><br>
</div></div>Okay.</div><div><div class="im"><br><blockquote type="cite"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">


<div><div>4b.  Is access control checked on the accessors from the declaration point of the property or from the use point?</div><div>4c.  Can the accessors be inherited from base classes?  Are normal ambiguity controls enforced?  Can you scope-qualify the accessor names, e.g. get=Base1::getElt?</div>


</div></blockquote><div>Inherit: yes. Ambiguity: yes. Scope-quailify: No, seems that there can only be one identifier after get= or put=. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">


<div>4d.  Are the index types in the accessors limited in some way, or can they be e.g. arbitrary class types?</div></blockquote><div>They can be arbitary types. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid">


<div><div><br></div><div>I'm sure we can find more questions. :)</div><div><div><br></div><blockquote type="cite"><div>Considering this situation, is it still possible to do it in your suggested way?</div>
</blockquote><div><br></div></div><div>Sure, that's not really a problem.  One very important thing — something I seem to have unconscionably forgotten put in my initial review — is that this is way, way more than just a property on a FieldDecl;  this really needs to be some new kind of Decl, probably named MSPropertyDecl.  That node would then be a reasonable place to stash things like the expected (minimum?) number of indices and any other important information from type-checking the declaration, e.g. the possibly-filtered lookup results.  You'll probably need to recognize the presence of the attribute in the parser and enter into a completely different Sema entrypoint, kindof like how the 'friend' keyword does.</div>


<span><font color="#888888"><div><br></div><div>John.</div></font></span></div></blockquote></div><div class="gmail_extra"><br> </div><div class="gmail_extra">Based on answers of these questions, let's guess how VC implements property.</div>


<div class="gmail_extra">I think the design principle for them is, reuse existing compiler code as much as possible, and make the solution as simple as possible.</div><div class="gmail_extra">Here are my opinions:</div><div class="gmail_extra">


1. Any [], [10], or [] that comes from typedef, is treated as a param to getter/setter. Hence, they lose their origin semantics meaning.</div></blockquote><div><br></div></div>Right, you need to walk through type sugar.  If template instantiation can't add to the number of arguments, then you'll need to do this at template parse time and then remember it in the MSPropertyDecl.</div>
<div><div class="im"><br><blockquote type="cite"><div class="gmail_extra">2. For accessors, they will be translated into getter/setter.</div>

<div class="gmail_extra">    i. property can be private, as long as getter/setter is public, they work well.</div></blockquote><div><br></div></div>Oh, now that's interesting.  Okay, you'll have to suppress access control on a member lookup that resolves to one of these.</div>
<div><div class="im"><br><blockquote type="cite"><div class="gmail_extra">    ii. getter/setter will be chosen like any normal overloaded functions.</div><div class="gmail_extra">

3. property are treated like normal members. So they can be inherited, and have ambiguity problem when a class has multiple base classes.</div><div class="gmail_extra">The only problem here, is when the element type is subscriptable itself.</div>

<div class="gmail_extra">    i. When it's pointer type, subscripting the property works as expected.</div><div class="gmail_extra">    ii. When it's class type which has overwritten operator[] (no matter vector or self-defined class),  subscripting the property doesn't compile.</div>

<div class="gmail_extra">I can't guess why this happens.<br clear="all"></div></blockquote><div><br></div></div>If int x[] can, in fact, take more than one subscript (as documented), then I would guess that the rule is that all possible subscripts are consumed by the property *unless* the element type is "obviously subscriptable", which is probably defined as "a pointer type" and doesn't recognize classes with operator[]s.  Interesting corner cases here would be</div>
<div>  int *&x[]; // does it realize that this result type is still "obviously subscriptable"?</div><div>  int *x[]; // if I do a.x[0][1][2], does it steal both [0] and [1] for the subscript, or does it steal just [0] and then try to subscript int* twice (which will fail, of course)?</div>
</div></blockquote><div>Here's two good samples, I think:</div><div> </div><div>#include <iostream></div><div>class C<br>{<br>public:<br> __declspec(property(get=GetA, put=SetA)) int **A[];<br> int** GetA(int i) { std::cout << "Get\n"; return &v; }<br>
 void SetA(int i, int **value) { std::cout << "Set\n";}<br> int *v;<br>};</div><div>int main()<br>{<br> C c;<br> c.A[123][0][0] = 2; // GetA()<br> // c.A[123][0] = 2; // doesn't compile! "Cannot convert int to int*"<br></div></div></div></blockquote><div><br></div>Well, that's true, you can't.  But if the RHS were (int*) 2, this would presumably compile (calling GetA()).</div><div><br></div><div><blockquote type="cite"><div class="gmail_extra"><div class="gmail_quote"><div>
 c.A[1] = 0; // SetA()<br>}</div><div> </div><div> </div><div>#include <iostream></div><div>class C<br>{<br>public:<br> __declspec(property(get=GetA, put=SetA)) int *A[];<br> int* GetA(int i) { std::cout << "Get 1\n"; return v; }<br>
 int* GetA(int i, int j) { std::cout << "Get 2\n"; return v; }<br> void SetA(int i, int *value) { std::cout << "Set 1\n"; }<br> void SetA(int i, int j, int *value) { std::cout << "Set 2\n"; }<br>
 int *v;<br>};</div><div>int main()<br>{<br> C c;<br> c.A[123][0] = 2; // Get 1<br> c.A[1] = 0; // Set 1<br>}</div></div></div></blockquote><div><br></div>Very nice test case.  Okay, one more:</div><div><br></div><div><blockquote type="cite"><div class="gmail_extra"><div class="gmail_quote">class C<br>{<br>public:<br> __declspec(property(get=GetA, put=SetA)) int *A[];<br> int* GetA(int i) { std::cout << "Get 1\n"; return v; }<br> int* GetA(std::string i, std::string j) { std::cout << "Get 2\n"; return v; }<br> void SetA(int i, int *value) { std::cout << "Set 1\n"; }<br> void SetA(std::string i, std::string j, int *value) { std::cout << "Set 2\n"; }<br> int *v;<br>};</div></div></blockquote><div><div class="gmail_extra"><div class="gmail_quote"><div><blockquote type="cite"><div class="gmail_extra"><div class="gmail_quote">int main()<br>{<br> C c;<br> c.A["a"]["b"][4] = 2;<br> c.A["a"]["b"] = 0;<br>}</div></div></blockquote><div><div class="gmail_extra"><div class="gmail_quote"><br></div></div></div></div></div><div class="gmail_quote">Do these lines compile?</div><div class="gmail_quote"><br></div><div class="gmail_quote">If not, and the error's something like "cannot subscript an int* with a const char(&)[2]",</div><div class="gmail_quote">then I think the rule is that you look at the getters and setters (at class parse time),</div><div class="gmail_quote">find the minimum number of arguments, and then consume that number of</div><div class="gmail_quote">subscripts.  (It'd be good to figure out what happens if the getters and setters are</div><div class="gmail_quote">mismatched in argument counts.)</div><div class="gmail_quote"><br></div><div class="gmail_quote">If so, then the rule may have to be "apply overload resolution with successively</div><div class="gmail_quote">more and more subscripts, stopping as soon as something succeeds".</div><div class="gmail_quote"><br></div><div class="gmail_quote">John.</div></div></div></div></body></html>