Thread overview
DIP4: Properties
Jul 24, 2009
Nick Sabalausky
Jul 24, 2009
Daniel Keep
Jul 24, 2009
Daniel Keep
Re: Properties
Jul 24, 2009
Nick Sabalausky
Jul 24, 2009
Nick Sabalausky
Jul 25, 2009
Robert Jacques
Jul 24, 2009
Lutger
July 24, 2009
An alternate usage/definition syntax for properties.

http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP4

Note that there are a few parts marked NEED HELP, that could use assistance from someone with more expertise in this than me.


July 24, 2009
Some comments:

There should be an actual proposal definition instead of just an example.  Examples tend to be misinterpreted.

I've tried to work out a possible grammar:

Decl:
	BasicType DeclaratorInitializer '{' PropertyDecls '}'

PropertyDecls:
	PropertyDecl
	PropertyDecl PropertyDecls

PropertyDecl:
	PropertyIdentifier BlockStatement

PropertyIdentifier:
	'get'
	'set'

(note: additions to this grammar are below)

---

The "optimise implicit value away" thing is a bit iffy.  I'd prefer some
actual syntactic distinction between a property with automatic storage.
 It would be far too easy to accidentally cause the backing to be added.

I had the following idea, but I'm worried that it's context-sensitive; it looks an awful lot like a normal AutoDeclaration, except that it's missing the assignment.  Mayhap someone with stronger grammar-fu could tell me? :D

We could add the following:

PropertyDecl:
	'auto' Identifier ';'

If this appears in a property, it creates a private variable with the same type as the property itself, scoped to the property declaration. This would allow for people to use whatever "magic" name they like. Your first example property would become:

int width = int.init
{
    auto value;
    get { return value; }
    set { value = set; }
}

---

Also, having the value being assigned to the property be called "set" is really unnerving.  We've already got to explain to people why in templates you "assign" to the name of the template; I don't want to have to explain that it works in completely the opposite way for property setters.  I think the solution to this is to just make it explicit somehow.  `set(v) { value = v; }` is not THAT much more typing (minimum of 3 characters), and it saves you from having to memorise yet another magic identifier.

---

Q: How do properties interact with templates?

---

Being able to modify a read-only property is just *nasty*.  Having either explicit backing or protection attributes on the getter/setter would be a better solution.

Change PropertyDecl to:

PropertyDecl:
	PropertyIdentifier BlockStatement
	ProtectionAttribute PropertyIdentifier BlockStatement

---

Q: Is this syntax context-free?  I can't think of any existing case it would conflict with.  Wish there was some easy way to check.

---

One issue I have with rewriting {a.b op= c} to {a.b = a.b op c} is that the former may be much more efficient than the latter.  It might perhaps be wise to postpone addressing this until later [1].

---

Some time ago, Andrei indicated that he felt properties needed *three* basic operations: get, swap and delete, or something.  We should find that post and look at whether it's a good idea.

---

Q: Why is 'delete' or 'remove' not available?  It's present in Python
(as an example), why not here?


[1] Personally, I suspect it would be best if we had a pragma or something that told the compiler "look, even if this is a property, don't rewrite it; I'll take care of it."  That, or maybe rewrite {a.b op= c} to {auto tmp = a.b; tmp op= c; a.b = tmp}.
July 24, 2009
Sorry; posted without going over the Description section.  :P

Again, automatic storage just rubs me the wrong way.  Less magic, please.

---

Without automatic storage, there's a fairly simple way to make it visible outside the property; move the "auto value;" declaration outside and make it "T _blah;" or something.  Not pretty, granted, but consistent and means we don't have to muck with traits or special syntax.  It's also *obvious* where stuff is accessible from.

---

struct Property(T)
{
    T delegate() getter;
    void delegate(T) setter;

    T get()
    {
        return enforce(getter, new MissingGetterException)();
    }
    void set(T v)
    {
        enforce(setter, new MissingSetterException)(v);
    }
}

The exceptions shouldn't need explanation.  :)

---

Interacting with inheritance is tricky.  I think what should be done is this:

class A { int foo { get; set; } }

Would generate the following hidden functions:

A.__property_foo_get
A.__property_foo_set

Then, this:

{
    A a;
    auto p = &a.foo;
}

translates to this:

{
    A a;
    Property!(int) p = {
        getter:&a.__property_foo_get,
        setter:&a.__property_foo_set};
}

This should allow class implementations to add a setter to read-only properties specified in either an interface or base class.

(Incidentally, the internal storage could be __property_foo_(name) or
something.)

As for defaults: public.  Properties are usually defined for public interfaces; if it was private, you might as well just use a field.

---

Again, I don't like having "set" be magical.  _argptr and _arguments are bad enough as it is, please let's not add more invisibly defined magic identifiers!

---

Regarding your cons: get and set mustn't be made keywords; they're too short and useful.  Using in and out is actually a pretty good idea.

Come to think of it... would it at all be useful to be able to expose a ref property that just exposes an underlying field?

Your note regarding array properties and extension methods was one I hadn't considered.  It should DEFINITELY be given thought.
July 24, 2009
Now that I've finally gotten my ng client to play nice and actually show me my own DIP4 thread (unsubscribed digitalmars.D and then re-subscribed), I'm moving the comment that was left on the Wiki over here:

------------------------------------

RobertJacques says:

Cons:

* Verbosity is an issue (i.e. the addition of extra boiler-plate code)

* keyword increase: both set and get become keywords. Perhaps re-using in and out in a manner similar to contract programming might work.

* +=, -=, etc. : The suggested syntactic sugar is good, but could be implemented with current properties. Separate?

* bondage and discipline: Different programmers have different coding styles. Hence the suggested syntactic sugar of func(class, value) <=> class.func(value) <=> class.func = value in other proposals and currently valid for arrays. Flexibility is a virtue

* IDE's, and doc-generators: Could all be well served with a appropriate set of DDoc tags


July 24, 2009
"Nick Sabalausky" <a@a.a> wrote in message news:h4c202$283l$1@digitalmars.com...
> Now that I've finally gotten my ng client to play nice and actually show
> me
> my own DIP4 thread (unsubscribed digitalmars.D and then re-subscribed),
> I'm
> moving the comment that was left on the Wiki over here:
>
> ------------------------------------
>
> RobertJacques says:
>
> Cons:
>

Ok, now I finally have a moment to respond to at least one set of comments:

> * Verbosity is an issue (i.e. the addition of extra boiler-plate code)
>

I'm not sure I see how the proposed syntax is verbose. And I specifically designed it to minimize boilerplate. With the current style, you have to (typically) define a private variable, and then one or two functions for getting/setting. This proposal isn't really much more than that even in the worst case. Maybe you could elaborate on what you mean?

> * keyword increase: both set and get become keywords. Perhaps re-using in and out in a manner similar to contract programming might work.
>

I indicated in the proposal that they would not be keywords. Someone indicated in the "Reddit: Why aren't people using D?" thread that that would be possible. Maybe they could explain here?

I suppose it might be required to make "value" and "set" keywords because of their use as implicit variables, but I'm not convinced. Maybe a language expert could shed some light on this?

Also, regarding in/out contracts, something like this was one of my earlier ideas, but I decided against it because I wasn't sure if it would cause parsing problems, and I wanted to leave the door open for (I forget who's) suggestion of allowing operator overloading for a property if that ended up being deemed necissary. But, I may as well stick it on the table here for open discussion:

-----------------------------
// Viable? Preferable?
int width = 7
get { return value; }
set { value = set; }
-----------------------------

> * +=, -=, etc. : The suggested syntactic sugar is good, but could be implemented with current properties. Separate?
>

Perhaps. What does everyone else think?

> * bondage and discipline: Different programmers have different coding styles. Hence the suggested syntactic sugar of func(class, value) <=> class.func(value) <=> class.func = value in other proposals and currently valid for arrays. Flexibility is a virtue
>

I'm sorry, but I have to strongly disagree with this one. Saying that "class.func(value) <=> class.func = value" is a matter of style is like saying that "2 + 2" vs "2 ~ 2" to do addition is a matter of style. (And I question the "func(class, value) <=> class.func(value)" part as well, albiet not quite as strongly) Within a language, each syntax and operator has it's own meaning. Allowing them to be switched around interchangably serves no purpose besides obfuscation.

> * IDE's, and doc-generators: Could all be well served with a appropriate
> set
> of DDoc tags

In the case of doc-generators, yes, that could be done and would not be unreasonable. However, any information that a doc-generator can get directly from the code instead of an additional doc-generator-specific syntax (let's not forget, that would add extra verbosity/boilerplate!) can only be an improvement.

In the case of debuggers, it's probably possible, but it's a bad idea. A debugging feature should not be dependant on any specific doc-generator. DDoc may be built into DMD, but it is expected that any standard doc generator can be used instead. The only way for a debugger to get around that is to try to support every doc-generator that someone might want to use (and just for the sake of properties alone?), which may be possible, but not the right approach.


July 24, 2009
Am I right in thinking that the automated storage is mainly to cut down verbosity? What other purpose could it serve? It looks to me the proposal could be much simplified by cutting this feature.

I think the "int foo {get;set;}" syntax may be sufficient and useful for keeping simple properties simple though. The advantage over plain fields in this case is primarily to keep interface compatibility. Speaking of which, how should properties behave in interfaces?


July 25, 2009
On Fri, 24 Jul 2009 17:12:39 -0400, Nick Sabalausky <a@a.a> wrote:

> "Nick Sabalausky" <a@a.a> wrote in message
> news:h4c202$283l$1@digitalmars.com...
>> Now that I've finally gotten my ng client to play nice and actually show
>> me
>> my own DIP4 thread (unsubscribed digitalmars.D and then re-subscribed),
>> I'm
>> moving the comment that was left on the Wiki over here:
>>
>> ------------------------------------
>>
>> RobertJacques says:
>>
>> Cons:
>>
>
> Ok, now I finally have a moment to respond to at least one set of comments:
>
>> * Verbosity is an issue (i.e. the addition of extra boiler-plate code)
>>
>
> I'm not sure I see how the proposed syntax is verbose. And I specifically
> designed it to minimize boilerplate. With the current style, you have to
> (typically) define a private variable, and then one or two functions for
> getting/setting. This proposal isn't really much more than that even in the
> worst case. Maybe you could elaborate on what you mean?

Your syntax seems very C# inspired. After doing a class project in C# a while ago, which heavily used properties, I breathed a major sigh of relief coming back to D properties. If I had to pick something concrete, I'd say the lack of clean one-liners is an issue as is the extra indentation.

I'd also note I almost never do the private var, public method pattern. (Really, only when I want a expose a read-only view of something) Most of the time I'm doing some kind of transform and storing the data in a seperate internal format.

>> * keyword increase: both set and get become keywords. Perhaps re-using in
>> and out in a manner similar to contract programming might work.
>>
>
> I indicated in the proposal that they would not be keywords. Someone
> indicated in the "Reddit: Why aren't people using D?" thread that that would
> be possible. Maybe they could explain here?
>
> I suppose it might be required to make "value" and "set" keywords because of
> their use as implicit variables, but I'm not convinced. Maybe a language
> expert could shed some light on this?
>
> Also, regarding in/out contracts, something like this was one of my earlier
> ideas, but I decided against it because I wasn't sure if it would cause
> parsing problems, and I wanted to leave the door open for (I forget who's)
> suggestion of allowing operator overloading for a property if that ended up
> being deemed necissary. But, I may as well stick it on the table here for
> open discussion:
>
> -----------------------------
> // Viable? Preferable?
> int width = 7
> get { return value; }
> set { value = set; }
> -----------------------------

Hmm... Here's some random ideas

int width = 7         /// Property with storage
out                   { return width;           }
in(int   i)           { width = i;              }
inout(alias op)(int i){ return width op i;      }

auto high_five        /// Property with no storage
out(float)     { return 5.99; }

>> * +=, -=, etc. : The suggested syntactic sugar is good, but could be
>> implemented with current properties. Separate?
>>
>
> Perhaps. What does everyone else think?
>
>> * bondage and discipline: Different programmers have different coding
>> styles. Hence the suggested syntactic sugar of func(class, value) <=>
>> class.func(value) <=> class.func = value in other proposals and currently
>> valid for arrays. Flexibility is a virtue
>>
>
> I'm sorry, but I have to strongly disagree with this one. Saying that
> "class.func(value) <=> class.func = value" is a matter of style is like
> saying that "2 + 2" vs "2 ~ 2" to do addition is a matter of style. (And I
> question the "func(class, value) <=> class.func(value)" part as well, albiet
> not quite as strongly) Within a language, each syntax and operator has it's
> own meaning. Allowing them to be switched around interchangably serves no
> purpose besides obfuscation.

Well, actually "func(class, value) <=> class.func(value)" is extremely valuable for extending third party structs/classes. It's also very much about programmer style. Some people prefer/understand one better than the other. It can also help make porting/refactoring go smoother. I've also used "class.func = value" several times even when according to the style of the library I shouldn't; In each case, it increased the readability and understandability of my code as a whole, despite "class.func = value" not making much sense in isolation.

Anyways, enforcing style for style's sake is always bondage and discipline programming. I mean, people have issues with restrictions even when they buy safety and robustness.

BTW, I think you meant "2 + 2" vs "2 ~ 2" to do concatenation. And if you really meant addition, then well that's just bad function name choice. It's got nothing to do with style.

>> * IDE's, and doc-generators: Could all be well served with a appropriate
>> set
>> of DDoc tags
>
> In the case of doc-generators, yes, that could be done and would not be
> unreasonable. However, any information that a doc-generator can get directly
> from the code instead of an additional doc-generator-specific syntax (let's
> not forget, that would add extra verbosity/boilerplate!) can only be an
> improvement.
>
> In the case of debuggers, it's probably possible, but it's a bad idea. A
> debugging feature should not be dependant on any specific doc-generator.
> DDoc may be built into DMD, but it is expected that any standard doc
> generator can be used instead. The only way for a debugger to get around
> that is to try to support every doc-generator that someone might want to use
> (and just for the sake of properties alone?), which may be possible, but not
> the right approach.

Curiosity, how would a debugger set a watch on a property since it doesn't acually exist?