www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why are there Properties in D?

reply "Robin" <robbepop web.de> writes:
Hiho,

I am learning D since some time and I must say all in all it is
truely a better C++! I especially like the statement of Walter
Bright that nowadays it is more important that the programmer can
easily read programming text and do not have to "interpret" every
single line by looking into several definitions and declarations
in order to fully understand what a piece of program text really
means as programmers normally spend much more time debugging a
code than writing one and thus it isn't that important to keep
program code short - more important is clean and unambiguous code.

But what about Properties - the feature where functions can be
called as if they were member variables ...
Isn't this a step backwards if you think about the sentence above?

With Properties used in a code a programmer again has to look up
the definition of all calls and assignments of variables just in
case they could be Properties and not just member variables.

So I am asking why should one use Properties? The only advantage
is that one can leave out the nasty "()" but the disadvantage is
that especially new people who are working out a code of another
person or people who have to inspect older code may have a harder
time understanding what really happens especially if Properties
are "overused".

In my opinion this leads to less clear code.

But maybe I am overlooking something and things aren't that worse
so it would be nice if someone could tell me about other
advantages of Properties. =)

Robbepop
Feb 14 2014
next sibling parent "Francesco Cattoglio" <francesco.cattoglio gmail.com> writes:
On Friday, 14 February 2014 at 09:32:40 UTC, Robin wrote:
 more important is clean and unambiguous code.

 With Properties used in a code a programmer again has to look up
 the definition of all calls and assignments of variables just in
 case they could be Properties and not just member variables.

Trusting the programmer that wrote code before you is something you will have to do anyway. Property however have been introduced in an "incomplete" way and are discussed once or twice a year in huge threads. Anyway, typical usage cases are pretty much the same described by C# properties: from http://msdn.microsoft.com: -Properties enable a class to expose a public way of getting and setting values, while hiding implementation or verification code.
Feb 14 2014
prev sibling next sibling parent reply "Rikki Cattermole" <alphaglosined gmail.com> writes:
In most languages, people utilise getters and setters for member 
variables of e.g. classes.

So instead of code like this:

Person getAuthor() {
     return this.author;
}

In D we can have:

 property Person author() {
     return this.author_;
}

(I appended an underscore to make it not conflict between 
internal property and the method).

Like most features you can over use them as you said.

This is a highly flexible method of setting and getting 'meta' 
internal data. This could be transformed and manipulated. You 
cannot do this with a plain old property on the class.

Other languages like C# have their own solutions to this. In C# 
they utilise:
public string Name
{
    get
    {
       return name;
    }
    set
    {
       name = value;
    }
}

As a property declaration.
A little less powerful but one I would love D to have (although 
doable via mixin templates).
It can also be simpler to the point of:

accessor type name {get; set}

If I remember right.

With D property function, you can still utilise them with the 
brackets.
e.g.
Person authorOfMyFavouriteBook = book.author();

But it infers that its taking action, instead of a internal 
'meta' data.

On the note of having to reread declarations ext. You have to do 
this at any rate. If you don't understand the code then you need 
to go work it out, before you can use it.

This is more of a D.learn post. But no worries.
Feb 14 2014
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/16/2014 02:21 AM, "Casper Færgemand" <shorttail gmail.com>" wrote:
 Does  property force you to call the function without parens?

It is supposed to, but no.
 If not I don't really see what the keyword actually does.

There's a variety of ideas what it should do: http://wiki.dlang.org/DIP21 http://wiki.dlang.org/DIP23 http://wiki.dlang.org/DIP24 (DIP21 is basically a subset of 'DIP24/ property: basic design'.)
Feb 16 2014
prev sibling next sibling parent "Daniel Murphy" <yebbliesnospam gmail.com> writes:
"Robin"  wrote in message news:beuazddmthazioufmnne forum.dlang.org...

 But what about Properties - the feature where functions can be
 called as if they were member variables ...
 Isn't this a step backwards if you think about the sentence above?

Language design is a balancing act and there are always trade-offs. In this case it was decided the benefit outweighed the cost (eg now you can easily instrument field access) With operator overloading, there are many other places where the syntax hides function calls of arbitrary complexity. You are of course free to avoid any/all of these features in your own code if you think it is better that way.
Feb 14 2014
prev sibling next sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
It's true that it hides what happens behind the scenes, but there 
are several advantages. Rikki Cattermole already mentioned 
instrumentation; more generally, this makes it easy to change 
between getter/setter and member variable without modifying all 
the use sites.

I'd like to add generic code. For an example, look at ranges: 
their `front` and `empty` must be callable without parens. This 
makes it possible for some ranges to have a normal member 
variable `front`, or a static enum member `empty` (which can even 
be tested for at compile time!), and for others to use 
methods/UFCS functions instead. Without these, a lot of the 
generic algorithms in `std.algorithm` would be full of 
`is(typeof(range.empty)) || is(typeof(range.empty()))`, or 
similar tests, making them harder to read and get right.
Feb 14 2014
prev sibling next sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 14 February 2014 at 11:34:00 UTC, Marc Schütz wrote:
 It's true that it hides what happens behind the scenes, but 
 there are several advantages. Rikki Cattermole already 
 mentioned instrumentation; ...

Oops, sorry, it was Daniel Murphy...
Feb 14 2014
prev sibling next sibling parent "Robin" <robbepop web.de> writes:
Hiho,

first of all, thank you all for your fast responses.

On Friday, 14 February 2014 at 11:34:00 UTC, Marc Schütz wrote:
 I'd like to add generic code. For an example, look at ranges: 
 their `front` and `empty` must be callable without parens. This 
 makes it possible for some ranges to have a normal member 
 variable `front`, or a static enum member `empty` (which can 
 even be tested for at compile time!), and for others to use 
 methods/UFCS functions instead. Without these, a lot of the 
 generic algorithms in `std.algorithm` would be full of 
 `is(typeof(range.empty)) || is(typeof(range.empty()))`, or 
 similar tests, making them harder to read and get right.

As I said I am still learning D (and I think I will never stop learning it xD) so sorry if I misunderstand certain programming patterns. As far as I can imagine you could also implement ranges via front and empty functions and ranges could easily expose their variables as a getter method named front() or empty() and nobody would care if it is handled functionally or via a simple variable again. I don't get why all the algorithms would be full of is(typeof(range.empty) || is(typeof(range.empty()) with the approach of getter methods for front and empty or am I wrong? Robin
Feb 14 2014
prev sibling next sibling parent "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Friday, 14 February 2014 at 14:55:02 UTC, Robin wrote:
 As far as I can imagine you could also implement ranges via 
 front and empty functions and ranges could easily expose their 
 variables as a getter method named front() or empty() and 
 nobody would care if it is handled functionally or via a simple 
 variable again.

FYI an infinite range is defined to have struct Infinite { enum empty = false; } You know it will never be empty at compile time. Being able to read and understand a piece of code has nothing to do with knowing exactly how it achieves its task or what the code the machine will be running. If there is a bug, then you'll need to dig into it. If there is a performance problem you've identified then you'll be looking at it, but in general those aren't important to understanding what the code does.
Feb 14 2014
prev sibling next sibling parent "Robin" <robbepop web.de> writes:
On Friday, 14 February 2014 at 15:21:04 UTC, Jesse Phillips wrote:
 On Friday, 14 February 2014 at 14:55:02 UTC, Robin wrote:
 As far as I can imagine you could also implement ranges via 
 front and empty functions and ranges could easily expose their 
 variables as a getter method named front() or empty() and 
 nobody would care if it is handled functionally or via a 
 simple variable again.

FYI an infinite range is defined to have struct Infinite { enum empty = false; } You know it will never be empty at compile time.

Hiho, thank you for this interesting input. =) Couldn't this be equally possible (also at runtime) with the following: struct Infinite { enum empty_ = false; bool empty() pure { return empty_; } } ? Robin
Feb 14 2014
prev sibling next sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 14 February 2014 at 16:16:28 UTC, Robin wrote:
 On Friday, 14 February 2014 at 15:21:04 UTC, Jesse Phillips 
 wrote:
 FYI an infinite range is defined to have

    struct Infinite {
        enum empty = false;
    }

 You know it will never be empty at compile time.

Hiho, thank you for this interesting input. =) Couldn't this be equally possible (also at runtime) with the following: struct Infinite { enum empty_ = false; bool empty() pure { return empty_; } }

Yes, but only at runtime. For some things to work, you need to be able to know it at compile time. `std.range` defines a template `isInfinite` that checks for this. This information can be used for some optimizations: `std.algorithm.count` and `std.range.walkLength` are only defined for non-infinite ranges (to avoid creating an infinite loop), `std.algorithm.cartesianProduct` can work with two infinite ranges using a special enumeration strategy if it can detect them, `std.range.chain` can optimize index access by stopping at the first infinite range, `std.range.take` can always define a length for infinite ranges (even if they don't have a length property themselves), ... Another example: The `length` property of ranges. It is possible to turn builtin slices (dynamic arrays) into ranges by importing `std.range` or `std.array`. Slices already have a member field `length` by default. Here you have an example where it's impossible to define a method `length()`. With properties, nothing special needs to be done: You can always use `length` without parens, even if it happens to be a method.
Feb 14 2014
prev sibling next sibling parent "Robin" <robbepop web.de> writes:
On Friday, 14 February 2014 at 19:24:58 UTC, Marc Schütz wrote:
 On Friday, 14 February 2014 at 16:16:28 UTC, Robin wrote:
 On Friday, 14 February 2014 at 15:21:04 UTC, Jesse Phillips 
 wrote:
 FYI an infinite range is defined to have

   struct Infinite {
       enum empty = false;
   }

 You know it will never be empty at compile time.

Hiho, thank you for this interesting input. =) Couldn't this be equally possible (also at runtime) with the following: struct Infinite { enum empty_ = false; bool empty() pure { return empty_; } }

Yes, but only at runtime. For some things to work, you need to be able to know it at compile time. `std.range` defines a template `isInfinite` that checks for this. This information can be used for some optimizations: `std.algorithm.count` and `std.range.walkLength` are only defined for non-infinite ranges (to avoid creating an infinite loop), `std.algorithm.cartesianProduct` can work with two infinite ranges using a special enumeration strategy if it can detect them, `std.range.chain` can optimize index access by stopping at the first infinite range, `std.range.take` can always define a length for infinite ranges (even if they don't have a length property themselves), ... Another example: The `length` property of ranges. It is possible to turn builtin slices (dynamic arrays) into ranges by importing `std.range` or `std.array`. Slices already have a member field `length` by default. Here you have an example where it's impossible to define a method `length()`. With properties, nothing special needs to be done: You can always use `length` without parens, even if it happens to be a method.

Uhm, ... I thought that enum types for variables are determined at compiletime and as pure functions aren't affected by side-effects and cause no side-effects their result should be determinable at compiletime, too. Couldn't it be possible again if we just add another getter method "length()" for the slice's length? Then you would have a uniform access as length() instead of length (without parens) if you do it analogiously for all other cases. There is just no difference in my opinion - the one solution forces an interface with parens and the other forces an interface without them. Robin
Feb 15 2014
prev sibling next sibling parent "Casper =?UTF-8?B?RsOmcmdlbWFuZCI=?= <shorttail gmail.com> writes:
Does  property force you to call the function without parens? If 
not I don't really see what the keyword actually does.
Feb 15 2014
prev sibling next sibling parent "Rikki Cattermole" <alphaglosined gmail.com> writes:
On Sunday, 16 February 2014 at 01:21:21 UTC, Casper Færgemand 
wrote:
 Does  property force you to call the function without parens? 
 If not I don't really see what the keyword actually does.

property does not force you to use parentheses. property myExample(int a) {} It can be called via myExample = a; or myExample(3); I can't entirely remember the behaviour for no args on the first syntax.
Feb 15 2014
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On 2/14/2014 4:32 AM, Robin wrote:
 Why are there Properties in D?

http://www.youtube.com/watch?v=z6dmnE2mUgE
Feb 15 2014
prev sibling next sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Saturday, 15 February 2014 at 15:45:40 UTC, Robin wrote:
 On Friday, 14 February 2014 at 19:24:58 UTC, Marc Schütz wrote:
 Another example: The `length` property of ranges. It is 
 possible to turn builtin slices (dynamic arrays) into ranges 
 by importing `std.range` or `std.array`. Slices already have a 
 member field `length` by default. Here you have an example 
 where it's impossible to define a method `length()`. With 
 properties, nothing special needs to be done: You can always 
 use `length` without parens, even if it happens to be a method.

Uhm, ... I thought that enum types for variables are determined at compiletime and as pure functions aren't affected by side-effects and cause no side-effects their result should be determinable at compiletime, too. Couldn't it be possible again if we just add another getter method "length()" for the slice's length? Then you would have a uniform access as length() instead of length (without parens) if you do it analogiously for all other cases. There is just no difference in my opinion - the one solution forces an interface with parens and the other forces an interface without them.

You can't define a method and a member variable with the same name.
Feb 16 2014
prev sibling parent Dejan Lekic <dejan.lekic gmail.com> writes:
Robin wrote:

 Hiho,
 
 I am learning D since some time and I must say all in all it is
 truely a better C++! I especially like the statement of Walter
 Bright that nowadays it is more important that the programmer can
 easily read programming text and do not have to "interpret" every
 single line by looking into several definitions and declarations
 in order to fully understand what a piece of program text really
 means as programmers normally spend much more time debugging a
 code than writing one and thus it isn't that important to keep
 program code short - more important is clean and unambiguous code.
 
 But what about Properties - the feature where functions can be
 called as if they were member variables ...
 Isn't this a step backwards if you think about the sentence above?
 
 With Properties used in a code a programmer again has to look up
 the definition of all calls and assignments of variables just in
 case they could be Properties and not just member variables.
 
 So I am asking why should one use Properties? The only advantage
 is that one can leave out the nasty "()" but the disadvantage is
 that especially new people who are working out a code of another
 person or people who have to inspect older code may have a harder
 time understanding what really happens especially if Properties
 are "overused".
 
 In my opinion this leads to less clear code.
 
 But maybe I am overlooking something and things aren't that worse
 so it would be nice if someone could tell me about other
 advantages of Properties. =)
 
 Robbepop

I understand your frustration. It gets even worse when properties are mixed with UFCS. People who are new to D just get more confused. :) I do not know, I find it very hard to read, personally, so I do not abuse them like some other people do. I like my code to be understood by anyone in the first "code scan". -- http://dejan.lekic.org
Feb 17 2014