www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - On packages and naming them

reply Bill Baxter <dnewsgroup billbaxter.com> writes:
This was going to be a proposal, but then I realized that D actually 
already has a nice way to deal with the issue.  So consider this an 
essay about how to use packages effectively in D.  Hopefully someone 
will find it informative.

Problem:
D code tends to work best when placed in a package [1], but a good 
package name is not always obvious.  I observe a few of strategies in use:

[Strategy 1] Just use a generic name like "utils" or "tools".  This 
makes the D compiler happy, but only until someone else decides to name 
their package the same thing.

[Strategy 2] Just use a random made-up name, like "cashew", "schooner", 
"tango", or "derelict".  This is fine except these packages often become 
huge, containing lots of disparate libraries and no one user is likely 
to want them all.  For instance a dev might want cashew.utils.Array but 
couldn't care less about cashew.cgi.*.  The granularity is bad.  You end 
up with a lib that is a monolithic assortment of eclectic rubbish.

[Stragegy 3] (from Java) Put modules inside net-derived package names 
like "com.sun.java".  That eliminates clashes but it's just ugly. 
Chances are there's only going to be *one* SWT out there, so saying 
"org.eclipse.swt" every time you import an SWT module is a little 
tedious.  And sometimes affiliations change, companies get acquired, or 
you're just a hobby dev and don't actually *have* your own domain name 
to use.

[Strategy 4] For an individual developer, use your initials or some form 
of your name.  This is ok if you intend to make this project "yours" 
forever, but if you're starting an open source project, I think putting 
any form of your own name on it is a bad practice.  It discourages 
others from joining the project.  Plus it has similarities to Strategy 
2, in that your name has nothing to do with the contents of the package, 
so the contents will end up being a random grab-bag.

POSSIBLE REMEDIES:

Here I was about to propose a few new ways to handle this, but realized 
that one of my proposals is actually possible, and indeed already in 
use.  So I'll just point out the solution:

The idea is just to split a single package across multiple locations. 
This is actually possible now, and is in fact used by Derelict to 
organize its various sub-projects.

So this means you can happily use a random-name package (Strategy 2) for 
everything you do without forcing everyone who uses one part of that 
package to download/install all of it.

If you use dsss for building/distribution you need to specify different 
names for the different components, but it's straightforward, just see 
derelict/DerelictAL/dsss.conf for instance. 
(http://www.dsource.org/projects/derelict/browser/trunk/DerelictAL/dsss.conf)

Still I think maybe D and supporting tools could do more to support this 
very nice paradigm.  For instance the Derelict source tree is kind of a 
mess because all the separate sub-libraries are in sub-directories.  So 
there is much redundancy in the directory layout: 
derelictFoo/derelict/foo/Foo.d, derelictBar/derelict/bar/Bar.d
It would be nicer if the derelict source tree could just be under a 
single top-level derelict/ directory.  There are probably issues with 
SVN involved there too in the decision to organize that way.

So I'm not sure what could be done to make that easier.

However there is one thing that I think D could do to make using 
pacakges easier, and that is

   Package aliases

But I think I'll put it in a separate message because it switches gears 
from an essay on how to do things now, to a proposal for a change.



[1] As an example I recently ran into a conflict where my module called 
just "memory" clashed with a module in Tango called 
"tango.something.something.memory".  So a package-less module can clash 
even with a deeply nested module in a package.  There are troubles with 
installation, too, (with DSSS) since all package-less modules are copied 
to the same DSSS include directory.

--bb
May 14 2008
parent reply terranium <spam here.lot> writes:
Bill Baxter Wrote:

 [Strategy 1] Just use a generic name like "utils" or "tools".  This 
 makes the D compiler happy, but only until someone else decides to name 
 their package the same thing.
One more option: import projectname.all;
May 15 2008
parent reply Yigal Chripun <yigal100 gmail.com> writes:
terranium wrote:
 Bill Baxter Wrote:
 
 [Strategy 1] Just use a generic name like "utils" or "tools".  This 
 makes the D compiler happy, but only until someone else decides to name 
 their package the same thing.
One more option: import projectname.all;
I'll also add something I read in this NG in the past about python's package system: you can define a file called __this__.py with imports. this is a reserved python symbol so you cannot import it directly. the idea is that you can write import package.subpackage; //replace with the python syntax for this and since you asked for a package and not a module, the compiler will rewrite it to mean: import package.subpackage.__this__; in the D version this would mean to define a special this.d file for packages. also, in the exciting D system it can be done in tango as well due to the naming convention: tango packages are all lowercase, while modules are CamelCase. this mean you can use the following: import package.subpackage.Module; import package.Subpackage; this works because d is case sensitive. so even if you try this on windows (where FSs are case insensitive) it will work cause the compiler will recognize them as different symbols, and will know to look for the right file in the file system. at least, this is what I read in the NG. I prefer something in this line more than .all since .all implies the D equivalent of import stuff.*; in Java. the two approaches above can be used when you want to import some sort of Public API (user defined) instead of all the symbols (including the internal ones)
May 15 2008
parent reply terranium <spam here.lot> writes:
Yigal Chripun Wrote:

 I prefer something in this line more than .all since .all implies the D
 equivalent of import stuff.*; in Java.
 the two approaches above can be used when you want to import some sort
 of Public API (user defined) instead of all the symbols (including the
 internal ones)
Who cares whether private symbols are imported or not? What can this affect?
May 22 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
terranium wrote:
 Yigal Chripun Wrote:
 
 I prefer something in this line more than .all since .all implies the D
 equivalent of import stuff.*; in Java.
 the two approaches above can be used when you want to import some sort
 of Public API (user defined) instead of all the symbols (including the
 internal ones)
Who cares whether private symbols are imported or not? What can this affect?
You can't have multiply-defined symbols, even if some of them are private. i.e. I have a 3-module program. I want two of the modules to work independently but want to use the alias "string" in all 3 modules if it hasn't been defined. No way to do this -- the two modules that need to be independent would define "string" separately, and the module that import them both fails to compile, even when the alias is private in one or both of them.
May 22 2008