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,
--
Per Å.

Reply via email to