www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Is defining get/set methods for every field overkill?

reply thebluepandabear <therealbluepandabear protonmail.com> writes:
I am creating a TUI library and I have a class with the following 
constant fields:

```
class Label : Renderable {
     const string text;
     const TextAlignment textAlignment;
     const Color color;

     this(Dimensions dimensions, string text, TextAlignment 
textAlignment, Color color) {
         this.dimensions = dimensions;
         this(text, textAlignment, color);
     }

     this(string text, TextAlignment textAlignment, Color color) {
         this.text = text;
         this.textAlignment = textAlignment;
         this.color = color;
     }

     override Cell[] render() const {
         Cell[] cells;

         for (int x = 0; x < 0 + text.length; ++x) {
             cells ~= Cell(Coordinates(x, 0), text[x], color);
         }

         return cells;
     }
}
```

I am debating whether or not I should add getter methods to these 
properties. On one hand, it will inflate the codebase by a lot, 
on the other hand -- in other languages like Java it is a good 
practice:

```
class Label : Renderable {
     private const string text;
     private const TextAlignment textAlignment;
     private const Color color;

     this(Dimensions dimensions, string text, TextAlignment 
textAlignment, Color color) {
         this.dimensions = dimensions;
         this(text, textAlignment, color);
     }

     this(string text, TextAlignment textAlignment, Color color) {
         this.text = text;
         this.textAlignment = textAlignment;
         this.color = color;
     }

     string getText() const {
         return text;
     }

     TextAlignment getTextAlignment() const {
         return textAlignment;
     }

     Color getColor() const {
         return color;
     }

     override Cell[] render() const {
         Cell[] cells;

         for (int x = 0; x < 0 + text.length; ++x) {
             cells ~= Cell(Coordinates(x, 0), text[x], color);
         }

         return cells;
     }
}
```

It's not a lot of code that has been added but if you have a 
class with say 10 different fields, adding getter methods would 
definitely increase the code size by a lot, so what are you guys 
thoughts on this?
Nov 16 2022
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
I wouldn't bother.

They are const, they can't change.

Nothing to protect, nothing to synchronize.
Nov 16 2022
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/16/22 20:39, thebluepandabear wrote:

 I am debating whether or not I should add getter methods to these
 properties.
If you are debating, then the answer is easy: you should not. :) Less code written means less bugs, more cohesion, easier refactoring, cleaner code, all good stuff... Even if a design requires e.g. a 'length' method, the default one should be a getter. A setter will come in the future only if 'length = 42' is clearly better than e.g. 'expandTo(42)'.
 in other languages like Java it is a good practice:
I've seen so many tutorials where any user-defined type immediately defines getters and setters. It is never good style to do that. There are good examples of where doing that is clearly wrong. For example, can a Date class really provide a setMonth() setter? It would be so wrong, I don't even know where to begin. (I remember talks by Kevlin Henney where he would use that example.) The guidelines I follow are simple in the following order: - Don't write any code until it makes sense :) - Don't write a getter until it makes sense - Don't write a setter until it makes sense Ali
Nov 16 2022
parent thebluepandabear <therealbluepandabear protonmail.com> writes:
On Thursday, 17 November 2022 at 06:29:56 UTC, Ali Çehreli wrote:
 On 11/16/22 20:39, thebluepandabear wrote:

 I am debating whether or not I should add getter methods to
these
 properties.
If you are debating, then the answer is easy: you should not. :) Less code written means less bugs, more cohesion, easier refactoring, cleaner code, all good stuff... Even if a design requires e.g. a 'length' method, the default one should be a getter. A setter will come in the future only if 'length = 42' is clearly better than e.g. 'expandTo(42)'.
 in other languages like Java it is a good practice:
I've seen so many tutorials where any user-defined type immediately defines getters and setters. It is never good style to do that. There are good examples of where doing that is clearly wrong. For example, can a Date class really provide a setMonth() setter? It would be so wrong, I don't even know where to begin. (I remember talks by Kevlin Henney where he would use that example.) The guidelines I follow are simple in the following order: - Don't write any code until it makes sense :) - Don't write a getter until it makes sense - Don't write a setter until it makes sense Ali
Appreciate your insight. Btw I think my example is a bit flawed as the fields are const 😂 I would be interested in hearing your thoughts on using 'const'. Many people claim that all variables should be const by default, but whether or not it is really needed is debatable and oftentimes making everything const could cause readability issues and make the code more complex. There is no real end to how much variables can be const. Oftentimes in popular repos I don't even see const being used. Some languages like Kotlin and Rust are const by default, but for languages that are not like D I have always wondered how often you should use const.
Nov 16 2022
prev sibling next sibling parent reply []() {}() <silentLambdas gmaiol.com> writes:
On Thursday, 17 November 2022 at 04:39:35 UTC, thebluepandabear 
wrote:
 I am creating a TUI library and I have a class with the 
 following constant fields:

 ```
 class Label : Renderable {
     const string text;
     const TextAlignment textAlignment;
     const Color color;

     this(Dimensions dimensions, string text, TextAlignment 
 textAlignment, Color color) {
         this.dimensions = dimensions;
         this(text, textAlignment, color);
     }

     this(string text, TextAlignment textAlignment, Color color) 
 {
         this.text = text;
         this.textAlignment = textAlignment;
         this.color = color;
     }

     override Cell[] render() const {
         Cell[] cells;

         for (int x = 0; x < 0 + text.length; ++x) {
             cells ~= Cell(Coordinates(x, 0), text[x], color);
         }

         return cells;
     }
 }
 ```

 I am debating whether or not I should add getter methods to 
 these properties. On one hand, it will inflate the codebase by 
 a lot, on the other hand -- in other languages like Java it is 
 a good practice:

 ```
 class Label : Renderable {
     private const string text;
     private const TextAlignment textAlignment;
     private const Color color;

     this(Dimensions dimensions, string text, TextAlignment 
 textAlignment, Color color) {
         this.dimensions = dimensions;
         this(text, textAlignment, color);
     }

     this(string text, TextAlignment textAlignment, Color color) 
 {
         this.text = text;
         this.textAlignment = textAlignment;
         this.color = color;
     }

     string getText() const {
         return text;
     }

     TextAlignment getTextAlignment() const {
         return textAlignment;
     }

     Color getColor() const {
         return color;
     }

     override Cell[] render() const {
         Cell[] cells;

         for (int x = 0; x < 0 + text.length; ++x) {
             cells ~= Cell(Coordinates(x, 0), text[x], color);
         }

         return cells;
     }
 }
 ```

 It's not a lot of code that has been added but if you have a 
 class with say 10 different fields, adding getter methods would 
 definitely increase the code size by a lot, so what are you 
 guys thoughts on this?
The Java code you presented requires getter, since your member variables are private (which is the default in java anyway). In D, public is the default. First decided whether you really do want them public (because those members now form a part of the interface that you present to the user of that class, which immediately constrains you in terms of changes). Decide whether they are in fact amenable to direct public access (i.e. do you need to test for null, or have some other rule that you must meet before providing a value back to the caller? Better to just make them private, and then provide getters. Then if you do need to implement a check for null or whatever, then you can do that with changing the interface. Controlled access to data (i.e. data protection) should always be the default, unless you are absolutely sure you don't need (and will never need) that controlled access.
Nov 17 2022
parent thebluepandabear <therealbluepandabear protonmail.com> writes:
 (and will never need) that controlled access.
Thanks. BTW the code is not Java, it is 100% D.
Nov 17 2022
prev sibling next sibling parent reply matheus <matheus gmail.com> writes:
On Thursday, 17 November 2022 at 04:39:35 UTC, thebluepandabear 
wrote:
 ...
 It's not a lot of code that has been added but if you have a 
 class with say 10 different fields, adding getter methods would 
 definitely increase the code size by a lot, so what are you 
 guys thoughts on this?
Food for thought: https://yewtu.be/watch?v=_xLgr6Ng4qQ or https://www.youtube.com/embed/_xLgr6Ng4qQ Matheus.
Nov 17 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Thursday, 17 November 2022 at 09:46:57 UTC, matheus wrote:
 Food for thought:

 https://yewtu.be/watch?v=_xLgr6Ng4qQ

 or

 https://www.youtube.com/embed/_xLgr6Ng4qQ

 Matheus.
'Food for thought'? Sure, if you're feeding that to your dog. Public fields in 'class' definitions rarely have place in production level code. How would you enforce the business rules?? Lets say, you have declared a public member variable that is of type int, but must be constrained to be within a particular range of that int? Well, you cannot enforce a business rule like that using a public member variable. The user of your class can easily corrupt you data, because they can access it directly. Well, you enforce a business rule, by making it a private member variable and having a public setter that accepts a value and checks whether it meets the business rule, and only if it does, and only if it does, will that value then be assigned to the member variable. That video link you presented is just dog food. Let your dog think about it. In the meantime, you think about production level code please.
Nov 18 2022
parent reply matheus <matheus gmail.com> writes:
On Friday, 18 November 2022 at 09:42:21 UTC, []() {}() wrote:
 ...
I think you missed the point of that video very badly. By the way just a few points from that video: Around: 2:32 -> "Never ever put in an 'accessor' until it actually does something...". Around: 3:10 -> "If there is an 'accessor' it had better do something in there...". Matheus.
Nov 18 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Friday, 18 November 2022 at 20:18:41 UTC, matheus wrote:
 On Friday, 18 November 2022 at 09:42:21 UTC, []() {}() wrote:
 ...
I think you missed the point of that video very badly. By the way just a few points from that video: Around: 2:32 -> "Never ever put in an 'accessor' until it actually does something...".
ok. But then you've made the member variable a part of the interface to the client, and if you even need to constrain the value being assigned to the member, you will have to break that interface. In production-level code, it is rare you would allow unconstrained access to a member variable. Not unheard of, just rare. And in any case, a simple accessor allows you to do so, should you're business rules ever change. You should plan for change, in production-level code. That's the 'point' missing from that rant in that video.
 Around: 3:10 -> "If there is an 'accessor' it had better do 
 something in there...".
It likely already does something, in that- >'it allows for change to occur without having to break the clients interface'. That too is the 'point' missing from that rant.
Nov 18 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
 It likely already does something, in that- >'it allows for 
 change to occur without having to break the clients interface'.

 That too is the 'point' missing from that rant.
With all due respect, I think your point is mostly invalid due to the point that Dukc made.
Nov 18 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 03:08:05 UTC, thebluepandabear 
wrote:
 It likely already does something, in that- >'it allows for 
 change to occur without having to break the clients interface'.

 That too is the 'point' missing from that rant.
With all due respect, I think your point is mostly invalid due to the point that Dukc made.
keep programming/maintaining and enhancing production-level code for the next 10 years. then you too will know the correct answer to your question :-)
Nov 18 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
On Saturday, 19 November 2022 at 03:14:18 UTC, []() {}() wrote:
 On Saturday, 19 November 2022 at 03:08:05 UTC, thebluepandabear 
 wrote:
 It likely already does something, in that- >'it allows for 
 change to occur without having to break the clients 
 interface'.

 That too is the 'point' missing from that rant.
With all due respect, I think your point is mostly invalid due to the point that Dukc made.
keep programming/maintaining and enhancing production-level code for the next 10 years. then you too will know the correct answer to your question :-)
I think because of uniform function call syntax, getters/setters are not needed even for production level code, in D of course. In Java, you do need them so your point holds true in that scenario, but in D I don't really see the point after giving it some thought, I would say they are code bloat.
Nov 18 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 03:24:41 UTC, thebluepandabear 
wrote:
 I think because of uniform function call syntax, 
 getters/setters are not needed even for production level code, 
 in D of course. In Java, you do need them so your point holds 
 true in that scenario, but in D I don't really see the point 
 after giving it some thought, I would say they are code bloat.
I like to see an example, of a 'class type' with 'public' member variables, somehow magically converted into both getter and setter using UFCS, without breaking client code.
Nov 18 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/18/22 19:35, [] () {} () wrote:

 I like to see an example, of a 'class type' with 'public' member
 variables, somehow magically converted into both getter and setter using
 UFCS, without breaking client code.
UFCS was mentioned before in the same context but I think what is meant was the D feature where functions can be called without parenthesis. Let's say, we have a pure data type: struct Point { int x; int y; } void clientCode() { auto p = Point(); p.y = p.x + 42; } void main() { clientCode(); } <aside>It took me 20 years to first think that public access to members was extremely wrong to then realize that there may not be any problem with it at all. As you said, "business logic" (I prefer "invariants") warrants limiting access to members. Without anything to protect, it is just extra work for no reason at all. (I fully agree with the posted video.) </aside> Ok, let's say that the business requirements changed and we wanted to perform some business logic. Thanks to D's pragmatism, clientCode() does not change at all: struct Point { int x_; // Rename int y_; // Rename auto x() { // Getter return x_ + y_; } auto y(int value) { // Setter x_ = value * 2; y_ = value / 2; } } void clientCode() { auto p = Point(); p.y = p.x + 42; } void main() { clientCode(); } There: clientCode() is not broken. Ali
Nov 19 2022
parent reply [] () {} () <SilentLamba gmail.com> writes:
On Saturday, 19 November 2022 at 19:40:43 UTC, Ali Çehreli wrote:
 ..
 (I fully agree with the posted video.)
 ...
Quoted from that video (the one that you agree with): "I don't ever think that private .. private is like just .. shouldn't even be used." "so I don't even use classes I just use struct so that everything is always public .. and that in my opinion is the correct method." Now, after thoroughly examining that rant, I better understand his agenda. It's hard for me to conceive how a someone who thinks of themself as a 'software engineer' could agree with this. anyho.. If anyone wants to learn more about why encapsulated types (classes) have shown to be so useful in my many years of programming, they can first pay me my fee.
Nov 20 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/20/22 00:31, [] () {} () wrote:

 Quoted from that video (the one that you agree with):

 "I don't ever think that private .. private is like just .. shouldn't
 even be used."

 "so I don't even use classes I just use struct so that everything is
 always public .. and that in my opinion is the correct method."
Yes, still agreeing with it.
 If anyone wants to learn more about why encapsulated types
 (classes) have shown to be so useful in my many years of programming,
Hm. 'private' is about access control. Encapsulation is something else.
 they can first pay me my fee.
If I could, I would like to pay to have less of that please. :) Ali
Nov 20 2022
next sibling parent reply [] () {} () <SilentLambda gmail.com> writes:
On Sunday, 20 November 2022 at 12:23:39 UTC, Ali Çehreli wrote:
 On 11/20/22 00:31, [] () {} () wrote:

 Quoted from that video (the one that you agree with):

 "I don't ever think that private .. private is like just ..
shouldn't
 even be used."

 "so I don't even use classes I just use struct so that
everything is
 always public .. and that in my opinion is the correct
method." Yes, still agreeing with it.
 If anyone wants to learn more about why encapsulated types
 (classes) have shown to be so useful in my many years of
programming, Hm. 'private' is about access control. Encapsulation is something else.
 they can first pay me my fee.
If I could, I would like to pay to have less of that please. :) Ali
so, as I understand it, your're against the use of private, against the use of class, and against the use of encapsulation. we have nothing more to discuss.. .. good luck with your career as a software engineer (but please, for all our sakes, don't work on any safety-related systems, and especially not the ones running in my car).
Nov 20 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/20/22 14:37, [] () {} () wrote:

 so, as I understand it, your're against the use of private, against the
 use of class, and against the use of encapsulation.
I never implied any of that.
 .. good luck with your career as a software engineer (but please, for
 all our sakes, don't work on any safety-related systems, and especially
 not the ones running in my car).
I haven't written any code that runs on the car yet but I did and still do work in autonomous vehicle projects: https://techcrunch.com/2017/04/04/daimler-and-bosch-fully-autonomous-cars-within-5-years/ (That partnership is no more at this time.) And coincidentally, to reply to your post that included Autosar, MISRA, etc. I am very well aware of those standards because I did contribute to the team that wrote our coding standards by going through every single one of their rules. As one would expect, there was no argument on whether to use getters and setters or direct public access for that project: We decided no public access to members. This discussion came to this point because you and I understood the question differently: I took the OP's question literally: "Is defining get/set methods for every field overkill?" You took the question as whether to define them for class hierarchies, safety-critical systems, etc. Ali
Nov 21 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Monday, 21 November 2022 at 11:56:59 UTC, Ali Çehreli wrote:
 ..
 You took the question as whether to define them for class 
 hierarchies, safety-critical systems, etc.

 Ali
Or even in a very, very simple counter class: public synchronized class Counter { static import core.atomic; private: int count = 0; public: void incrementCounter() { if ((count + 1) < 0) { // you might want to handle this } else core.atomic.atomicOp!"+="(this.count, 1); } int displayCounter() { return count; } }
Nov 21 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
On Monday, 21 November 2022 at 23:25:21 UTC, []() {}() wrote:
 On Monday, 21 November 2022 at 11:56:59 UTC, Ali Çehreli wrote:
 ..
 You took the question as whether to define them for class 
 hierarchies, safety-critical systems, etc.

 Ali
Or even in a very, very simple counter class: public synchronized class Counter { static import core.atomic; private: int count = 0; public: void incrementCounter() { if ((count + 1) < 0) { // you might want to handle this } else core.atomic.atomicOp!"+="(this.count, 1); } int displayCounter() { return count; } }
But why give a C++ code example? 🤨
Nov 21 2022
parent reply Siarhei Siamashka <siarhei.siamashka gmail.com> writes:
On Monday, 21 November 2022 at 23:41:22 UTC, thebluepandabear 
wrote:
 But why give a C++ code example? 🤨
It's a D code example and it even can't be compiled by a C++ compiler. Just add the missing main function: ```D void main() { shared c = new Counter; c.incrementCounter; c.count = 12345; // haha, this isn't really private in D (unless the class // is moved to a different module in its own personal file) writeln(c.displayCounter); } ``` The `counter` member variable isn't really protected from rogue accesses (if these accesses are done by the code in the same source file) and this behavior differs from C++.
Nov 21 2022
next sibling parent thebluepandabear <therealbluepandabear protonmail.com> writes:
On Tuesday, 22 November 2022 at 00:46:34 UTC, Siarhei Siamashka 
wrote:
 On Monday, 21 November 2022 at 23:41:22 UTC, thebluepandabear 
 wrote:
 But why give a C++ code example? 🤨
It's a D code example and it even can't be compiled by a C++ compiler. Just add the missing main function:
My bad.
Nov 21 2022
prev sibling parent reply []() {}() <SilentLambda gmail.com> writes:
On Tuesday, 22 November 2022 at 00:46:34 UTC, Siarhei Siamashka 
wrote:
 ..
 The `counter` member variable isn't really protected from rogue 
 accesses (if these accesses are done by the code in the same 
 source file) and this behavior differs from C++.
module CounterTest; // concrete public synchronized class Counter // if only D has this property. public synchronized class Counter { static import core.atomic; private: int count = 0; public: void incrementCounter() { if ((count + 1) < 0) { // you might want to handle this } else core.atomic.atomicOp!"+="(this.count, 1); } int displayCounter() { return count; } } void main() { import std; shared Counter c = new Counter; for (int i = 0; i < 5; i++) c.incrementCounter; c.count = 0; // not if your class is a concrete class writeln(c.displayCounter); } unittest { shared Counter c = new Counter; c.count = 0; // not if your class is a concrete class }
Nov 21 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Tuesday, 22 November 2022 at 02:11:20 UTC, []() {}() wrote:

maybe:  complete class

insteadof:  concrete class
Nov 21 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Tuesday, 22 November 2022 at 02:16:16 UTC, []() {}() wrote:

nevermind ;-)  .. seems clear nobody wants something like this in 
D.

https://forum.dlang.org/post/kbl20f$2np9$1 digitalmars.com

and... 20 years later.... ... .. .
Nov 21 2022
parent reply Sergey <kornburn yandex.ru> writes:
On Tuesday, 22 November 2022 at 03:04:03 UTC, []() {}() wrote:
 On Tuesday, 22 November 2022 at 02:16:16 UTC, []() {}() wrote:

 nevermind ;-)  .. seems clear nobody wants something like this 
 in D.

 https://forum.dlang.org/post/kbl20f$2np9$1 digitalmars.com

 and... 20 years later.... ... .. .
Based on this (not too old) post the idea remains the same and approved by Walter’s experience: https://dlang.org/blog/2018/11/06/lost-in-translation-encapsulation/ I saw some posts at forum about private-class-scope, but community of core-D is fine with module-unit approach I think.
Nov 22 2022
next sibling parent reply []() {}() <SilentLambda gmail.com> writes:
On Tuesday, 22 November 2022 at 10:10:48 UTC, Sergey wrote:
 Based on this (not too old) post the idea remains the same and 
 approved by Walter’s experience:
 https://dlang.org/blog/2018/11/06/lost-in-translation-encapsulation/
 I saw some posts at forum about private-class-scope, but 
 community of core-D is fine with module-unit approach I think.
In the interest of 'critical thinking', it's important to point out, that one of the persons in this thread agreeing with the one-sided rant in the video link in this thread, is a co-author of that article. It also seems, that article is primarly discussing encapsulation. Encapsulation is not enough, as I've pointed out in this thread. In D, one can no longer provide a static specification of a class type, let alone rely on the compiler to assure you of the correctness of that specification, in relation to the code surrounding it). Rather, in D, one must always include all the code in the module as being part of the static specification of the class (and the same is true for how ever many classes you have in that module). Even another class could form part of the specification of another class in the same module, even though they are both concrete classes. Wow! I'm sorry, but that makes no sense to me. The designers of the other languages mentioned in that article, seem to have the same opinion. Whatever happened to the principle of least priveledge in D? Of course, if you're against the us of private, against the use of getters and setters, and against the use of classes, in D, then sure, I can fully understand the decision to completely remove the perimeter for a class type, and hence that article makes complete sense. Regardless, I fully support the concept that people should always form their own opinion - even on matters as absurd as this ;-)
Nov 22 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Tuesday, 22 November 2022 at 20:36:51 UTC, []() {}() wrote:

 From a software engineering perspective, what justification can 
their possibly be, for allowing (by default, and with no language 
mechanism to prevent it) any code in the same module as this 
class (including a tightly coupled, but otherwise fully 
specificed class), to override the specification of this class? 
How does that enhance encapsulation, as argued in that article?


     public synchronized class Counter
     {
         static import core.atomic;

         private:
             int count = 0;

         public:
             void incrementCounter()
             {
                 if ((count + 1) < 0)
                 {
                     // you might want to handle this
                 }
                 else
                     core.atomic.atomicOp!"+="(this.count, 1);
             }

             int displayCounter()
             {
                 return count;
             }
     }
Nov 22 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Tuesday, 22 November 2022 at 21:00:58 UTC, []() {}() wrote:

"Being able to declare a “friend” that is somewhere in some other 
file runs against notions of encapsulation." (This is the 
motivation for that article it seems).

I completely disagree with the assertion.

C++ Friend notion does not, not by any means, run against the 
notion of encapsulation.

Sure, it expands the perimeter (i.e. it puts a door in the wall).

But, and this is my point, there is a guard standing at the door. 
And that guard knows who has been authorised to pass through it. 
The encapsulation remains. Only its perimeter has been expanded.

One could argue that D's approach is just that. It expands the 
perimeter to the module level. But there's no guard at the door 
in D.

Surely, this 'let anyone pass through' design, decreases 
encapsulation? How could it possibly increase encapsulation, as 
claimed, by the author of that article?

If there were a means in the language for controlled sharing 
within a module, *that* would increase encapsulation.
Nov 22 2022
parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Tuesday, 22 November 2022 at 21:45:29 UTC, []() {}() wrote:
 On Tuesday, 22 November 2022 at 21:00:58 UTC, []() {}() wrote:

 "Being able to declare a “friend” that is somewhere in some 
 other file runs against notions of encapsulation." (This is the 
 motivation for that article it seems).

 I completely disagree with the assertion.

 C++ Friend notion does not, not by any means, run against the 
 notion of encapsulation.

 Sure, it expands the perimeter (i.e. it puts a door in the 
 wall).

 But, and this is my point, there is a guard standing at the 
 door. And that guard knows who has been authorised to pass 
 through it. The encapsulation remains. Only its perimeter has 
 been expanded.

 One could argue that D's approach is just that. It expands the 
 perimeter to the module level. But there's no guard at the door 
 in D.

 Surely, this 'let anyone pass through' design, decreases 
 encapsulation? How could it possibly increase encapsulation, as 
 claimed, by the author of that article?

 If there were a means in the language for controlled sharing 
 within a module, *that* would increase encapsulation.
The module is the capsule. D is simply not interested in building a capsule around a class. D does not let "anyone" pass through, it lets "anyone in the module" pass through, because the module is the wall. I think this is a stronger concept of encapsulation than C++ friends because the encapsulation is lexical rather than just declarative.
Nov 23 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Wednesday, 23 November 2022 at 09:51:46 UTC, FeepingCreature 
wrote:
 The module is the capsule. D is simply not interested in 
 building a capsule around a class. D does not let "anyone" pass 
 through, it lets "anyone in the module" pass through, because 
 the module is the wall. I think this is a stronger concept of 
 encapsulation than C++ friends because the encapsulation is 
 lexical rather than just declarative.
But if I write a class specification, then that class will be its own capsule. It will be its own type, just like a built in type. It will have its own interface by which other code can interact with it, just like a built in type. Why then should a programming language insist that all other code in the module should be able to bypass my specification, and do as it pleases to my type? If this applied to built in types, imagine the chaos that could follow from that. Well, the class is a type as well. I struggle to see how treating other code in the module as though it is a part of the specification of my type (ie. all that code is essentially inside the perimeter of my class type), benefits me as software engineer. I am surely missing something here. In C++, if I want another type to interact with my type, in a tightly coupled manner, then I can explicately authorise that interaction very easily, using friend. Now when I see my code, or others read my code, they know intent. In a D module, intent cannot be discovered so easily, since it cannot be explicately declared. Not even the compiler knows your intent. It can only assume everything you typed in the module is correct. And now your counter class overflows...and boom!
Nov 23 2022
parent reply Tejas <notrealemail gmail.com> writes:
On Wednesday, 23 November 2022 at 11:06:12 UTC, []() {}() wrote:
 On Wednesday, 23 November 2022 at 09:51:46 UTC, FeepingCreature 
 wrote:

 Why then should a programming language insist that all other 
 code in the module should be able to bypass my specification, 
 and do as it pleases to my type?
Please let's not repeat previous topics `private` will be enforced at module scope, for better or for worse, there has already been a [1000 post thread](https://forum.dlang.org/post/lqlllioynzfmpaozwbfj forum.dlang.org) that resulted in basically nothing except someone creating a `private this` pull for curiosity that will never be accepted in the language Look at the very last post where the moderator had to externally kill the thread to prevent it from being revived/argued further
Nov 23 2022
next sibling parent []() {}() <SilentLambda gmail.com> writes:
On Wednesday, 23 November 2022 at 13:24:37 UTC, Tejas wrote:
 On Wednesday, 23 November 2022 at 11:06:12 UTC, []() {}() wrote:
 On Wednesday, 23 November 2022 at 09:51:46 UTC, 
 FeepingCreature wrote:

 Why then should a programming language insist that all other 
 code in the module should be able to bypass my specification, 
 and do as it pleases to my type?
Please let's not repeat previous topics `private` will be enforced at module scope, for better or for worse, there has already been a [1000 post thread](https://forum.dlang.org/post/lqlllioynzfmpaozwbfj forum.dlang.org) that resulted in basically nothing except someone creating a `private this` pull for curiosity that will never be accepted in the language Look at the very last post where the moderator had to externally kill the thread to prevent it from being revived/argued further
I wasnt discussing private, and it's rather off the point somewhat. I was responding to the claims that were made in the blog that someone mentioned in this thread: https://dlang.org/blog/2018/11/06/lost-in-translation-encapsulation/ The claim was, that Friends in C++ breaks encapsulation. But that is not correct. It merely expands the perimeter of that encapsulation by putting a door in the wall, along with a guard at the door. The encapsulation remains. The encapsulation itself is not enough however, hence the guard at the door. And if you program classes 'as types' (whether you additionally do OOP or not - as that too is off the point), then coming to D and finding out that in the context of a module, your class is not even a type (because it simply has no perimeter at all in a module), then I cannot see how that enhances encapsulation, as was claimed in the blog. How can that possibly enhance encapsulation? That makes no sense. If the blog were published in a journal.. well.. it would never get published in a journal ;-) Critical analysis remains a great tool, even in relation to 'blogs'.
Nov 23 2022
prev sibling next sibling parent reply []() {}() <SilentLambda gmail.com> writes:
On Wednesday, 23 November 2022 at 13:24:37 UTC, Tejas wrote:

In fact that author of that article wrote this in his blog:

"For one, we want to ensure that private members aren’t 
manipulated outside of class declarations with hundreds or 
thousands of lines in between. "

Yes. That is where we agree.

Where we disgree, it seems, is that I do not want to have to 
completely refactor my modules in order to achieve this, as he 
explains in his blog.

This refactoring is required before you can have a true class 
type in a D module.

That is, a type with its own perimeter.

No wonder people are 'surprised when they come to D'.

I mean, who wouldn't be?
Nov 23 2022
parent reply []() {}() <SilentLamba gmail.com> writes:
On Wednesday, 23 November 2022 at 22:43:54 UTC, []() {}() wrote:

My last post ;-)

It seems far too many people conflate classes and oop.

You can do oop without classes (whether you would want to is 
another question all together).

You can also use class-types without doing oop.

A class-type is just a type. If you're against a class-type, you 
must also be against an int type, a char type, a function type, 
and enum type.....

Now *clearly* many D users appear to be in the anti oop camp.

But please don't be in the anti class-type camp.

Class 'types' really are an extremely useful and important tool 
in software engineering, regardless of whether you use them as a 
tool to do oop, or not.

That the D module dissolves that perimeters of my types - in 
relation to other code in the same module, is a really odd design 
decision that I cannot, as yet, get my head around. That is, I 
can see no possible way in which this design decision can enhance 
my coding, even after having given if way more thought than it 
deserves.
Nov 23 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
 That the D module dissolves that perimeters of my types - in 
 relation to other code in the same module, is a really odd 
 design decision that I cannot, as yet, get my head around. That 
 is, I can see no possible way in which this design decision can 
 enhance my coding, even after having given if way more thought 
 than it deserves.
Please stop, we get it... I'm not a moderator so I cannot enforce rules but there is NO need to continue this debate here. This software 'religiousness' is too much.
Nov 23 2022
parent reply Mike Parker <aldacron gmail.com> writes:
On Wednesday, 23 November 2022 at 23:35:59 UTC, thebluepandabear 
wrote:

 Please stop, we get it... I'm not a moderator so I cannot 
 enforce rules but there is NO need to continue this debate 
 here. This software 'religiousness' is too much.
I am a moderator and I can enforce the rules. So yes, let's please drop this tired old debate about private and get back on topic. Or just let the thread die. Thanks.
Nov 23 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Thursday, 24 November 2022 at 02:00:15 UTC, Mike Parker wrote:
 On Wednesday, 23 November 2022 at 23:35:59 UTC, 
 thebluepandabear wrote:

 Please stop, we get it... I'm not a moderator so I cannot 
 enforce rules but there is NO need to continue this debate 
 here. This software 'religiousness' is too much.
I am a moderator and I can enforce the rules. So yes, let's please drop this tired old debate about private and get back on topic. Or just let the thread die. Thanks.
I broke a forum rule by critically analysing your blog? Wow.
Nov 23 2022
next sibling parent thebluepandabear <therealbluepandabear protonmail.com> writes:
 I broke a forum rule by critically analysing your blog?

 Wow.
Erm... You went off topic.
Nov 23 2022
prev sibling parent Mike Parker <aldacron gmail.com> writes:
On Thursday, 24 November 2022 at 03:49:16 UTC, []() {}() wrote:

 I broke a forum rule by critically analysing your blog?

 Wow.
Criticize my blog posts all you want. Just stop please stop derailing threads. I'm going to delete further off topic posts in this thread.
Nov 23 2022
prev sibling parent surlymoor <surlymoor cock.li> writes:
On Wednesday, 23 November 2022 at 13:24:37 UTC, Tejas wrote:
 Please let's not repeat previous topics

 `private` will be enforced at module scope, for better or for 
 worse, there has already been a [1000 post 
 thread](https://forum.dlang.org/post/lqlllioynzfmpaozwbfj forum.dlang.org)
that resulted in basically nothing except someone creating a `private this`
pull for curiosity that will never be accepted in the language

 Look at the very last post where the moderator had to 
 externally kill the thread to prevent it from being 
 revived/argued further
It's the same guy. He knows what he's doing and will not let this go, like a vengeful spirit.
Nov 23 2022
prev sibling parent []() {}() <SilentLambda gmail.com> writes:
On Tuesday, 22 November 2022 at 10:10:48 UTC, Sergey wrote:
 ..
 I saw some posts at forum about private-class-scope, but 
 community of core-D is fine with module-unit approach I think.
That's fair enough. I fully support 'majority rules' (if that's what's happening here). But it could limit the uptake of the langauge, particulary for those software engineers who believe that when you are defining a class, you are defining a type - as Scott Myers has put it. To such people, other code in the module shouldn't affect my type, in the same way it shouldn't affect a built-in type. At least, not unless I've authorised it, as part of the specification of my type, which presumably I have, by default, just by including any other code in a module, where a class type has been defined. In such a module, one should annotate the class with hereBeDragons
Nov 22 2022
prev sibling next sibling parent reply Siarhei Siamashka <siarhei.siamashka gmail.com> writes:
On Sunday, 20 November 2022 at 12:23:39 UTC, Ali Çehreli wrote:
 On 11/20/22 00:31, [] () {} () wrote:
 If anyone wants to learn more about why encapsulated types
 (classes) have shown to be so useful in my many years of
programming, Hm. 'private' is about access control. Encapsulation is something else.
BTW, many software developers and also wikipedia actually agree with [] () {} (): https://en.wikipedia.org/wiki/Encapsulation_(computer_programming) And this all is getting really silly. The proof is in the pudding. I mean the existence of really large successful software is the best evidence of the programming language or coding technique superiority. C++ has plenty of large successful object oriented software written using it (Mozilla, Chromium, LibreOffice, Qt, LLVM, ...). People had a lot of time to try various C++ features and everyone has their own opinion. Multiple inheritance isn't very popular, but having private class members and the ability to easily hide class implementation details is generally seen as a good and useful feature. D makes a rather arbitrary change to encapsulation and claims that this is an improvement. But you can't easily convince everyone by just making such claims. How it really works in practice is the only thing that matters.
Nov 20 2022
parent reply [] () {} () <SilentLambda gmail.com> writes:
On Sunday, 20 November 2022 at 23:04:18 UTC, Siarhei Siamashka 
wrote:
 ..
 BTW, many software developers and also wikipedia actually agree 
 with [] () {} (): 
 https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)
and.. Autostar C++, Misra C++, Cert C++ ... I could go on and on. but as you rightly point out, the proof is in the pudding. some of us actually enjoy going to work each day and creating great software for our customers...and having to type a getter/setter doesn't bother us one little bit ;-) the alternative is just make everything public, and watch our customer systems fail terribly, with all kinds of awful consequences... .. not to mention, I'd be out of job if I stopped writing getters/setters ;-)
Nov 20 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
 .. not to mention, I'd be out of job if I stopped writing 
 getters/setters ;-)
I value your input in this discussion, you have brought some good points. Out of interest, what type of industry-level software are you creating with D? I don't know much companies using D commercially.
Nov 20 2022
next sibling parent thebluepandabear <therealbluepandabear protonmail.com> writes:
On Monday, 21 November 2022 at 00:29:12 UTC, thebluepandabear 
wrote:
 .. not to mention, I'd be out of job if I stopped writing 
 getters/setters ;-)
I value your input in this discussion, you have brought some good points. Out of interest, what type of industry-level software are you creating with D? I don't know much companies using D commercially.
I think I may actually have been convinced that writing getters/setters is good practice, I think it's better be safe than sorry because I am writing a library it may be important not to break ABI compatibility in the future if needed, plus I will not need to change the field name if I ever want to add getters/setters.
Nov 20 2022
prev sibling parent [] () {} () <SilentLambda gmail.com> writes:
On Monday, 21 November 2022 at 00:29:12 UTC, thebluepandabear 
wrote:
 .. not to mention, I'd be out of job if I stopped writing 
 getters/setters ;-)
I value your input in this discussion, you have brought some good points. Out of interest, what type of industry-level software are you creating with D? I don't know much companies using D commercially.
As someone else mentioned in this thread, there are some 'arbitrary changes' in D, for example, to the traditional concept of the class type, as being a user-defined type for encapsulating data and methods that operate on that data. That is, the module, not the class, is the unit of encapsulation in D. In addition, public is the default visibility in a class in D, which also goes against the traditional concept of using an encapsulated user-defined data type in conjunction with 'information hiding' (or access controls, depending on what terminology you want to use). These decisions no doubt, are design decisions, and not accidental, I presume. These decisions have consequences of course. You should be completely aware of these changes in D, *before* embarking on using classes in D. Some would say those consequences are benefical, while others would reject that proposition, entirely ;-) As such I leave it to the designer(s) of D to better explain their reasoning. These changes by themself rule out the use of D in our environment. "..utility functions operating on data structures. Welcome to 1972!" There are many other reasons also of course, which frankly are unrelated to (and more important) than the above. But otherwise, I find D to be an enjoyable hobby language, particulary for lower-level programming, to both use and explore its capabilities. There are of course some companies using it commercially. But not the company I work for.
Nov 20 2022
prev sibling next sibling parent [] () {} () <SilentLambda gmail.com> writes:
On Sunday, 20 November 2022 at 12:23:39 UTC, Ali Çehreli wrote:
 Hm. 'private' is about access control. Encapsulation is 
 something else.

 Ali
"Clearly, encapsulation is not enough." https://www.infoworld.com/article/2075271/encapsulation-is-not-information-hiding.html
Nov 20 2022
prev sibling parent reply [] () {} () <SilentLambda gmail.com> writes:
On Sunday, 20 November 2022 at 12:23:39 UTC, Ali Çehreli wrote:
 ..
 Hm. 'private' is about access control. ....
It's unfortunate that phrase ('private') is used, both traditionally, and now (and yes, even by me). A much better, clearer term, would be: 'interaction control', since that is what the programmer is really trying to achieve when inserting getters/setters into a class type. i.e They are creating the specification for an encapulated object (data, and methods that operate on that data) with the necessary controls for 'interacting' with it. On the otherhand, if the programmer is genuinely after 'access' control, then 'private' just won't do it ;-) Also, D's 'arbitrary' changes, as mentioned in previous post, do not further progress the composition problem. By that I mean, by enabling cooperative interactions within a module, D has also enabled potentially hazardous interactions as well, since you cannot enforce a perimeter around a class type from other code in the module. All code within a module, is within the bounds of that perimeter, at all times. i.e. There is no way to enforce the principle of least privilege within a D module. On that basis, I might be tempted to agree with you're point of view -> never, ever, ever, ever, use classes in D.
Nov 20 2022
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/20/22 23:01, [] () {} () wrote:

 On that basis, I might be tempted to agree with you're point of view ->
 never, ever, ever, ever, use classes in D.
That's not my point of view. Ali
Nov 21 2022
prev sibling next sibling parent reply Dukc <ajieskola gmail.com> writes:
On Thursday, 17 November 2022 at 04:39:35 UTC, thebluepandabear 
wrote:
 I am debating whether or not I should add getter methods to 
 these properties. On one hand, it will inflate the codebase by 
 a lot, on the other hand -- in other languages like Java it is 
 a good practice
D has far less need for getters/setters than Java or C++. The reason is [Uniform Function Call Syntax](https://ddili.org/ders/d.en/ufcs.html). This means that a member of a `struct` or `class` can start out as a normal field and be later converted to getter/setter if needed, without breaking calling code. You still might want to use setters when you want to be extra conservative (client code taking address of a struct field will still break if your getter replacing it can't return by `ref`), but for the vast majority of purposes that is an overkill IMO.
Nov 17 2022
next sibling parent reply Gavin Ray <ray.gavin97 gmail.com> writes:
On Thursday, 17 November 2022 at 09:52:11 UTC, Dukc wrote:

 D has far less need for getters/setters than Java or C++. The 
 reason is [Uniform Function Call 
 Syntax](https://ddili.org/ders/d.en/ufcs.html). This means that 
 a member of a `struct` or `class` can start out as a normal 
 field and be later converted to getter/setter if needed, 
 without breaking calling code.
This is a great point that I actually had never considered. If you need to swap out the implementation details later, you haven't actually locked yourself in to exposing the raw member because you swap it with a getter function/property of the same name. Huh. I love D.
Nov 18 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
On Saturday, 19 November 2022 at 00:25:57 UTC, Gavin Ray wrote:
 On Thursday, 17 November 2022 at 09:52:11 UTC, Dukc wrote:

 D has far less need for getters/setters than Java or C++. The 
 reason is [Uniform Function Call 
 Syntax](https://ddili.org/ders/d.en/ufcs.html). This means 
 that a member of a `struct` or `class` can start out as a 
 normal field and be later converted to getter/setter if 
 needed, without breaking calling code.
This is a great point that I actually had never considered. If you need to swap out the implementation details later, you haven't actually locked yourself in to exposing the raw member because you swap it with a getter function/property of the same name. Huh. I love D.
Interesting point. If that's the case, I'd say getters/setters are mostly just code bloat.
Nov 18 2022
parent thebluepandabear <therealbluepandabear protonmail.com> writes:
On Saturday, 19 November 2022 at 03:04:41 UTC, thebluepandabear 
wrote:
 On Saturday, 19 November 2022 at 00:25:57 UTC, Gavin Ray wrote:
 On Thursday, 17 November 2022 at 09:52:11 UTC, Dukc wrote:

 D has far less need for getters/setters than Java or C++. The 
 reason is [Uniform Function Call 
 Syntax](https://ddili.org/ders/d.en/ufcs.html). This means 
 that a member of a `struct` or `class` can start out as a 
 normal field and be later converted to getter/setter if 
 needed, without breaking calling code.
This is a great point that I actually had never considered. If you need to swap out the implementation details later, you haven't actually locked yourself in to exposing the raw member because you swap it with a getter function/property of the same name. Huh. I love D.
Interesting point. If that's the case, I'd say getters/setters are mostly just code bloat.
*in most circumstances where no special behavior is needed btw
Nov 18 2022
prev sibling parent reply []() {}() <SilentLambda gmail.com> writes:
On Thursday, 17 November 2022 at 09:52:11 UTC, Dukc wrote:
 ..
 D has far less need for getters/setters than Java or C++. The 
 reason is [Uniform Function Call 
 Syntax](https://ddili.org/ders/d.en/ufcs.html). This means that 
 a member of a `struct` or `class` can start out as a normal 
 field and be later converted to getter/setter if needed, 
 without breaking calling code.
 ..
can you give an example please. i.e. before (class with public member) and after ( i.e. that public member converted to getter/setter).
Nov 18 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
On Saturday, 19 November 2022 at 03:19:53 UTC, []() {}() wrote:
 On Thursday, 17 November 2022 at 09:52:11 UTC, Dukc wrote:
 ..
 D has far less need for getters/setters than Java or C++. The 
 reason is [Uniform Function Call 
 Syntax](https://ddili.org/ders/d.en/ufcs.html). This means 
 that a member of a `struct` or `class` can start out as a 
 normal field and be later converted to getter/setter if 
 needed, without breaking calling code.
 ..
can you give an example please. i.e. before (class with public member) and after ( i.e. that public member converted to getter/setter).
Did you read the link provided? There's examples there...
Nov 18 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 03:22:12 UTC, thebluepandabear 
wrote:
 On Saturday, 19 November 2022 at 03:19:53 UTC, []() {}() wrote:
 On Thursday, 17 November 2022 at 09:52:11 UTC, Dukc wrote:
 ..
 D has far less need for getters/setters than Java or C++. The 
 reason is [Uniform Function Call 
 Syntax](https://ddili.org/ders/d.en/ufcs.html). This means 
 that a member of a `struct` or `class` can start out as a 
 normal field and be later converted to getter/setter if 
 needed, without breaking calling code.
 ..
can you give an example please. i.e. before (class with public member) and after ( i.e. that public member converted to getter/setter).
Did you read the link provided? There's examples there...
it's say for member functions, not member variables. I read it, but I dont get the point was being made about how use ufcs to convert a public member variable of a class type into a getter and setter. Was there an example in the link that I missed?
Nov 18 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
On Saturday, 19 November 2022 at 03:39:18 UTC, []() {}() wrote:
 On Saturday, 19 November 2022 at 03:22:12 UTC, thebluepandabear 
 wrote:
 On Saturday, 19 November 2022 at 03:19:53 UTC, []() {}() wrote:
 On Thursday, 17 November 2022 at 09:52:11 UTC, Dukc wrote:
 ..
 D has far less need for getters/setters than Java or C++. 
 The reason is [Uniform Function Call 
 Syntax](https://ddili.org/ders/d.en/ufcs.html). This means 
 that a member of a `struct` or `class` can start out as a 
 normal field and be later converted to getter/setter if 
 needed, without breaking calling code.
 ..
can you give an example please. i.e. before (class with public member) and after ( i.e. that public member converted to getter/setter).
Did you read the link provided? There's examples there...
it's say for member functions, not member variables. I read it, but I dont get the point was being made about how use ufcs to convert a public member variable of a class type into a getter and setter. Was there an example in the link that I missed?
It's actually kind of hard to wrap my head around. I will try to give you an example as to how you could convert a field into a getter/setter without breaking the interface between the user of the library, though it does require code refactoring on your end. Say you have the class Rect2D: ``` class Rect2D { int width; int height; } ``` The users of your class would use it like so: ``` Rect2D rect = new Rect2D(); rect.width = 5; rect.height = 5; ``` Say you want to write 'SET' now whenever someone sets a width/height value for the rect (as an example), and 'GET' when someone gets the width/height value for the rect, what you could do is do this: ``` class Rect2D { int rectWidth; int rectHeight; int width() { writeln("GET"); return rectWidth; } void width(int rectWidth) { writeln("SET"); this.rectWidth = rectWidth; } int height() { writeln("GET"); return rectHeight; } void height(int rectHeight) { writeln("SET"); this.rectHeight = rectHeight; } } ``` Honestly, it may not be a magic bullet, but still useful.
Nov 18 2022
next sibling parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
On Saturday, 19 November 2022 at 03:52:41 UTC, thebluepandabear 
wrote:
 On Saturday, 19 November 2022 at 03:39:18 UTC, []() {}() wrote:
 On Saturday, 19 November 2022 at 03:22:12 UTC, 
 thebluepandabear wrote:
 On Saturday, 19 November 2022 at 03:19:53 UTC, []() {}() 
 wrote:
 On Thursday, 17 November 2022 at 09:52:11 UTC, Dukc wrote:
 ..
 D has far less need for getters/setters than Java or C++. 
 The reason is [Uniform Function Call 
 Syntax](https://ddili.org/ders/d.en/ufcs.html). This means 
 that a member of a `struct` or `class` can start out as a 
 normal field and be later converted to getter/setter if 
 needed, without breaking calling code.
 ..
can you give an example please. i.e. before (class with public member) and after ( i.e. that public member converted to getter/setter).
Did you read the link provided? There's examples there...
it's say for member functions, not member variables. I read it, but I dont get the point was being made about how use ufcs to convert a public member variable of a class type into a getter and setter. Was there an example in the link that I missed?
It's actually kind of hard to wrap my head around. I will try to give you an example as to how you could convert a field into a getter/setter without breaking the interface between the user of the library, though it does require code refactoring on your end. Say you have the class Rect2D: ``` class Rect2D { int width; int height; } ``` The users of your class would use it like so: ``` Rect2D rect = new Rect2D(); rect.width = 5; rect.height = 5; ``` Say you want to write 'SET' now whenever someone sets a width/height value for the rect (as an example), and 'GET' when someone gets the width/height value for the rect, what you could do is do this: ``` class Rect2D { int rectWidth; int rectHeight; int width() { writeln("GET"); return rectWidth; } void width(int rectWidth) { writeln("SET"); this.rectWidth = rectWidth; } int height() { writeln("GET"); return rectHeight; } void height(int rectHeight) { writeln("SET"); this.rectHeight = rectHeight; } } ``` Honestly, it may not be a magic bullet, but still useful.
The only caveat (and I am a noob to D, so don't take any sort of advice from me seriously, please) seems to be that you just need to change the field name on your end.
Nov 18 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
A better example of a code refactor after adding getters/setters 
is changing the names of the fields like so:

```
class Rect2D {
     int _width;
     int _height;
```

or

```
class Rect2D {
     int width_;
     int height_;
```
Nov 18 2022
parent thebluepandabear <therealbluepandabear protonmail.com> writes:
If you only want to add setters:

```
class Rect2D {
     int _width;
     int _height;

     void width(int width) {
         writeln("SET");
         this._width = width;
     }

     void height(int height) {
         writeln("SET");
         this._height = height;
     }
}
```
Nov 18 2022
prev sibling next sibling parent reply []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 03:52:41 UTC, thebluepandabear 
wrote:
 On Saturday, 19 November 2022 at 03:39:18 UTC, []() {}() wrote:
 On Saturday, 19 November 2022 at 03:22:12 UTC, 
 thebluepandabear wrote:
 On Saturday, 19 November 2022 at 03:19:53 UTC, []() {}() 
 wrote:
 On Thursday, 17 November 2022 at 09:52:11 UTC, Dukc wrote:
 ..
 D has far less need for getters/setters than Java or C++. 
 The reason is [Uniform Function Call 
 Syntax](https://ddili.org/ders/d.en/ufcs.html). This means 
 that a member of a `struct` or `class` can start out as a 
 normal field and be later converted to getter/setter if 
 needed, without breaking calling code.
 ..
can you give an example please. i.e. before (class with public member) and after ( i.e. that public member converted to getter/setter).
Did you read the link provided? There's examples there...
it's say for member functions, not member variables. I read it, but I dont get the point was being made about how use ufcs to convert a public member variable of a class type into a getter and setter. Was there an example in the link that I missed?
It's actually kind of hard to wrap my head around. I will try to give you an example as to how you could convert a field into a getter/setter without breaking the interface between the user of the library, though it does require code refactoring on your end. Say you have the class Rect2D: ``` class Rect2D { int width; int height; } ``` The users of your class would use it like so: ``` Rect2D rect = new Rect2D(); rect.width = 5; rect.height = 5; ``` Say you want to write 'SET' now whenever someone sets a width/height value for the rect (as an example), and 'GET' when someone gets the width/height value for the rect, what you could do is do this: ``` class Rect2D { int rectWidth; int rectHeight; int width() { writeln("GET"); return rectWidth; } void width(int rectWidth) { writeln("SET"); this.rectWidth = rectWidth; } int height() { writeln("GET"); return rectHeight; } void height(int rectHeight) { writeln("SET"); this.rectHeight = rectHeight; } } ``` Honestly, it may not be a magic bullet, but still useful.
oh. so i get it now. you have to refactor your class (change member variable names and also do it in all places where they are used througout the class. then add new methods, overloading them in this way and that way, all because you're initial design never factored in the possibility of change (or even some validation of the vale being returned to the client, or validation of value coming from the client). after 10 years of doing all that, you may well come to the conclusion that public member variables are not such a great idea afterall ;-)
Nov 18 2022
next sibling parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
 oh. so i get it now. you have to refactor your class (change 
 member variable names and also do it in all places where they 
 are used througout the class. then add new methods, overloading 
 them in this way and that way, all because you're initial 
 design never factored in the possibility of change (or even 
 some validation of the vale being returned to the client, or 
 validation of value coming from the client).

 after 10 years of doing all that, you may well come to the 
 conclusion that public member variables are not such a great 
 idea afterall ;-)
These days with modern IDEs it takes a second to change the name of a variable globally. In production level code, it may take more time, but I doubt by a lot. Think about it, if you have a class with 20 different variables that don't need any special rules to access, think about the amount of code you would have to add for getters/setters. Now in production level code you will have thousands of these classes, and as such you will have a good chunk of code that is practically useless and doing nothing.
Nov 18 2022
next sibling parent thebluepandabear <therealbluepandabear protonmail.com> writes:
 classes, and as such you will have a good chunk of code that is 
 practically useless and doing nothing.
Meant *fields not variables, excuse my terminology.
Nov 18 2022
prev sibling parent reply []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 04:19:01 UTC, thebluepandabear 
wrote:
 oh. so i get it now. you have to refactor your class (change 
 member variable names and also do it in all places where they 
 are used througout the class. then add new methods, 
 overloading them in this way and that way, all because you're 
 initial design never factored in the possibility of change (or 
 even some validation of the vale being returned to the client, 
 or validation of value coming from the client).

 after 10 years of doing all that, you may well come to the 
 conclusion that public member variables are not such a great 
 idea afterall ;-)
These days with modern IDEs it takes a second to change the name of a variable globally. In production level code, it may take more time, but I doubt by a lot. Think about it, if you have a class with 20 different variables that don't need any special rules to access, think about the amount of code you would have to add for getters/setters. Now in production level code you will have thousands of these classes, and as such you will have a good chunk of code that is practically useless and doing nothing.
By making your class member variables public, it is not clear whether you forgot that you needed to validate incoming and outgoing values, or whether you don't need to do this (not ever). If you did it because of the former, you're fired ;-) If you did it because of the latter, you're also fired ;-)
Nov 18 2022
next sibling parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
On Saturday, 19 November 2022 at 04:27:14 UTC, []() {}() wrote:
 On Saturday, 19 November 2022 at 04:19:01 UTC, thebluepandabear 
 wrote:
 oh. so i get it now. you have to refactor your class (change 
 member variable names and also do it in all places where they 
 are used througout the class. then add new methods, 
 overloading them in this way and that way, all because you're 
 initial design never factored in the possibility of change 
 (or even some validation of the vale being returned to the 
 client, or validation of value coming from the client).

 after 10 years of doing all that, you may well come to the 
 conclusion that public member variables are not such a great 
 idea afterall ;-)
These days with modern IDEs it takes a second to change the name of a variable globally. In production level code, it may take more time, but I doubt by a lot. Think about it, if you have a class with 20 different variables that don't need any special rules to access, think about the amount of code you would have to add for getters/setters. Now in production level code you will have thousands of these classes, and as such you will have a good chunk of code that is practically useless and doing nothing.
By making your class member variables public, it is not clear whether you forgot that you needed to validate incoming and outgoing values, or whether you don't need to do this (not ever). If you did it because of the former, you're fired ;-) If you did it because of the latter, you're also fired ;-)
Thankfully I only code in D as a hobby, so I don't need to use getters/setters! Thanks.
Nov 18 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 04:37:51 UTC, thebluepandabear 
wrote:
 Thankfully I only code in D as a hobby, so I don't need to use 
 getters/setters! Thanks.
well, in that case, you can throw out everything that programmers have learnt over many decades, and just to whatever you want in your code. But if you ever want to have users of your TUI Library, or want to have other developers contribute to it, you will want to follow reasonable guidelines. easily apply to D): https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms229042(v=vs.100)
Nov 18 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
 https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms229042(v=vs.100)
Thanks, I'll think about it more -- I am a noob so I may be wrong in what I am saying. just do `{ get; set; }`, and I really wish D had something similar 😂
Nov 18 2022
next sibling parent reply []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 04:47:57 UTC, thebluepandabear 
wrote:
 https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms229042(v=vs.100)
Thanks, I'll think about it more -- I am a noob so I may be wrong in what I am saying. just do `{ get; set; }`, and I really wish D had something similar 😂
It does. private int myVariable; public Get_myVariable(){} public Set_myVariable(){} those public Get/Set members functions are exactly what you get saving you the keystokes.. but the end code is just as if you had typed them out yourself.
Nov 18 2022
parent thebluepandabear <therealbluepandabear protonmail.com> writes:
On Saturday, 19 November 2022 at 05:42:03 UTC, []() {}() wrote:
 those public Get/Set members functions are exactly what you get 

 saving you the keystokes.. but the end code is just as if you 
 had typed them out yourself.
I know...
Nov 18 2022
prev sibling parent reply []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 04:47:57 UTC, thebluepandabear 
wrote:
 ..

 just do `{ get; set; }`, and I really wish D had something 
 similar 😂
If you used such, you would still need to completely refactor your class when you decided to implement you business rules (within the getter/setter), since you cannot do anything more than get and set with auto property. Once you refactor your class (creating actual private member variables and creating getter/setter methods, you are almost certainly going to break binary compatability, and when you send your update compiler library to your customer, there code will stop working - cause they'll have to recompile it against the new library. All this because some programmer wanted to save a few key strokes, or did not anticipate change, or did not anticipate the need to ensure data is valid before assigning it, or returning it. So no. It's not overkill. It's called software engineering.
Nov 19 2022
next sibling parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
I respectfully disagree... It is not just a couple of keystrokes 
but rather thousands of lines that can be saved.

Let's just agree to disagree.
Nov 19 2022
parent reply []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 09:14:33 UTC, thebluepandabear 
wrote:
 I respectfully disagree... It is not just a couple of 
 keystrokes but rather thousands of lines that can be saved.

 Let's just agree to disagree.
Well, as I've already stated.. do it your way for the next 10 years, and I bet you will eventually come to a different point of view ;-) if you're just a hobyist programmer, then you're really free to do as you please. but if you are a software engineer employed by a company, within a team of other software engineers, then you have to a have framework that you *all* work against. anyone who says otherwise, doesn't know what they're talking about. In my team, 'classes' do not have public member variables. not ever. another team is free to do as it pleases of course ;-) but members of that team will have a hard time getting into my team.
Nov 19 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/19/22 01:43, [] () {} () wrote:

 do it your way for the next 10 years, and
 I bet you will eventually come to a different point of view ;-)
Hm... I am responding without reading the rest of the thread so I don't know whether you've mentioned the 10 years more but here it goes: I hope 11 years will be sufficient to stop following guidelines blindly. Especially this specific one where a posted video has shown how wasteful it can be.
 if you're just a hobyist programmer, then you're really free to do as
 you please.
I am a professional programmer and I do not write public accessors blindly. As stated before, they are written only when there is an invariant to protect.
 but if you are a software engineer employed by a company, within a team
 of other software engineers, then you have to a have framework that you
 *all* work against.
Agreed.
 anyone who says otherwise, doesn't know what they're talking about.
Agreed.
 In my team, 'classes' do not have public member variables. not ever.
I am not working there! :) And what about structs? ;)
 another team is free to do as it pleases of course ;-)
Thanks. :)
 but members of that team will have a hard time getting into my team.
Mutual feelings there... Ali
Nov 19 2022
next sibling parent [] () {} () <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 19:59:20 UTC, Ali Çehreli wrote:
 ..
 ...
 Ali
The 10 years was mentioned, because it was what I learnt over that period (well, long before that actually). It wasn't mentioned to demonstrate that I have some superior knowledge. Object data needs to be protected. It often needs its 'invariants' altered. There are far more reasons for inserting getters/setters and design stage, than leaving them out at design stage, in order to save some keystrokes, or code bloat. How often do you design your class? How often to users use your class, and ask for changes? Better to anticipate change - the cost of that is much smaller at design time. If you learnt something different over your 30+ years, good for you, and your team, and your customers. But in my experience, public member variables rarely make sense in a 'class' type, and I'd put protected in the same principle. This is not a hard and fast rule. But it makes sense in most cases. Perhaps you can direct me to a software engineering *team* that builds *class* library's for a living, and that also use public member variables in their classes. Perhaps they can teach me something I do not know. I'm happy to learn more. Your post was mainly about struct types?? This thread is about the relevance of getters/setters in a 'class' type. btw. If you can get away with using public member variables, you likely don't need a class type.
Nov 19 2022
prev sibling parent [] () {} () <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 19:59:20 UTC, Ali Çehreli wrote:
 On 11/19/22 01:43, [] () {} () wrote:

 do it your way for the next 10 years, and
 I bet you will eventually come to a different point of view
;-) Hm... I am responding without reading the rest of the thread so I don't know whether you've mentioned the 10 years more but here it goes: I hope 11 years will be sufficient to stop following guidelines blindly. Especially this specific one where a posted video has shown how wasteful it can be.
You mention your 30+ years of programming, but at the same time, point out how 'correct' that one-sided rant is in that video. I'm confused ;-)
Nov 19 2022
prev sibling next sibling parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Saturday, 19 November 2022 at 09:05:42 UTC, []() {}() wrote:
 Once you refactor your class (creating actual private member 
 variables and creating getter/setter methods, you are almost 
 certainly going to break binary compatability, and when you 
 send your update compiler library to your customer, there code 
 will stop working - cause they'll have to recompile it against 
 the new library.
I think you are speaking about shipping dynamic library to users. I think compiler authors can clarify whether introducing getters/setters breaks ABI or not. On the other side if it breaks then it can be easily checked: create simple program that uses dynamic library, then change the latter to use getters/setters and run program again without recompiling.
Nov 19 2022
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/19/22 01:05, [] () {} () wrote:

 All this because some programmer wanted to save a few key strokes, or
 did not anticipate change, or did not anticipate the need to ensure data
 is valid before assigning it, or returning it.

 So no. It's not overkill. It's called software engineering.
I disagree. Engineering is about applying different solutions to different problems. Blindly following guidelines whether it is fit for purpose would be dogmatic, not pragmatic. Ali
Nov 19 2022
parent [] () {} () <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 19:54:59 UTC, Ali Çehreli wrote:
 On 11/19/22 01:05, [] () {} () wrote:

 All this because some programmer wanted to save a few key
strokes, or
 did not anticipate change, or did not anticipate the need to
ensure data
 is valid before assigning it, or returning it.

 So no. It's not overkill. It's called software engineering.
I disagree. Engineering is about applying different solutions to different problems. Blindly following guidelines whether it is fit for purpose would be dogmatic, not pragmatic. Ali
Neither I, nor anyone in my team blindly follows anything, or anyone ;-) What goes on inside an object, is the responsibilty of that object. That's a guideline (i.e. encapsulation) that we accept as being an important principle in software *engineering*, for us, and for all of the reasons I've mentioned, and so we implement and follow it. Not having that encapsulation would (and has) create major problems for us, and our customers. Again, if you and/or your team have discovered something different (i.e. encapsulation is not that important afterall), then that's great, for you. But it wouldn't be great for us, or our customers, that much I do know.
Nov 19 2022
prev sibling parent Sergey <kornburn yandex.ru> writes:
On Saturday, 19 November 2022 at 04:27:14 UTC, []() {}() wrote:
 By making your class member variables public, it is not clear 
 whether you forgot that you needed to validate incoming and 
 outgoing values, or whether you don't need to do this (not 
 ever).

 If you did it because of the former, you're fired ;-)

 If you did it because of the latter, you're also fired ;-)
Functional programming developers be like: "meh" :)
Nov 19 2022
prev sibling next sibling parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Saturday, 19 November 2022 at 04:13:33 UTC, []() {}() wrote:
 oh. so i get it now. you have to refactor your class (change 
 member variable names and also do it in all places where they 
 are used througout the class. then add new methods, overloading 
 them in this way and that way, all because you're initial 
 design never factored in the possibility of change (or even 
 some validation of the vale being returned to the client, or 
 validation of value coming from the client).
You are not required to rename everything, just actual members. D has nice feature to convert `foo.bar` to `foo.bar()` and `foo.bar = value` to `foo.bar(value)` that doesn't exist in C/C++ for example. This reduces some headache in planning the API ahead. Let's we have this class and its usage: ```d class Rect2D { int width; int height; auto area() const { return width * height; } } Rect2D rect = new Rect2D(); rect.width = 5; rect.height = 5; writeln(rect.area); // note that this is seamlessly translated to rect.area() ``` Then you decided that you want getters/setters so you add them without changing anything: ```d class Rect2D { int width_; int height_; auto width() const { return width_; } void width(int w) { width_ = w; } auto height() const { return height_; } void height(int h) { height_ = h; } auto area() const { return width * height; } // no changes here - using getters } Rect2D rect = new Rect2D(); rect.width = 5; // no changes here - using setter rect.height = 5; // no changes here - using setter writeln(rect.area); ``` You can also use UFCS instead of class members but it has a caveat: plain `width`/`height` won't work within class so you have to either use `width_`/`height_` directly or `this.width`/`this.height`: ```d class Rect2D { int width_; int height_; auto area() const { return this.width * this.height; } // UFCS calls to global width() and height() functions } // These functions have to be in global scope for UFCS to work auto width(const Rect2D rect) { return rect.width_; } void width(ref Rect2D rect, int w) { rect.width_ = w; } auto height(const Rect2D rect) { return rect.height_; } void height(ref Rect2D rect, int h) { rect.height_ = h; } void main() { // Still no changes in user code Rect2D rect = new Rect2D(); rect.width = 5; rect.height = 5; writeln(rect.area); } ```
Nov 19 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
That's the point many people have given here which is not 
convincing him, even though it is quite great.

I think we all know the answer here 😂
Nov 19 2022
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Saturday, 19 November 2022 at 09:12:26 UTC, thebluepandabear 
wrote:
 That's the point many people have given here which is not 
 convincing him, even though it is quite great.

 I think we all know the answer here 😂
IMHO you are both right :) You are speaking about API compatibility, `[]() {}()` speaks about ABI compatibility. The latter makes sense in long-running production software. So we know that there are no issues in API compatibility but we don't know anything about ABI.
Nov 19 2022
next sibling parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
On Saturday, 19 November 2022 at 09:26:49 UTC, Andrey Zherikov 
wrote:
 On Saturday, 19 November 2022 at 09:12:26 UTC, thebluepandabear 
 wrote:
 That's the point many people have given here which is not 
 convincing him, even though it is quite great.

 I think we all know the answer here 😂
IMHO you are both right :) You are speaking about API compatibility, `[]() {}()` speaks about ABI compatibility. The latter makes sense in long-running production software. So we know that there are no issues in API compatibility but we don't know anything about ABI.
I am too dumb to know what ABI is,does anyone who is more experienced have any info on whether or not this is actually a problem in D?
Nov 19 2022
next sibling parent Dukc <ajieskola gmail.com> writes:
On Saturday, 19 November 2022 at 09:49:18 UTC, thebluepandabear 
wrote:
 On Saturday, 19 November 2022 at 09:26:49 UTC, Andrey Zherikov 
 wrote:
 On Saturday, 19 November 2022 at 09:12:26 UTC, 
 thebluepandabear wrote:
 That's the point many people have given here which is not 
 convincing him, even though it is quite great.

 I think we all know the answer here 😂
IMHO you are both right :) You are speaking about API compatibility, `[]() {}()` speaks about ABI compatibility. The latter makes sense in long-running production software. So we know that there are no issues in API compatibility but we don't know anything about ABI.
I am too dumb to know what ABI is
ABI is short for application binary interface. Where API means how you use another module in source code, ABI means how you would use that module in assembly langauge or machine code. If two versions of a library have the same ABI, the program using the library does not have to be recompiled, only relinked to the new library (which happens at runtime if it's a dynamically linked library). It tends to be of less importance in D than in C or C++. First, D modules usually compile quickly enough that premade binaries (which would be hard to keep up to date with the source code headers) don't make sense. Second, DUB standardises the build process so binaries aren't needed for user convenience either. Maybe the most important remaining use case is building a library that can be used from other languages.
Nov 19 2022
prev sibling parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Saturday, 19 November 2022 at 09:49:18 UTC, thebluepandabear 
wrote:
 I am too dumb to know what ABI is
https://en.wikipedia.org/wiki/Application_binary_interface
Nov 19 2022
prev sibling next sibling parent reply []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 09:26:49 UTC, Andrey Zherikov 
wrote:
 On Saturday, 19 November 2022 at 09:12:26 UTC, thebluepandabear 
 wrote:
 That's the point many people have given here which is not 
 convincing him, even though it is quite great.

 I think we all know the answer here 😂
IMHO you are both right :) You are speaking about API compatibility, `[]() {}()` speaks about ABI compatibility. The latter makes sense in long-running production software. So we know that there are no issues in API compatibility but we don't know anything about ABI.
team. I expect it would also break ABI in D. so again, getters/setters will almost certainly have value, even if you initially see no value in the few extra keystrokes needed to implement them. the alternative case being presented is to just make class member variables public so clients can set/get them directly .... well... good luck with that. that's the end of my input on this thread.
Nov 19 2022
next sibling parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Saturday, 19 November 2022 at 09:51:09 UTC, []() {}() wrote:

 team.
Every company works differently. Yours are using .net and (I guess) ships dlls so you must care about ABI with existing software. In my company we use static linking so the only ABI compatibility we care about is with libc.
 I expect it would also break ABI in D.
I'd like to know the answer so I hope someone from D core step in and shed a light on it.
Nov 19 2022
prev sibling parent reply []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 09:51:09 UTC, []() {}() wrote:
 ...

 team.
of course that's not the reason we don't use public member variables in classes. the reason we don't use them, is because (1) we always anticpiate change including the need to implement (and change) business rules associated with the objects data (using setter/getters), and (2) we always prioritise the stability of the public interface of a class at the time of design. if neither of those are your concern, in production-level code, I'd be really surprised (and shocked).
Nov 19 2022
parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Saturday, 19 November 2022 at 10:17:19 UTC, []() {}() wrote:
 On Saturday, 19 November 2022 at 09:51:09 UTC, []() {}() wrote:
 ...

 team.
of course that's not the reason we don't use public member variables in classes. the reason we don't use them, is because (1) we always anticpiate change including the need to implement (and change) business rules associated with the objects data (using setter/getters), and (2) we always prioritise the stability of the public interface of a class at the time of design. if neither of those are your concern, in production-level code, I'd be really surprised (and shocked).
We don't use public members either in most cases - we use them in simple structs. We have teams that do care and prioritize stability of public interface because they ship their libraries to end-users. Other teams care much less because all their users are internal so they can fix whatever they break. Regarding ABI compatibility: it's usually driven by what dependencies your software has. In your case (as far as I got) you ship .dll that is used by already deployed software so your library must be ABI compatible with it. In our case, our software has only system-level dependencies like C runtime, WinSocks so we don't have such a thing as ABI incompatibility between different parts of our software but we care about system-level ABI.
Nov 19 2022
prev sibling parent Dukc <ajieskola gmail.com> writes:
On Saturday, 19 November 2022 at 09:26:49 UTC, Andrey Zherikov 
wrote:
 On Saturday, 19 November 2022 at 09:12:26 UTC, thebluepandabear 
 wrote:
 That's the point many people have given here which is not 
 convincing him, even though it is quite great.

 I think we all know the answer here 😂
IMHO you are both right :) You are speaking about API compatibility, `[]() {}()` speaks about ABI compatibility. The latter makes sense in long-running production software. So we know that there are no issues in API compatibility but we don't know anything about ABI.
Yes, this is a good summary. Redefining a raw field as a getter/setter pair keeps the API but breaks the ABI, so in some cases conservative getters/setters can be justified. Another problem with raw fields: ```D struct S{int field;} safe clientCode() { auto s = new S(); doSomething(&s.field); } ``` This will break if S is rewritten as ```D struct S { int field_; auto field(){return field_;} auto field(int val){return field_ = val;} } ``` I though at first that breakage could still be avoided by instead writing ```D struct S { int field_; ref field(){return field_;} } ``` ...but I tested and actually it does not work because in this case `&s.field` takes the address of the getter function, not the field. Now, despite all this I don't think it'd be a good idea to write everything to getters/setters just in case. The binary interface issue is frankly secondary: most structs and classes are just compiled along with their client code. And even separately compiled libraries only have to do this if they strive to provide a stable ABI between releases, which is not nearly always the case. Nor needs to be. But still the pointer problem in the above example stands, so conservative getters/setters are justified in an API that's used widely enough. But probably not for something internal to a ten thousand line long package.
Nov 19 2022
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/18/22 20:13, [] () {} () wrote:

 after 10 years of doing all that, you may well come to the conclusion
 that public member variables are not such a great idea afterall ;-)
It depends. Majority of my structs are pure data. When there is no invariant to protect, then there is no reason to write any accessor. If 10 years is mentioned to prove a point, I currently have 33 years of professional programming experience (37 including pure hobby years), so I must be right. ;) Ali
Nov 19 2022
prev sibling next sibling parent []() {}() <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 03:52:41 UTC, thebluepandabear 
wrote:
 ...
 .....
 Honestly, it may not be a magic bullet, but still useful.
This refactoring may be source compatible, but would it be binary compatible? i.e. you refactor your class, compile it as an updated version of your library, then ship that updated library to your users.... will they then need to recompile their own code because of the refactoring you did? As for D, I do not know (and I don't expect you to either ;-)
Nov 18 2022
prev sibling parent Dukc <ajieskola gmail.com> writes:
On Saturday, 19 November 2022 at 03:52:41 UTC, thebluepandabear 
wrote:
 Say you want to write 'SET' now whenever someone sets a 
 width/height value for the rect (as an example), and 'GET' when 
 someone gets the width/height value for the rect, what you 
 could do is do this:

 ```
 class Rect2D {
     int rectWidth;
     int rectHeight;

     int width() {
         writeln("GET");
         return rectWidth;
     }

     void width(int rectWidth) {
         writeln("SET");
         this.rectWidth = rectWidth;
     }

     int height() {
         writeln("GET");
         return rectHeight;
     }

     void height(int rectHeight) {
         writeln("SET");
         this.rectHeight = rectHeight;
     }
 }
 ```

 Honestly, it may not be a magic bullet, but still useful.
Yes, this is what I meant. I did use the UFCS name inaccurately: I believe UFCS means the ability to write `y.x(z)` in place of `x(y, z)`, and maybe the ability to write `y.x = z` in place of `y.x(z)`, but it does not mean the ability to omit empty parenthesis in a function call. The latter is what enables getters that don't break the API.
Nov 19 2022
prev sibling next sibling parent reply [] () {} () <SilentLambda gmail.com> writes:
On Thursday, 17 November 2022 at 04:39:35 UTC, thebluepandabear 
wrote:
 ...
 I am debating whether or not I should add getter methods to 
 these properties. On one hand, it will inflate the codebase by 
 a lot, on the other hand -- in other languages like Java it is 
 a good practice:
You really should, instead, be debating why your class has public member variables. If you come to the conclusion that those member variables are completely ok being public, then making them private and thus needing to provide a simple getter/setter for getting/setting the raw value, well, that is just equivalent to making them public anyway, really. So have you achieved nothing with that refactoring? Well, only time (and 100's of users) will tell ;-) Do I really need a fence around my house... well.. only time will tell. I'm inclined to build the fence anyway. Though it would be great if didn't need fences.
Nov 19 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
On Saturday, 19 November 2022 at 22:57:36 UTC, [] () {} () wrote:
 On Thursday, 17 November 2022 at 04:39:35 UTC, thebluepandabear 
 wrote:
 ...
 I am debating whether or not I should add getter methods to 
 these properties. On one hand, it will inflate the codebase by 
 a lot, on the other hand -- in other languages like Java it is 
 a good practice:
You really should, instead, be debating why your class has public member variables. If you come to the conclusion that those member variables are completely ok being public, then making them private and thus needing to provide a simple getter/setter for getting/setting the raw value, well, that is just equivalent to making them public anyway, really. So have you achieved nothing with that refactoring? Well, only time (and 100's of users) will tell ;-) Do I really need a fence around my house... well.. only time will tell. I'm inclined to build the fence anyway. Though it would be great if didn't need fences.
Ok... thank you.
Nov 19 2022
parent [] () {} () <SilentLambda gmail.com> writes:
On Saturday, 19 November 2022 at 23:05:30 UTC, thebluepandabear 
wrote:
..
btw. Although this thread has well and truly exhausted it usefulness, the question you posed primarly relates to encapsulation, and as such, I think Scott Myers provided a reasonable answer to your question - more than 2 decades ago: "Encapsulation is a means, not an end. There's nothing inherently desirable about encapsulation. Encapsulation is useful only because it yields other things in our software that we care about. In particular, it yields flexibility and robustness." https://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsuhttps://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197
Nov 19 2022
prev sibling next sibling parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Thursday, 17 November 2022 at 04:39:35 UTC, thebluepandabear 
wrote:
 I am creating a TUI library and I have a class with the 
 following constant fields:

 ```
 class Label : Renderable {
     const string text;
     const TextAlignment textAlignment;
     const Color color;

     this(Dimensions dimensions, string text, TextAlignment 
 textAlignment, Color color) {
         this.dimensions = dimensions;
         this(text, textAlignment, color);
     }

     this(string text, TextAlignment textAlignment, Color color) 
 {
         this.text = text;
         this.textAlignment = textAlignment;
         this.color = color;
     }

     override Cell[] render() const {
         Cell[] cells;

         for (int x = 0; x < 0 + text.length; ++x) {
             cells ~= Cell(Coordinates(x, 0), text[x], color);
         }

         return cells;
     }
 }
 ```

 I am debating whether or not I should add getter methods to 
 these properties. On one hand, it will inflate the codebase by 
 a lot, on the other hand -- in other languages like Java it is 
 a good practice:

 ```
 class Label : Renderable {
     private const string text;
     private const TextAlignment textAlignment;
     private const Color color;

     this(Dimensions dimensions, string text, TextAlignment 
 textAlignment, Color color) {
         this.dimensions = dimensions;
         this(text, textAlignment, color);
     }

     this(string text, TextAlignment textAlignment, Color color) 
 {
         this.text = text;
         this.textAlignment = textAlignment;
         this.color = color;
     }

     string getText() const {
         return text;
     }

     TextAlignment getTextAlignment() const {
         return textAlignment;
     }

     Color getColor() const {
         return color;
     }

     override Cell[] render() const {
         Cell[] cells;

         for (int x = 0; x < 0 + text.length; ++x) {
             cells ~= Cell(Coordinates(x, 0), text[x], color);
         }

         return cells;
     }
 }
 ```

 It's not a lot of code that has been added but if you have a 
 class with say 10 different fields, adding getter methods would 
 definitely increase the code size by a lot, so what are you 
 guys thoughts on this?
Dunno if someone mentioned, but you can minimize use of boilerplate by hiding it into mixin templates. Say you have: ```D mixin template Property(T) { private T subject_; T Property() { return subject_; } void Property(T value) { subject_ = value; } } ``` The you can use it in your class to define properties of class: ```D class MyMegaPropertyClass { mixin Property!(string) myFancyProperty; } auto c = new MyMegaPropertyClass() c.myFancyProperty = "indeed" ``` The only issue is that, by using eponymous naming you also block any access of underlying subject_ or any other miscellaneous info that you may add. Best regards, Alexandru.
Nov 21 2022
next sibling parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Monday, 21 November 2022 at 11:20:31 UTC, Alexandru Ermicioi 
wrote:
 On Thursday, 17 November 2022 at 04:39:35 UTC, thebluepandabear 
 wrote:
 [...]
Dunno if someone mentioned, but you can minimize use of boilerplate by hiding it into mixin templates. Say you have: ```D mixin template Property(T) { private T subject_; T Property() { return subject_; } void Property(T value) { subject_ = value; } } ``` The you can use it in your class to define properties of class: ```D class MyMegaPropertyClass { mixin Property!(string) myFancyProperty; } auto c = new MyMegaPropertyClass() c.myFancyProperty = "indeed" ``` The only issue is that, by using eponymous naming you also block any access of underlying subject_ or any other miscellaneous info that you may add. Best regards, Alexandru.
You can use mixin templates to also define contlstructors, or any other boilerplate that is buildable using meta programming capabilities in D. It would be awesome to have smth like Lombok from java but in D using mixin templates. Best regards, Alexandru
Nov 21 2022
prev sibling parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
 Best regards,
 Alexandru.
Thanks but I haven't reached that yet.
Nov 21 2022
parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Monday, 21 November 2022 at 11:34:50 UTC, thebluepandabear 
wrote:
 Best regards,
 Alexandru.
Thanks but I haven't reached that yet.
Well, I wish you'll reach as soon as possible :)
Nov 21 2022
prev sibling next sibling parent FeepingCreature <feepingcreature gmail.com> writes:
On Thursday, 17 November 2022 at 04:39:35 UTC, thebluepandabear 
wrote:
 I am creating a TUI library and I have a class with the 
 following constant fields:

 ```
 class Label : Renderable {
     const string text;
     const TextAlignment textAlignment;
     const Color color;

     this(Dimensions dimensions, string text, TextAlignment 
 textAlignment, Color color) {
         this.dimensions = dimensions;
         this(text, textAlignment, color);
     }

     this(string text, TextAlignment textAlignment, Color color) 
 {
         this.text = text;
         this.textAlignment = textAlignment;
         this.color = color;
     }

     override Cell[] render() const {
         Cell[] cells;

         for (int x = 0; x < 0 + text.length; ++x) {
             cells ~= Cell(Coordinates(x, 0), text[x], color);
         }

         return cells;
     }
 }
 ```

 I am debating whether or not I should add getter methods to 
 these properties. On one hand, it will inflate the codebase by 
 a lot, on the other hand -- in other languages like Java it is 
 a good practice:

 ```
 class Label : Renderable {
     private const string text;
     private const TextAlignment textAlignment;
     private const Color color;

     this(Dimensions dimensions, string text, TextAlignment 
 textAlignment, Color color) {
         this.dimensions = dimensions;
         this(text, textAlignment, color);
     }

     this(string text, TextAlignment textAlignment, Color color) 
 {
         this.text = text;
         this.textAlignment = textAlignment;
         this.color = color;
     }

     string getText() const {
         return text;
     }

     TextAlignment getTextAlignment() const {
         return textAlignment;
     }

     Color getColor() const {
         return color;
     }

     override Cell[] render() const {
         Cell[] cells;

         for (int x = 0; x < 0 + text.length; ++x) {
             cells ~= Cell(Coordinates(x, 0), text[x], color);
         }

         return cells;
     }
 }
 ```

 It's not a lot of code that has been added but if you have a 
 class with say 10 different fields, adding getter methods would 
 definitely increase the code size by a lot, so what are you 
 guys thoughts on this?
Obligatory note that boilerplate https://code.dlang.org/packages/boilerplate exists for just this reason: class Label : Renderable { ConstRead private const string text_; ConstRead private const TextAlignment textAlignment_; ConstRead private const Color color_; this(Dimensions dimensions, string text, TextAlignment textAlignment, Color color) { this.dimensions_ = dimensions; this(text, textAlignment, color); } override Cell[] render() const { Cell[] cells; for (int x = 0; x < 0 + text.length; ++x) { cells ~= Cell(Coordinates(x, 0), text[x], color); } return cells; } mixin(GenerateFieldAccessors); mixin(GenerateThis); }
Nov 21 2022
prev sibling parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Thursday, 17 November 2022 at 04:39:35 UTC, thebluepandabear 
wrote:
 I am creating a TUI library and I have a class with the 
 following constant fields:

 ```
 class Label : Renderable {
     const string text;
     const TextAlignment textAlignment;
     const Color color;

     this(Dimensions dimensions, string text, TextAlignment 
 textAlignment, Color color) {
         this.dimensions = dimensions;
         this(text, textAlignment, color);
     }

     this(string text, TextAlignment textAlignment, Color color) 
 {
         this.text = text;
         this.textAlignment = textAlignment;
         this.color = color;
     }

     override Cell[] render() const {
         Cell[] cells;

         for (int x = 0; x < 0 + text.length; ++x) {
             cells ~= Cell(Coordinates(x, 0), text[x], color);
         }

         return cells;
     }
 }
 ```

 I am debating whether or not I should add getter methods to 
 these properties. On one hand, it will inflate the codebase by 
 a lot, on the other hand -- in other languages like Java it is 
 a good practice:

 ```
 class Label : Renderable {
     private const string text;
     private const TextAlignment textAlignment;
     private const Color color;

     this(Dimensions dimensions, string text, TextAlignment 
 textAlignment, Color color) {
         this.dimensions = dimensions;
         this(text, textAlignment, color);
     }

     this(string text, TextAlignment textAlignment, Color color) 
 {
         this.text = text;
         this.textAlignment = textAlignment;
         this.color = color;
     }

     string getText() const {
         return text;
     }

     TextAlignment getTextAlignment() const {
         return textAlignment;
     }

     Color getColor() const {
         return color;
     }

     override Cell[] render() const {
         Cell[] cells;

         for (int x = 0; x < 0 + text.length; ++x) {
             cells ~= Cell(Coordinates(x, 0), text[x], color);
         }

         return cells;
     }
 }
 ```

 It's not a lot of code that has been added but if you have a 
 class with say 10 different fields, adding getter methods would 
 definitely increase the code size by a lot, so what are you 
 guys thoughts on this?
Little optimization, you could prefill your cells instead of creating a new dynamic array every frames not good for the gc ```D class Label : Renderable { private const string text; private const TextAlignment textAlignment; private const Color color; private const Cell[] cells; this(Dimensions dimensions, string text, TextAlignment textAlignment, Color color) { this.dimensions = dimensions; this(text, textAlignment, color); } this(string text, TextAlignment textAlignment, Color color) { this.text = text; this.cells.length = test.length; this.textAlignment = textAlignment; this.color = color; // fill cells here for (int x = 0; x < text.length; x++) this.cells[x] = Cell(Coordinates(x, 0), text[x], color); } string getText() const { return text; } TextAlignment getTextAlignment() const { return textAlignment; } Color getColor() const { return color; } override Cell[] render() const { return cells; } } ``` As for the get/set, i almost never use `private`, and i never use getter/setter to just access variables, it's pointless imo Unless you expect your users to extend/override your types, then it make sense, but i personally prefer composition, as i'm not a fan of OOP
Nov 23 2022
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
On Wednesday, 23 November 2022 at 13:52:18 UTC, ryuukk_ wrote:
 On Thursday, 17 November 2022 at 04:39:35 UTC, thebluepandabear 
 wrote:
 I am creating a TUI library and I have a class with the 
 following constant fields:

 ```
 class Label : Renderable {
     const string text;
     const TextAlignment textAlignment;
As for the get/set, i almost never use `private`, and i never use getter/setter to just access variables, it's pointless imo Unless you expect your users to extend/override your types, then it make sense, but i personally prefer composition, as i'm not a fan of OOP
Thanks for the input, I've modified the code since then so that `private` isn't used, etc.
Nov 23 2022
parent thebluepandabear <therealbluepandabear protonmail.com> writes:
've modified the code since then so that
 `private` isn't used, etc.
Also thanks for that code improvement that you did, quite nice.
Nov 23 2022