On 2010-11-11 13:10, Per Ångström wrote:
I hope we can all agree that minimizing module interdependencies is a
good thing, that a highly interdependent set of modules is generally
harder to understand and more difficult to test than if the
module-dependency chain is acyclic.

With that in mind, suppose I have the following C++ code, organized with
a separation of interface and implementation, with no circular include
dependencies:

// IStudent.h
class ITeacher; // forward reference

class IStudent {
public:
virtual void ask(ITeacher &) = 0;
virtual void learn(ITeacher &, const char * knowledge) = 0;
};

// ITeacher.h
class IStudent; // forward reference

class ITeacher
{
public:
virtual void teach(IStudent &) = 0;
};

// Student.h
#include "IStudent.h"
class Student : public IStudent {
public:
void ask(ITeacher &);
void learn(ITeacher &, const char * knowledge);
};
// Teacher.h
#include "ITeacher.h"
class Teacher: public ITeacher {
public:
void teach(IStudent &);
};
// Student.cpp
#include "Student.h"
#include "ITeacher.h"

void Student::ask(ITeacher & teacher)
{
teacher.teach(*this);
}

void Student::learn(ITeacher &, const char * )
{
}

// Teacher.cpp
#include "Teacher.h"
#include "IStudent.h"

void Teacher::teach(IStudent & student)
{
student.learn(*this, "knowledge");
}

// main.cpp
#include "Student.h"
#include "Teacher.h"
int main()
{
Student student;
Teacher teacher;
student.ask(teacher);
return 0;
}

Below is my attempt at porting the code to D2. I hope I'm missing
something due to my limited experience with D, but it seems D forces me
to create circular dependencies between modules ITeacher and IStudent,
since I cannot find a way to forward-declare types external to the
current module in D like in C/C++.

// IStudent.d
import ITeacher; // would like to forward-declare the interface instead

interface IStudent {
void ask(ITeacher);
void learn(ITeacher, string knowledge);
}

// ITeacher.d
import IStudent;

interface ITeacher
{
void teach(IStudent);
}
// Student.d
import IStudent;

class Student : IStudent {
void ask(ITeacher teacher)
{
teacher.teach(this);
}
void learn(ITeacher teacher, string knowledge)
{
}
}
// Teacher.d
import ITeacher;
import IStudent;

class Teacher: ITeacher {
void teach(IStudent student)
{
student.learn(this, "knowledge");
}
}

// main.d
import Student;
import Teacher;
void main()
{
auto student = new Student;
auto teacher = new Teacher;
student.ask(teacher);
}

So my question is: Am I missing something, or is this the D way to do it?

Cheers,

First you have to import ITeacher in Student.d (if I'm reading this right). Second, D has (generally) no problems with circular references. You only get problems when two modules is a part of a circular reference and both have module constructors. If you porting C++ code you will not have this problem since C++ doesn't have module constructors.

BTW, you generally don't separate your interface and implementation in D (you can to that if you want to hide your implementation).

The import/module system in D is more like the one in Java than the one in C/C++.

--
/Jacob Carlborg

Reply via email to