Difference between revisions of "DIP26"
(→Overloading @property methods) |
(→Taking the address of a property) |
||
Line 93: | Line 93: | ||
assert(is(typeof(a)==int)); | assert(is(typeof(a)==int)); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | "Calling" the property accessor functions with foo() or foo(value) is invalid just as in DIP23. | ||
== Overloading @property methods == | == Overloading @property methods == |
Revision as of 23:37, 8 February 2013
Title: | Properties with actual definition of the term property |
---|---|
DIP: | 26 |
Version: | 1 |
Status: | Draft |
Created: | 2013-02-08 |
Last Modified: | 2013-02-08 |
Author: | Robert Klotzner |
Links: | DIP23 |
Contents
Abstract
This DIP establishes a very concrete definition of the term property and desired characteristics of properties and in turn establishes semantics of use for them. For optional parentheses, I would like to adopt the scheme already explained in DIP23.
Rationale
DIP23 and DIP24 both don't seem to have a clear concept what properties actually are, resulting in rules that destroy their original purpose (For example forbidding module level properties).
Properties as defined in this DIP are a way of encapsulation of fields of an entity (class, struct, module) in a way that the class/struct/module can actually control the access and thus encapsulates it, such that the field in reality might not even exist or be in a different format than presented, ...
The usual way of establishing this kind of encapsulation, explained in almost every book on OOP, is by the use of get/set methods and not exposing any fields in public. The problem with this approach is that the common case are trivial get/set methods which just return the internal fields value or set the fields value respectively. Also the naming of set/get methods is specified by convention making it hard for tools to detect what actually is a property and what is none if the convention is broken.
As can be seen the classical get/set methods and not exposing any field in public solves the above requirements perfectly, so this proposal defines properties to be nothing more as get/set methods with a well defined signature and some syntactic sugar.
Description
A property in D is defined as either a specially marked get method for read-only properties:
@property T foo();
or a specially marked set method for write-only methods:
@property void foo(T value);
or both for read/write properties.
For a default implementation and solving the problem of the boilerplate problem of traditional set/get methods the following syntax is suggested:
@property T foo;
which will be lowered by the compiler to:
private T __foo; // Just some internal name.
@property void foo(T value) {
__foo=value;
}
@property T foo() {
return __foo;
}
As it has been asked in the newsgroups a lot: Why not simply use a public field? The syntax for accessing them in D's current syntax for properties is the same anyway:
foo=someValue;
someValue=foo;
Well yes, but this is a pitfall. A public field simply offers no encapsulation by its very definition: It is a public field. This means:
- You can rely on the fact that the field really exists somewhere in the object - you can take its address, can use it as an lvalue.
- You can use them in expressions, which are currently not allowed for properties like:
foo+=someValue; foo/=someValue;
While the latter could be fixed, the former can't.
There have been some rejections to the @property field syntax on the news group: In short, if we don't have it, then properties are reduced to syntactic sugar for get/set methods and it should be very clearly stated in the documentation that despite their similar syntax to plain fields, they are not interchangeable at all and that one has to write the trivial set/get implementations or use a mixin.
Taking the address of a property
As this is illegal for properties the unary & operator is free to take the address of the accessor method, just as explained in DIP23, but without being able to take the address of the returned value.
And yeah, just as in DIP23:
@property int a();
assert(is(typeof(a)==int));
"Calling" the property accessor functions with foo() or foo(value) is invalid just as in DIP23.
Overloading @property methods
- Properties may not be overloaded with normal functions.
- Property get methods might be overloaded freely with other one parameter get methods.
- Property get method overloads might take their parameter via ref, for performance reasons.
The following property definition would be illegal, as it violates encapsulation:
private T a_;
@property ref T a() {
return a_;
}
It violates encapsulation just as a public field would and is thus, by definition, no property. Of course there are use cases for this, the front element of ranges comes to mind and they are of course still supported, just leave out "@property" in the above definition and you are all set. Semantic stays the same because of the optional-parentheses feature of functions:
private int a_;
ref int a() {
return a_;
}
unittest {
a=7;
int c=a;
}
The only thing is, the moment you give up @property you loose encapsulation, if that is ok for your application, then you'll be fine. If not, a looser property definiton would not help you either.
No UFCS for properties
Properties protect the access to a field of an entity (class/struct/module), so they actually have to be defined within the entity they belong to, just as a field would. Even though D's module wide private access would make it technically possible to implement a property outside a class/struct, it sure is no big gain to actually allow this.
On the other hand, property methods implemented outside of the struct/class's containing module are not able to encapsulate any field, because they have only access to the public parts of the struct/class, which are directly accessible anyway.
So the very definition of properties, makes UFCS properties nonsensical and thus solves the ambiguity of module level properties.
@property fields Details
The compiler must generate the standard get/set methods, taking parameters by value and returning them by value. From a quick look in the Qt documentation it seems that most properties are small any way. If pass by reference is desired, the implementations would have to be written by hand.
Copyright
This document has been placed in the Public Domain.