www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP4: Properties

reply "Nick Sabalausky" <a a.a> writes:
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.
Jul 23 2009
next sibling parent Daniel Keep <daniel.keep.lists gmail.com> writes:
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}.
Jul 24 2009
prev sibling next sibling parent Daniel Keep <daniel.keep.lists gmail.com> writes:
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.
Jul 24 2009
prev sibling next sibling parent reply "Nick Sabalausky" <a a.a> writes:
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 
Jul 24 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"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.
Jul 24 2009
parent "Robert Jacques" <sandford jhu.edu> writes:
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?
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?
Jul 24 2009
prev sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
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? 
Jul 24 2009