Discussion on using module-scoped variables (was 'with' bug?)

Chris Cain clcain at uncg.edu
Tue Nov 6 12:12:32 PST 2012


On Tuesday, 6 November 2012 at 15:34:41 UTC, Faux Amis wrote:
> I would have loved an answer to this:
>
> Is there any reason to encapsulate this kind of code in a 
> struct?
> ---
> module a;
>
> private int _a;
>
> int a(){
>   return _a;
> }
>
> void a(int aIn){
>   _a = aIn;
> }
>
> void useA(){
> }
> ---
> module main;
>
> static import a;
>
> void main(){
>   a.useA();
> }
> ---
>
> What I am trying to get answered here is whether there is 
> something special about a struct or a class which makes it a 
> 'correct' data encapsulator where a module does not.

So
---
module a;

private int _a;

int a(){
    return _a;
}

void a(int aIn){
    _a = aIn;
}

void useA(){
}
// and more using the shared state _a?
---

vs.

---
module a;

struct S {
     private int _a;
     void a(int aIn) {
        _a = aIn;
     }
     void a() { return _a; }

     void doSLikeThings() {
         // uses A
     }
}
// and more in the module using the shared state of S which
encapsulates _a?
---
?

Well, let's start off with the way that I think about using
modules. They represent a logical grouping of many concepts and
ideas. If you have a "compression module", it would probably hold
functions, structures, and classes which are used in compression.

If you want to create a struct, it needs to represent some
singular concept or idea that will encapsulate the data "a" (and
presumably more data: "b","c","d" ...etc). If you can do that
(and you usually can) then it certainly makes sense to
encapsulate it in a struct (or a class, especially it is a
concept that benefits from inheritance or if you want reference
semantics by default).

And you should avoid using module-level encapsulation of data for
the reasons stated in previous posts.

If you are trying to share some data, then it would be better to
explicitly share it among the parts of your module:
---
module a;
struct S {
      // common information
      int a, b, c, d;

      // methods/functions which help the information stay
consistent
}
struct T {
      S* s;
      // Maybe some other information

      // uses data from the shared s
}
struct U {
      // Some methods use S* (or ref S) as arguments, but not all.
}
struct V {
      // Doesn't need S for anything
}
struct W {
      T* t;
      // Uses shared state of s indirectly via shared state of t
}

void fun(ref S s, ref V v) pure {
      // does things with s and v which is reflected to anyone
using this particular s or v
}
---

The alternative, implicitly sharing information using
module-scoped variables, has the advantage of being somewhat less
to type (after all, you wouldn't pass in the information via
args). However, as I showed before, it has several disadvantages
that make it significantly less compelling.

Does that answer your question? I'm not sure how else to answer
"whether there is something special about a struct or a class
which makes it a 'correct' data encapsulator where a module does
not" other than by showing how module-scoped data is bad (which
is what previous posts have covered the most) and how you could
alternatively use structs (which is what this post is trying to
cover).

... I looked over what you said, and I'm more curious as to what
you might be using modules for. It seems to me like you're using
modules similar to a singleton. Would this be correct? Or am I
missing something?


More information about the Digitalmars-d mailing list