www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - proposal to disambiguate &a.fun: disable optional parenthesis INSIDE

reply "timotheecour" <thelastmammoth gmail.com> writes:
There's current disagreement regarding the syntax &a.fun, as it 
makes &a.fun be different from &(a.fun):
&a.fun   : address of member function
&(a.fun) : address of return value of a.fun

This breaks the usual rules of scoping and makes the expression 
&a.fun special. More complex cases can arise, eg: &a.b.c, 
&(a+b).c, etc as pointed out by others, plus who knows what else 
might come up in practice.

Here's a very simple proposal:

for anything INSIDE &() operator, optional parenthesis are NOT 
allowed:

&(fun) : address of function fun
&(a.fun) : address of member function fun (different from DIP23)
&(a.fun()) : address of element returned by a.fun()
&fun : same as &(fun)

Now when fun is a  property: I would propose to break one rule to 
make everything else more consistent: treat properties as normal 
functions inside the &() operator, so that we can distinguish as 
above the address of property vs adress of return type. This is 
the only time a property can be called with parens: eg
&(a.fun) : address of property fun
&(a.fun()) : address of return type of property fun


The last point of this proposal is what to do with the expression 
without parens:
&a.fun : current behavior in DIP23: address of member function fun
proposed behavior: there are 3 options, please chime in:

A1) disallow this with compile time error, forcing user to 
disambiguate as:
  - (&a).fun
  - &(a.fun)
  - &(a.fun())

A2) interpret it as : (&a).fun, which would make the rule for "&" 
consistent with the rule for template "!" operator: B!double.x 
<=> (B!(double)).x)
----
template B(T){	T x; }
void main(){assert(is(typeof(B!double.x) == double)); //same as 
(B!(double)).x) }
----

A3) decide whether to interpret it as address of function or of 
return type, but again, the user  can disambiguate with the 
preferred &() syntax.
Feb 04 2013
next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 4 February 2013 at 10:09:09 UTC, timotheecour wrote:
 There's current disagreement regarding the syntax &a.fun, as it 
 makes &a.fun be different from &(a.fun):
 &a.fun   : address of member function
 &(a.fun) : address of return value of a.fun

 This breaks the usual rules of scoping and makes the expression 
 &a.fun special. More complex cases can arise, eg: &a.b.c, 
 &(a+b).c, etc as pointed out by others, plus who knows what 
 else might come up in practice.

 Here's a very simple proposal:

MOAR special cases !
Feb 04 2013
prev sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 4 February 2013 at 10:09:09 UTC, timotheecour wrote:
 There's current disagreement regarding the syntax &a.fun, as it 
 makes &a.fun be different from &(a.fun):
 &a.fun   : address of member function
 &(a.fun) : address of return value of a.fun

 This breaks the usual rules of scoping and makes the expression 
 &a.fun special. More complex cases can arise, eg: &a.b.c, 
 &(a+b).c, etc as pointed out by others, plus who knows what 
 else might come up in practice.

 Here's a very simple proposal:

 for anything INSIDE &() operator, optional parenthesis are NOT 
 allowed:

 &(fun) : address of function fun
 &(a.fun) : address of member function fun (different from DIP23)
 &(a.fun()) : address of element returned by a.fun()
 &fun : same as &(fun)

 Now when fun is a  property: I would propose to break one rule 
 to make everything else more consistent: treat properties as 
 normal functions inside the &() operator, so that we can 
 distinguish as above the address of property vs adress of 
 return type. This is the only time a property can be called 
 with parens: eg
 &(a.fun) : address of property fun
 &(a.fun()) : address of return type of property fun


 The last point of this proposal is what to do with the 
 expression without parens:
 &a.fun : current behavior in DIP23: address of member function 
 fun
 proposed behavior: there are 3 options, please chime in:

 A1) disallow this with compile time error, forcing user to 
 disambiguate as:
  - (&a).fun
  - &(a.fun)
  - &(a.fun())

 A2) interpret it as : (&a).fun, which would make the rule for 
 "&" consistent with the rule for template "!" operator: 
 B!double.x <=> (B!(double)).x)
 ----
 template B(T){	T x; }
 void main(){assert(is(typeof(B!double.x) == double)); //same as 
 (B!(double)).x) }
 ----

 A3) decide whether to interpret it as address of function or of 
 return type, but again, the user  can disambiguate with the 
 preferred &() syntax.

As I asked in the other thread: What is the point of even allowing taking the address of a property function? If a property is designed as something that can encapsulate and emulate a field, then it makes to sense to get the address of the getter (As far as I can tell). If we already have optional parenthesis, then why even bother having property getters? They would end up being exactly the same thing as a normal function... I say that if "b" is a property, then "a.b" should mean "the thing returned by b", *regardless of context*. Simple as that: "&a.b" => address of what is gotten with "a.b" "&(a.b)" => address of what is gotten with "a.b" Simple, no? As for "how do I take the address of the function b": "You can't".
Feb 04 2013
parent reply FG <home fgda.pl> writes:
On 2013-02-04 11:20, monarch_dodra wrote:
 As I asked in the other thread: What is the point of even allowing taking the
 address of a property function? If a property is designed as something that can
 encapsulate and emulate a field, then it makes to sense to get the address of
 the getter (As far as I can tell).

Yes, but this is not just about properties but also normal functions: foo; // calling foo &foo; // delegate of foo &foo(); // calling and taking address of ref return &(foo());// calling and taking address of ref return &(foo); // OLD: delegate of foo &(foo); // NEW: calling foo and taking address of ref return The change in behavior of &(expr) makes sense in the light that "expr" should behave the same in every context, not just in &(...), i.e. call foo(). As for properties, they will never be truly exchangeable with variables, therefore being able to pass around their function pointers is useful. Naturally taking their address doesn't have to follow the same rules, but why shouldn't they behave like other functions in "typeof(&prop)"?
 If we already have optional parenthesis, then why even bother having property
 getters? They would end up being exactly the same thing as a normal function...

Indeed, their existence is not essential. They may be more useful when the operator rewriting is done. The biggest problem is with the amount of code that uses "prop = x" syntax, which doesn't play well with optional parentheses.
 if "b" is a property, then "a.b" should mean "the thing returned by b",
 *regardless of context*. Simple as that:
 "&a.b"   => address of what is gotten with "a.b"
 "&(a.b)" => address of what is gotten with "a.b"

For me only "&(a.b)" is about the context of "a.b". "&a.b" is something completely different from "a.b", hence doesn't have to produce same output.
Feb 04 2013
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/4/13 8:37 AM, FG wrote:
 On 2013-02-04 11:20, monarch_dodra wrote:
 As I asked in the other thread: What is the point of even allowing
 taking the
 address of a property function? If a property is designed as something
 that can
 encapsulate and emulate a field, then it makes to sense to get the
 address of
 the getter (As far as I can tell).

Yes, but this is not just about properties but also normal functions:

Hah! I swear I posted before seeing this :o). Andrei
Feb 04 2013
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 02:37 PM, FG wrote:
 ...
 The change in behavior of &(expr) makes sense in the light that "expr"
 should behave the same in every context, not just in &(...), i.e. call foo().
 ...

The entire optional parens/ property thing is about (limited) context-dependent behaviour! This line of reasoning is simply wrong. There is no difference whatsoever between &expr and &(expr).
Feb 04 2013
parent FG <home fgda.pl> writes:
On 2013-02-04 15:42, Timon Gehr wrote:
 On 02/04/2013 02:37 PM, FG wrote:
 ...
 The change in behavior of &(expr) makes sense in the light that "expr"
 should behave the same in every context, not just in &(...), i.e. call foo().
 ...

The entire optional parens/ property thing is about (limited) context-dependent behaviour! This line of reasoning is simply wrong. There is no difference whatsoever between &expr and &(expr).

Indeed, currently there isn't and, considering the use of optional parentheses for delimiting and grouping, it also makes sense to treat &expr as &(expr). Oh, wait, no -- this leads straight to the OP's idea, which is: Rule of optional parentheses omission doesn't work in the context of '&'. Properties on the other hand need a different kind of treatment here. Forcing properties to also use parentheses here is a bad idea: &obj.prop; // a delegate? &obj.prop(); // address of the returned referenced data? Bad! This would make some typical code awkward: void* p1 = &someRange.retro.front; // suddenly it's a function pointer, not pointer to the element :( void* p2 = &someRange.retro.front(); // but having to add () just feels wrong. Therefore it's better for &prop to become the address of return data and to use some __traits or special member (like prop.__delegate) for taking address of the property: auto a = &someRange.retro.front; // address of element, yay auto b = someRange.retro.front.__delegate; // a delegate of front Simple enough? To specify exactly which prop we want it could even become: prop.__delegate(RetType, FirstArgType, SecondArgType)
Feb 04 2013