Time to destroy Walter: breaking modules into packages

TommiT tommitissari at hotmail.com
Wed Jun 19 02:55:30 PDT 2013


On Wednesday, 19 June 2013 at 07:12:30 UTC, Jonathan M Davis 
wrote:
> On Wednesday, June 19, 2013 08:51:38 TommiT wrote:
>> I can't put a member function into a different file if it's
>> supposed to have access to private data of its enclosing
>> class/struct.
>
> Then you can put the class in a different file. But even if
> you can't, I don't think that it's worth it to complicate the
> package attribute any further.

Let's now assume that we change the language specification so 
that 'package' access specifier allows access also to modules in 
nested packages. I'll show how difficult it can be to refactor 
your code in order to break it up into a package:

The file structure:
-------------------
/my_lib/mod_x.d
/my_lib/mod_y.d


File: /my_lib/mod_x.d
----------------------
module my_lib.mod_x;

import my_lib.mod_y;

void fun()
{
     my_lib.mod_y.S1 s1;
     s1.detail();
}


File: /my_lib/mod_y.d
----------------------
module my_lib.mod_y;

struct S1
{
     public void api()
     {
         S2 s2;
         s2.detail();
     }

     package void detail() { }
}

struct S2
{
     public void api() { }

     package void detail() { }
}

################################################################
Now, I want to break up both mod_x.d and mod_y.d into packages. 
I'll start by doing it naively and end up with this:

The file structure:
-------------------
/my_lib/mod_x/submod.d
/my_lib/mod_x/package.d
/my_lib/mod_y/submod_s1.d
/my_lib/mod_y/submod_s2.d
/my_lib/mod_y/package.d


File: /my_lib/mod_x/submod.d
-----------------------------
module my_lib.mod_x.submod;

import my_lib.mod_y;

void fun()
{
     my_lib.mod_y.S1 s1;
     s1.detail();
}


File: /my_lib/mod_x/package.d
------------------------------
module my_lib.mod_x;

public import my_lib.mod_x.submod;


File: /my_lib/mod_y/submod_s1.d
--------------------------------
module my_lib.mod_y.submod_s1;

import my_lib.mod_y.submod_s2;

struct S1
{
     public void api()
     {
         S2 s2;
         s2.detail();
     }

     package void detail() { }
}


File: /my_lib/mod_y/submod_s2.d
--------------------------------
module my_lib.mod_y.submod_s2;

struct S2
{
     public void api() { }

     package void detail() { }
}


File: /my_lib/mod_y/package.d
------------------------------
module my_lib.mod_y;

public import my_lib.mod_y.submod_s1;
public import my_lib.mod_y.submod_s2;

################################################################
At this point I notice this doesn't work because 
my_lib.mod_x.submod.fun tries to call my_lib.mod_y.S1.detail 
which is marked package and now in different package. In order to 
fix this without changing the public API, I'll create a new file 
called shared_s1.d, move the struct S1 there, and public import 
shared_s1.d back into the S1's original submod_s1.d file:

The file structure:
-------------------
/my_lib/mod_x/submod.d
/my_lib/mod_x/package.d
/my_lib/mod_y/submod_s1.d
/my_lib/mod_y/submod_s2.d
/my_lib/mod_y/package.d
/my_lib/shared_s1.d


File: /my_lib/shared_s1.d
--------------------------
module my_lib.shared_s1;

import my_lib.mod_y.submod_s2;

struct S1
{
     public void api()
     {
         S2 s2;
         s2.detail();
     }

     package void detail() { }
}


File: /my_lib/mod_y/submod_s1.d
--------------------------------
module my_lib.mod_y.submod_s1;

public import my_lib.shared_s1;


(other files stay the same)
################################################################
Now my_lib.mod_x.submod.fun has access rights and is able to call 
my_lib.mod_y.S1.detail because it's now an alias to 
my_lib.shared_s1.S1.detail. But then we notice that it doesn't 
work, because by moving the definition of S1 one folder up, we 
made it so that my_lib.shared_s1.S1.api isn't able to call 
my_lib.mod_y.submod_s2.S2.detail. So, we must do the same trick 
for the struct S2 now. Notice how viral this effect is. We end up 
with:

The file structure:
-------------------
/my_lib/mod_x/submod.d
/my_lib/mod_x/package.d
/my_lib/mod_y/submod_s1.d
/my_lib/mod_y/submod_s2.d
/my_lib/mod_y/package.d
/my_lib/shared_s1.d
/my_lib/shared_s2.d


File: /my_lib/shared_s2.d
--------------------------
module my_lib.shared_s2;

struct S2
{
     public void api() { }

     package void detail() { }
}


File: /my_lib/mod_y/submod_s2.d
--------------------------------
module my_lib.mod_y.submod_s2;

public import my_lib.shared_s2;


################################################################
And now it all works. But what did we learn from all this:

Your suggestion makes breaking modules into packages easier to 
understand but harder to do.

My suggestion makes breaking modules into packages harder to 
understand but easier to do.


On Wednesday, 19 June 2013 at 07:12:30 UTC, Jonathan M Davis 
wrote:
> Even if we lose something in the process, we really don't lose
> much, and since currently, package only applies to modules
> directly in the same package and not nested packages, you'd
> still be gaining over what we currently have.

I don't want 'package' symbols to give away access to nested 
packages.


More information about the Digitalmars-d mailing list