Fixing D's Properties

BCS ao at pathlink.com
Sat Aug 18 10:29:09 PDT 2007


Reply to Chad,

> BCS wrote:
> 
>> Reply to Chad,
>> 
>>> -------------------------------------(1)
>>> 
>>> First, the very common ambiguity:
>>> 
>>> Does
>>> foo.bar++;
>>> become
>>> foo.bar( foo.bar + 1 );
>>> or
>>> foo.bar() + 1;
>>> ??
[...]
>> This is not a syntax  issue with how properties are defined, but the
>> semantics of there use.
>> It can be fixed with minor changes.
>
> What minor changes?
> 
> If you're going to suggest giving implicit properties lvalueness, then
> this would break any code that relies on the quirks of current
> implicit properties.  I was hoping to preserve reverse compatibility
> with my solution, especially since Walter seems conservative about
> doing anything that breaks existing code.
> 

How? Letting implicit properties be simultaneously L and R values (they can 
now be either, just not both at the same time) won't break anything that 
I know of. Anything that is legal now, still would be, and any cases where 
the behavior would be different, were illegal to begin with.

>>> -------------------------------------(2)
>>> 
>> [...]
>> 
>> this is the same as #1 (or am i missing somthing)
>> 
> Promotion != lvalueness
> 
> The idea here is that #2 is a natural consequence of #1, thus you see
> them as the same.  #2 though, has a different consequence for the
> programmer.  #1 is merely very annoying, while #2 causes nasty code
> extensibility issues.
> 

If you see them as disticntly different points, then we must be looking at 
things at different levels. I see both 1 and 2 as saying: "properties can 
be used with ++, += etc and members can". OK I'll grant that #1 doesn't cover 
a few cases that #2 does, but that just makes #1 a special case of #2.

>>> -------------------------------------(3)
>>> 
>>> Third, there is a problem with value types and properties. Consider
>>> the following code:
>>> 
>> short version:
>> 
>> struct S {int i; void I(int j){i=j;} }
>> struct P {S s void GetS() { return s;} }
>> P p;
>> p.GetS.I = 5; // assignes 5 to temp, not member of p
>>
>> This is a reference semantics issue. The same isses happens to
>> general functions.
>> 
> Exactly.  I don't want function semantics with my properties.  I
> already have function semantics with my functions.
> 

I see your point and I strongly disagree. Under the covers, it IS a function 
and I /don't/ want that hidden.

>>> -------------------------------------(5)
>>> 
>>> Fifth, delegates aren't over with yet.
>> [...]
>>> the user code that relies on the delegate will fail.
>> [...]
>> 
>> ouch! that sounds worse than the problem you point out.
>> 
> I disagree, but in light of what you value, it becomes an aesthetics
> vs functionality issue.
> 

Unless you can trust the compiler to inline delegate literals (and the potentially 
virtual function call underneath), it is a performance issue.


>>> ========================================
>>> How to fix it
>>> ========================================
>> [...]
>> 
>>> *lvalue:  If foo is an lvalue, than foo = 5; should set foo's value
>>> to
>>> 5, instead of evaluating to 5; and doing nothing.  Implicit write
>>> properties fake this to some extent, but do not hold in the general
>>> case.  Example (3) above and the foo++; and foo+=10; issues are
>>> examples
>>> where lvalueness is needed.
>>
>> I would disagree. I would clam that the issue is that implicit
>> properties can be used a lvalues or rvalues, but not both.
>> 
> Still doesn't handle promotion/demotion between fields and properties.

My point was not intended to. It is a minor issue claming that the mechanics 
of one of your (valid) issues with implicit properties is incorrectly stated.

> Also, if you have a way to make the lvalue&rvalue semantics work, let
> me hear it.
> 

I think that you actually described somewhere the solution I wold use.

Use the R-value property (getter) to get the value, do the operation, then 
use the L-value property (setter) to push it back in.

struct S { ... int i(); void i(int); }
S s;

s.i++;
// becomes
{
  auto __tmp = s.i;  
  __tmp++;
  s.i = __tmp;
}

If only one or the other property exits then it is assumed the author wants 
to disallow this type of operation.

>> [......]
>> 
>> The basis of your thoughts seem to come from the idea that hiding the
>> fact that properties are functions would be a good thing. I would
>> assert that this is highly debatable. I will concede that the current
>> semantics of properties being not quite interchangeable with fields
>> is sub optimal. However fixing this by creating a new construct that,
>> in the end, is identical to a function but with a number of things
>> forbidden seems somehow wrong.
>> 
> Actually, I am suggesting that properties not be functions at all.
> They will of course share the notion of a body of executable code, but
> for all intents and purposes they are a way of accessing data while
> introducing side effects.
> 

Will they be accessed by doing a call/return sequence at the machine code 
level? If so, I would assert they are functions for all purposes I'm interested 
in. If it would be implemented by some other means, then I have have missed 
some major point of your post.

D is a low level language in many respects, as such, if it looks like a function 
when it comes out of the compiler, I want to be able to treat it as a function 
when it goes in.

>> As I see it the issues you bring up amount to:
>> 
>> 1> no L/R-value usage (++, +=, etc, use as an inout or out arg)
>> 2> they can lead to hard to find reference semantics issues
>> 3> syntax problems with properties retuning delegates
>> 4> not interchangeable with fields
>> #1 can be fixed without explicit properties
>> 
> how? 

same as above

> 
>> #2 is not at all a problem in my book
>> 
> I have suffered many hours of debugging thanks to this "feature".
> Don't tell me it isn't a problem!
>

It's not a problem with /properties/. dropping properties compleaty wouldn't 
remove this type of isses. It might make some cases easyer to spot but nothing 
more. As to converting from a member to a property changing things, that 
is part of point #4.
 
>> #4 this is a good point, however, as stated above, I don't like the
>> proposed solution. Also, the proposed solution doesn't fix the issue
>> because taking the address of a field is allowed, even with explicit
>> properties, this wouldn't work
>> 
> If the proposed solution is not good enough, please give a better one.
> Suggestions are welcome and encouraged.
> 

Nothing yet. IMHO, your proposed solution, while maybe appropriate for higher 
level languages, is not right for D. If I see a solution that solves these 
issues without cause to many of its own problems, I would be interested.

> As for the address of a field... perhaps if taking the address of a
> field returned a delegate... nah.
> This is somewhat of a corner case, but you've got me there, for now.
> I'd love to see someone come up with a slick solution to this.
> I should also note that C# didn't seem to have this problem with its
> explicit properties.  That is probably because in C#, using pointers
> was
> considered "unsafe" and done very infrequently.  It makes me want to
> bust out C# again and see what happens when one tries to take the
> address of a property, and I probably will at some point.
> Even if the addressing thing can't be fixed, I'd at least like to see
> the rest of the stuff get fixed.

I'll bet you can't. You can't use one for an out or ref argument (I just 
cheked) but you can use a member.





More information about the Digitalmars-d mailing list