July 30, 2018
Not a question.

I came up with a nice and simple way to apply operations on an arbitrary number of members of unknown type of a set of objects of unknown type. This without having to reimplement these operations for each class that needs to support the operation(s). All this without explicitly storing references to these members. The only requirement is that the members fulfill the expectations of the operations.

An example will make it clearer.


// First we need to store the operations somewhere:
class Storage {
    Operations operations;
}


// And here we have a subject that contains data structs (of any type) that we want to apply the operations on.
// There may also be a SubjectB, C, ...
// For simplicity it subclasses Storage but operations could also be stored externaly, e.g in an array, or in some cases in the subject itself.

class SubjectA : Storage {

    // The members we want operations to work on.
    // Their type doesn't matter as long as they are compatible with
    // the operations. In this example assume these have a name and value member
    SomeStruct1 a;
    SomeStruct2 b;
    SomeStruct3!Y c;

    // Make these members available for operations with one line:
    this() {
        operations.operateOn(a, b, c);
    }
}


// After this simple setup you can now apply operations from anywhere and whenever you want:
foreach(Storage stor; storageList) {
    string s = stor.operations.concatNames();  // concats the names of a b c
    stor.operations.setValue(s);               // sets the value of a b c
}


The advantage of this is that you can have SubjectB, SubjectC, ... all with different kind of members, and it only takes one line to make them available for the operations. Also, the subjects do not need to know how many operation there are and what these operations do with the members a,b,c.


// Here is how to define the operations:

struct Operations {

  void operateOn(T...)(ref T ts) {
      concatNames = {
          string name;
          foreach(ref t; ts) name = name ~ t.name;
          return name;
      };

      setValue = (string val) => {
          foreach(ref t; ts) t.value = val;
      };

    }

    string delegate() concatNames;
    void delegate(string s) setValue;
}