Jump to page: 1 2
Thread overview
Why are there Properties in D?
Feb 14, 2014
Robin
Feb 14, 2014
Rikki Cattermole
Feb 16, 2014
Casper Færgemand
Feb 16, 2014
Rikki Cattermole
Feb 16, 2014
Timon Gehr
Feb 14, 2014
Daniel Murphy
Feb 14, 2014
Marc Schütz
Feb 14, 2014
Marc Schütz
Feb 14, 2014
Robin
Feb 14, 2014
Jesse Phillips
Feb 14, 2014
Robin
Feb 14, 2014
Marc Schütz
Feb 15, 2014
Robin
Feb 16, 2014
Marc Schütz
Feb 16, 2014
Nick Sabalausky
Feb 18, 2014
Dejan Lekic
February 14, 2014
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
February 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 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.
February 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.

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.
February 14, 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. 

February 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.
February 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...
February 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
February 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.
February 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:
>> 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
February 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:
>> 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.
« First   ‹ Prev
1 2