digitalmars.D - Why are there Properties in D?
- Robin (27/27) Feb 14 2014 Hiho,
- Francesco Cattoglio (9/13) Feb 14 2014 Trusting the programmer that wrote code before you is something
- Rikki Cattermole (45/45) Feb 14 2014 In most languages, people utilise getters and setters for member
- "Casper =?UTF-8?B?RsOmcmdlbWFuZCI=?= <shorttail gmail.com> (2/2) Feb 15 2014 Does @property force you to call the function without parens? If
- Rikki Cattermole (10/12) Feb 15 2014 @property does not force you to use parentheses.
- Timon Gehr (7/9) Feb 16 2014 There's a variety of ideas what it should do:
- Daniel Murphy (8/11) Feb 14 2014 Language design is a balancing act and there are always trade-offs. In ...
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (14/14) Feb 14 2014 It's true that it hides what happens behind the scenes, but there
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (2/5) Feb 14 2014 Oops, sorry, it was Daniel Murphy...
- Robin (15/24) Feb 14 2014 Hiho,
- Jesse Phillips (12/17) Feb 14 2014 FYI an infinite range is defined to have
- Robin (11/22) Feb 14 2014 Hiho,
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (20/37) Feb 14 2014 Yes, but only at runtime. For some things to work, you need to be
- Robin (12/53) Feb 15 2014 Uhm, ... I thought that enum types for variables are determined
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (3/21) Feb 16 2014 You can't define a method and a member variable with the same
- Nick Sabalausky (2/3) Feb 15 2014 http://www.youtube.com/watch?v=z6dmnE2mUgE
- Dejan Lekic (8/42) Feb 17 2014 I understand your frustration. It gets even worse when properties are mi...
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
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 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
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. 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
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
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
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
"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
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
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
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
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
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: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_; } } ? RobinAs 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.
Feb 14 2014
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: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.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_; } }
Feb 14 2014
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: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. RobinOn Friday, 14 February 2014 at 15:21:04 UTC, Jesse Phillips wrote: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.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_; } }
Feb 15 2014
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:You can't define a method and a member variable with the same name.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.
Feb 16 2014
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
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. =) RobbepopI 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