design - class to represent a variable

Discussion in 'C++' started by bartek, May 20, 2004.

  1. bartek

    bartek Guest

    Hello,

    I've been pondering with this for quite some time now, and finally
    decided to ask here for suggestions. I'm kind of confused, actually...
    Maybe I'm thinking too much...

    Brain dump follows...

    I need a class to represent a variable, with an associated data type
    and/or value. Though, I don't want it to be a variant type, and not a
    'convenience' class either.

    The variable objects will be used in variable lists (a'la symbol tables),
    so they are going to be polymorphic.

    Now to the point...

    The variable type is determined by the following factors:
    1. raw data type (int, float, string, etc...)
    2. array width (if it's an array of p.1)
    3. storage class modifier

    My dilemma concerns the actual design of the way how to access those
    variables in different parts of the system.

    The lists of variables are used in quite different situations.
    For example, in generating function prototypes (type declarations),
    carrying actual data around the system, translating data coming from
    external sources.

    The above requirements are pushing me towards a consequent use of the
    visitor pattern. Though, I'm completely puzzled on how to apply visitor
    to a type which is determined by 3 factors (as shown above).

    It all seems as a total maintenance disaster at the moment...

    THE Question:
    Is there a simple way (or a way to simplify) such a case of three-way-
    visitation?

    Should I go for explicit definition of each type?

    E.g.

    Given types Int and Float, and storage classes Uniform and Varying,
    define every possible combination of data type, array specifier, and
    storage class modifier. ouch!

    class Variable ... // the root

    class UniformInt : public Variable ...
    class UniformIntArray : public Variable ...
    class VaryingInt : public Variable ...
    class VaryingIntArray : public Variable ...
    class UniformFloat : public Variable ...
    etc...

    Maybe I could nest it in some way?

    E.g.

    class StorageSpec ... // root

    class Uniform : public StorageSpec ...
    class Varying : public StorageSpec ...

    class Variable ... // root

    class Float : public Variable {
    StorageSpec* m_storage_spec;
    };
    etc...

    Or maybe the other way around, that is - embed data type in a storage
    class?

    I'm aware that it's impossible to help me with so small amount of
    information given. Though I hope you can give me some references to
    whatever medium, where a remotely similar problem is solved.

    Thanks for your time.

    Cheers.
     
    bartek, May 20, 2004
    #1
    1. Advertising

  2. bartek

    Derek Guest

    What exactly are you writing? I'm curious because I'm
    working on a very similar problem.
     
    Derek, May 20, 2004
    #2
    1. Advertising

  3. bartek

    bartek Guest

    Derek <> wrote in news::

    > What exactly are you writing? I'm curious because I'm
    > working on a very similar problem.


    Actually it's going to be a part of an application utilizing Renderman
    interface. I'd like to represent RI variable specifications in C++ classes
    following consequent OO practices. *cough* *cough*
     
    bartek, May 20, 2004
    #3
  4. bartek

    Derek Guest

    > > What exactly are you writing? I'm curious because I'm
    > > working on a very similar problem.

    >
    > Actually it's going to be a part of an application
    > utilizing Renderman interface. I'd like to represent
    > RI variable specifications in C++ classes following
    > consequent OO practices. *cough* *cough*


    That's what I thought. I just started a little RenderMan
    project myself (yet another RenderMan-compliant renderer).
    It's very new and I can barely render a sphere at this
    point, but I've been thinking ahead about how to implement
    RI variables.

    I've started peeking at open-source renderers to see how
    they handle variables (Aqsis and Pixe are both C++), but I
    haven't come up with a definitive design yet.

    Let me know if you come up with a cool design. My email
    address is "derek AT networld DOT com" if you want to
    compare notes sometime.
     
    Derek, May 20, 2004
    #4
  5. bartek

    Derek Guest

    I'm not sure you want to deal with the combinatorial
    explosion of using the visitor pattern. After all,
    there are 5 storage classes (constant, uniform,
    varying, facevarying, and vertex) and 10 types
    (float, integer, vector, color, normal, point, matrix,
    double, hpoint, and string). And each combination
    can be a scalar or an array. Yikes!

    I propose a very simple strucutre (off the top of my
    head):

    class Variable
    {
    public:
    //...
    private:
    std::string m_varName;
    StorageType m_storageType;
    DataType m_dataType;
    int m_arrayLength;
    int m_elementLength;
    std::vector<float> m_data;
    };

    Now your algorithms can 'switch' based on type type if
    they have to. I think you will find that many operations
    (e.g., linear interpolation) don't care about the type
    at all.

    Perhaps the only wrinkle is that string variables can't
    be stored very efficiently in a vector<float> and should
    probably be treated separately.
     
    Derek, May 20, 2004
    #5
  6. bartek

    bartek Guest

    Derek <> wrote in news::

    > I'm not sure you want to deal with the combinatorial
    > explosion of using the visitor pattern. After all,
    > there are 5 storage classes (constant, uniform,
    > varying, facevarying, and vertex) and 10 types
    > (float, integer, vector, color, normal, point, matrix,
    > double, hpoint, and string). And each combination
    > can be a scalar or an array. Yikes!


    That's exactly the point.
    Having such huge visitors seemed like a bad idea.
    On the other hand, visitor guarantees that every subtype will be serviced
    individually in the code.

    > I propose a very simple strucutre (off the top of my
    > head):
    >
    > class Variable
    > {
    > public:
    > //...
    > private:
    > std::string m_varName;
    > StorageType m_storageType;
    > DataType m_dataType;
    > int m_arrayLength;
    > int m_elementLength;
    > std::vector<float> m_data;
    > };
    >
    > Now your algorithms can 'switch' based on type type if
    > they have to. I think you will find that many operations
    > (e.g., linear interpolation) don't care about the type
    > at all.


    I've been considering a similar design, except that the main data was
    separated into respective derived classes.

    That is:

    class Variable {
    std::string m_name;
    StorageType m_storage_type;
    int m_size; // ==0 : scalar, >0 - array
    public:
    virtual void AcceptVisitor(Visitor&) const = 0;
    // ... accessors, etc.
    };

    class FloatVariable : public Variable {
    std::vector<float> m_data;
    public:
    //...
    };

    class StringVariable : public Variable {
    std::vector<std::string> m_data;
    public:
    //...
    };

    // etc...

    This way, I could dispatch based on the actual data type, and use
    conditionals for the storage type and/or array specification.

    But then ... I'd probably end up with such conditionals in every visitor,
    which is kind of contradictory to the whole design. Why bother with
    visitor at all when there will be switches everywhere, anyway?

    On the other hand, considering the fact that the storage specifier is
    only giving a new meaning for array dimensions, I thought about turning
    it into a kind of templated policy class, which would only determine the
    algorithms for operations on the data regardless of the type...

    E.g.

    // only one element to copy
    struct UniformStorage {
    template <class IterT>
    static void Copy(IterT to, IterT from)
    { *to = *from; } // just one value to copy here
    // ...
    };

    // nvertices elements to copy
    class VaryingStorage {
    int m_nvertices;
    public:
    VaryingStorage(int nvertices) : m_nvertices(nvertices) { }
    template <class IterT>
    static void Copy(IterT to, IterT from) {
    for (int i=0; i!=m_nvertices; ++i) {
    *to = *from;
    ++to; ++from;
    }
    }
    };

    And then use those policies as template arguments for FloatVariable et
    al.

    This technique, however, rules out the GOF style visitation, because
    virtual functions cannot be templates.
    Unless all templates are given explicitly...

    // in visitor
    virtual void Visit(FloatVariable<UniformStorage> const&)
    //...

    So here we go back to the huge-visitor maintenance problem, because every
    possible combination of variable with storage class must be given
    explicitly...

    Uhh too much coffee I guess...

    Cheers
     
    bartek, May 20, 2004
    #6
  7. bartek

    Derek Guest

    Your logic is all too familiar; I've gone 'round and
    'round with the same thoughts. The biggest problem is
    that I'm not really sure what operations I will need
    to perform on RI variables. That is, I'm not convinced
    that I will really have to switch based on type in all
    THAT many places. I really think in many cases all
    numerical data can be treated uniformly regardless of
    type. In that case a simple one-class solution with a
    few switch statements here and there is probably the
    best way to go. If I'm wrong, however, and I need to
    switch all over the place, I will revisit a polymorphic
    solution with visituation. Either way, I'm still a few
    weeks away from having to worry about it. Good luck.
     
    Derek, May 21, 2004
    #7
  8. bartek

    bartek Guest

    Derek <> wrote in news::

    > Your logic is all too familiar; I've gone 'round and
    > 'round with the same thoughts. The biggest problem is
    > that I'm not really sure what operations I will need
    > to perform on RI variables. That is, I'm not convinced
    > that I will really have to switch based on type in all
    > THAT many places. (...)


    You're right. I guess I'm just trying too hard.

    But still, I'm curious how do others handle similar design issues.

    Cheers.
     
    bartek, May 21, 2004
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. TB
    Replies:
    2
    Views:
    332
  2. Trevor Andrew
    Replies:
    0
    Views:
    956
    Trevor Andrew
    Jul 21, 2003
  3. Alf P. Steinbach
    Replies:
    9
    Views:
    302
    Alf P. Steinbach
    May 1, 2006
  4. Replies:
    3
    Views:
    682
    Richard Tobin
    Apr 18, 2008
  5. Olivia Dou
    Replies:
    3
    Views:
    101
    Trans
    Dec 13, 2006
Loading...

Share This Page