Thread overview
Constructor protection: package ctors, UFCS, static methods?
Dec 26, 2014
aldanor
Dec 26, 2014
aldanor
Dec 27, 2014
aldanor
Dec 28, 2014
ketmar
December 26, 2014
Hi, I've been wondering if anyone would give some advice on an OOP-related question. Assume there's an external library (module c_library) that handles IDs for groups and datasets and we want to wrap it in a high-level D API. Groups can contain datasets identified by names, and each dataset has a parent group; there are external functions get_dataset/get_group that provide the corresponding ids.

The Group class needs to have a "dataset(name)" method that returns a dataset by name and the Dataset needs to have a "group()" method that returns the parent group. However constructors of Group and Dataset that take an id are really meant to be completely internal (i.e. private or protected) which leads to the problem: how would those methods be able to access those constructors?

--------------------------

Solution 1: set protection level for constructors of Group/Dataset to "package" so they are callable from anywhere in the package. This feels a bit wrong though as they are really meant to be protected; this is also an exploit of the D-specific "package" qualifier so e.g. one wouldn't be able to do something like this in C++.

/* id.d */

class ID {
    protected int m_id;
    protected this(int id) {
        m_id = id;
    }
    int id() @property const {
        return m_id;
    }
}

/* group.d */

import c_library : get_dataset;
import id : ID;
import dataset : Dataset;

class Group : ID {
    package this(int id) { super(id); } // <-- package
    public this(...) { // high-level public ctor }
    Dataset getDataset(string name) const {
        int dataset_id = get_dataset(this.id, name);
        return Dataset(dataset_id);
}

/* dataset.d */

import c_library : get_group;
import id : ID;
import group : Group;

class Dataset : ID {
    package this(int id) { super(id); } // <-- package
    public this(...) { // high-level public ctor }
    Group group() const {
        int group_id = get_group(this.id);
        return Group(group_id);
    }
}

--------------------------

Solution 2: use UFCS and swap the group() / dataset(name) functions between the two modules. This way, e.g. group() will have access to protected Group.this(id) due to being in the same module. However, now there's a different problem: if you "import group", you won't be able to do a "group.dataset(name)" due to it being in a different module, so a public import is required to fix that -- which also feels a bit ugly (what if there are 15 different modules and not 2, would they all have to cross-public-import each other?). This is also a D-specific exploit so it again wouldn't be possible in C++.

/* group.d */

import c_library : get_group;
import id : ID;

public import dataset; // <-- public import due to UFCS

class Group : ID {
    protected this(int id) { super(id); } // <-- protected
}

Group group(in Dataset dataset) {
    return Group(get_group(dataset.id));
}

/* dataset.d */

import c_library : get_dataset;
import id : ID;

public import group; // <-- public import due to UFCS

class Dataset : ID {
    protected this(int id) { super(id); } // <-- protected
}

Dataset dataset(in Group group, string name) {
    return new Dataset(get_dataset(group.id, name));
}

--------------------------

Solution 3: add static methods like Dataset::fromGroup(name) and Group::fromDataset() and then do something like this:

/* group.d */

class Group : ID {
    ...
    static typeof(this) fromDataset(in Dataset dataset) {
        return new typeof(this)(get_group(dataset.id));
    }
}


/* dataset.d */

class Dataset {
    ...
    Group group() @property const {
        return Group.fromDataset(this);
    }
}

However, this essentially leads to duplications of every such lookup methods, so if there are many such entities, there will be a whole bunch of such static methods..

--------------------------

Is this a completely normal situation or is the design flawed and there's a clean way around it?

Thanks!
December 26, 2014
Please ignore the missing "new" keywords in the code and other minor typos :)
December 27, 2014
On Friday, 26 December 2014 at 15:58:18 UTC, aldanor wrote:
> Please ignore the missing "new" keywords in the code and other minor typos :)

Any opinions please?.. Would be much appreciated.

Thanks!
December 28, 2014
On Sat, 27 Dec 2014 23:34:06 +0000
aldanor via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com>
wrote:

> On Friday, 26 December 2014 at 15:58:18 UTC, aldanor wrote:
> > Please ignore the missing "new" keywords in the code and other minor typos :)
> 
> Any opinions please?.. Would be much appreciated.

i can't understand a word from it. sorry. ;-)

no, really, i'm stupid and the text is big. try to write it with some other words, make it shorter. it's mostly a non-technical question as i can see, so clarity is important there.