Adding a payload to a type

Simen Kjærås simen.kjaras at gmail.com
Mon May 27 09:27:37 UTC 2019


On Monday, 27 May 2019 at 08:40:45 UTC, Amex wrote:
> I have some types I've declared and I'd like to magically 
> extend them and add data. The problem is I inheriting from them 
> them is bad news.
>
> Suppose, for example, I have an image type that is used in an 
> application. For a small part of the application it needs to 
> associate with each image type an xy coordinate type that adds 
> a coordinate to the image to be used by the part of the app 
> that needs to have coordinates for the image. The rest of the 
> app does not care or need the xy coordinates.
>
> Inheritance solves this problem in some sense except it 
> doesn't. If I want to add new data then it breaks.
>
> class image;
> class xy : image; // can only add an image.
> class z : ??; ?? could be xy, image, or something else
>
> Inheritance is not the correct thing to do here. I only want to 
> associate data with an object. The hierarchy does not matter.
>
>
> I could add a payload type to image but this causes problems 
> since it would have to be void or of a singular type. Mainly it 
> causes problems with the serializer I'm using since it can't 
> handle voids(I might be able to get it to work with a special 
> type but it will not be easy).
>
>
> I could, of course, add a parallel struct that somehow 
> associates the image it's extra data but to keep them in sync 
> will not be easy since it will have to persist between runs(so 
> the address could not be used).
>
> One could think of what I'm trying to do is create a tuple that 
> holds the image and any other data.
>
> tuple(tuple(image, xy), z) // the outer tuple may occur later 
> without knowing that the image has been "wrapped".
>
> How does one normally handle this? It seems like something 
> really simple to do(attach data) but it has no real 
> programmatic way to do naturally that works with oop.
>
>
> The main thing is that attaching different data should "stack" 
> and not effect the base type or break the type hierarchy. If 
> something takes an image it should take any extended object.
>
>
> I feel like the only way to do this is to create a special type 
> that can be serialized properly and is part of the base 
> class... I'll have to do it for all the classes. Hopefully 
> someone has some better ideas?

There's of course many different ways to skin a cat. Here's my 
first idea:

class Image {
     // regular image stuff
     Metadata[] metadata;

     T getMetadata(T : Metadata)() {
         foreach (e; metadata) {
             if (cast(T)e !is null) {
                 return cast(T)e;
             }
         }
         return null;
     }
}

abstract class Metadata {}

class Coordinates : Metadata {
     int x, y;
     this(int x, int y) {
         this.x = x;
         this.y = y;
     }
}

unittest {
     auto img = new Image();
     img.metadata ~= new Coordinates(1,2);

     auto coords = img.getMetadata!Coordinates;
     assert(coords.x == 1);
     assert(coords.y == 2);
}

This could easily be extended to support multiple metadata of the 
same type by adding a name field or such.

--
   Simen


More information about the Digitalmars-d-learn mailing list