Thread overview
Problem with one-class-per-file approach
Mar 08, 2010
Kris Herlaar
Mar 08, 2010
bearophile
Mar 09, 2010
BCS
March 08, 2010
Hi folks,

Allow me to introduce myself, I'm Kris and new to this list and the D language in general, but have well over 20 years of programming experience using several other languages ranging from Wozniaks' integer basic to Hejlsbergs' c#.

My first venture using D is to create a set of classes implementing XML DOM using familiar syntax for people used to php or javascript and such. I was able to write the basics for this in D in a few hours using a bunch of classes:

- XMLDocument
- XMLNode
- XMLAttribute
- XMLElement
- XMLTextNode
- XMLComment
- XMLCDataSection
- XMLNodeList
- XMLAttributeList

All in the package "red.xml"

Being used to (and really liking!) the one-class-per-file approach, I instinctively created the classes in seperate files. When attempting to compile a simple test program however it quickly became totally unrealistic to use the one-class-per-file approach because I had to import each and every single file seperately in order to get a working build. When I moved all the classes into a single module (red.xml.xmldom) it worked flawlessly but I would really like to have the best of both approaches.

Is it possible to split the files up to use one class per file again, but add a red.xml.xmldom module imports and exposes them somehow?

I was hoping it'd be something like the following in the red.xml.dom module:

import red.xml.xmldocument;
import red.xml.xmlnNode;
import red.xml.xmlattribute;
import red.xml.xmlelement;
import red.xml.xmltextnode;
import red.xml.xmlcomment;
import red.xml.xmlcdatasection;
import red.xml.xmlnodelist;
import red.xml.xmlattributelist;

But that doesn't seem to work (I get a whole bunch of "module ... is in multiple defined" errors).

I'm compiling with the latest dmd compiler on the commandline in macos x (10.6) using a commandline tool I built in php that compiles a file "main.d" and adds all imported dependencies to the dmd commandline. The generated commandline statement looks like this:

dmd -of/Users/kris/Developer/D/xml-tests/main -unittest /Users/kris/Developer/D/xml-tests/main.d /Users/kris/Developer/D/xml-tests/red/generic/linkedlist.d /Users/kris/Developer/D/xml-tests/red/xml/xmlnode.d /Users/kris/Developer/D/xml-tests/red/xml/xmldocument.d /Users/kris/Developer/D/xml-tests/red/xml/xmlattribute.d /Users/kris/Developer/D/xml-tests/red/xml/xmlattributelist.d /Users/kris/Developer/D/xml-tests/red/xml/xmlelement.d /Users/kris/Developer/D/xml-tests/red/xml/xmltextnode.d /Users/kris/Developer/D/xml-tests/red/xml/xmlcomment.d /Users/kris/Developer/D/xml-tests/red/xml/xmlcdatasection.d /Users/kris/Developer/D/xml-tests/red/xml/xmlnodelist.d /Users/kris/Developer/D/xml-tests/red/xml/dom.d

more readable:

dmd -ofmain -unittest main.d
	red/generic/linkedlist.d
	red/xml/xmlnode.d
	red/xml/xmldocument.d
	red/xml/xmlattribute.d
	red/xml/xmlattributelist.d
	red/xml/xmlelement.d
	red/xml/xmltextnode.d
	red/xml/xmlcomment.d
	red/xml/xmlcdatasection.d
	red/xml/xmlnodelist.d
	red/xml/dom.d

I've also tried versions omitting the dom.d (same errors), and adding only dom.d (lots of "identifier ... is not defined" errors), but nothing works the way I'd hope and/or expect.

Is there any clean way to do this?

I can make my sourcecode available if anyone would like that (for the build tool as well).

March 08, 2010
Kris Herlaar:

> Allow me to introduce myself, I'm Kris and new to this list and the D language in general,

Welcome here and to D then.


> Being used to (and really liking!) the one-class-per-file approach, I instinctively created the classes in seperate files.<

D gives you the freedom, if you want, to put single classes in files, but the normal D idiom is to put related classes in a single module (if they aren't too much long).
And keep in mind that in D there are also free functions (and templates, inner functions, true closures, etc), so you don't need to use classes for everything.


> import red.xml.xmldocument;
> import red.xml.xmlnNode;
> import red.xml.xmlattribute;
> import red.xml.xmlelement;
> import red.xml.xmltextnode;
> import red.xml.xmlcomment;
> import red.xml.xmlcdatasection;
> import red.xml.xmlnodelist;
> import red.xml.xmlattributelist;

You can also write:
public import red.xml.xmldocument,
              red.xml.xmlnNode,
              red.xml.xmlattribute,
              ...
              red.xml.xmlattributelist;



>I'm compiling with the latest dmd compiler on the commandline in macos x (10.6) using a commandline tool I built in php that compiles a file "main.d" and adds all imported dependencies to the dmd commandline.<

There are several already written programs to do that :-) For example I use 'bud', there is also rdmd built in the distribution.

Bye,
bearophile
March 09, 2010
Hello Kris,

> Hi folks,
> 
> Is it possible to split the files up to use one class per file again,
> but add a red.xml.xmldom module imports and exposes them somehow?

Take a look at the details of import. IIRC "public import" does something like what you want.

> 
> I was hoping it'd be something like the following in the red.xml.dom
> module:
> 
> import red.xml.xmldocument;
> import red.xml.xmlnNode;
> import red.xml.xmlattribute;
> import red.xml.xmlelement;
> import red.xml.xmltextnode;
> import red.xml.xmlcomment;
> import red.xml.xmlcdatasection;
> import red.xml.xmlnodelist;
> import red.xml.xmlattributelist;
> But that doesn't seem to work (I get a whole bunch of "module ... is
> in multiple defined" errors).

I don't know what's causing that, but my first guess would be to add module "red.xml.whatever;" lines to each module.

-- 
... <IXOYE><