home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / lang / cplus / 11785 < prev    next >
Encoding:
Text File  |  1992-07-30  |  4.9 KB  |  128 lines

  1. Path: sparky!uunet!cs.utexas.edu!qt.cs.utexas.edu!yale.edu!yale!mintaka.lcs.mit.edu!ai-lab!life.ai.mit.edu!tmb
  2. From: tmb@arolla.idiap.ch (Thomas M. Breuel)
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: tagged unions, an alternative to RTTI (Re: run-time type checking)
  5. Message-ID: <TMB.92Jul30152807@arolla.idiap.ch>
  6. Date: 30 Jul 92 19:28:07 GMT
  7. References: <1992Jul24.234628.21196@cadsun.corp.mot.com>
  8.     <1992Jul25.172045.24675@ucc.su.OZ.AU> <BryL9q.K5I@watcgl.waterloo.edu>
  9.     <1992Jul28.183746.24287@ucc.su.OZ.AU>
  10.     <TMB.92Jul29125322@arolla.idiap.ch>
  11. Sender: news@ai.mit.edu
  12. Reply-To: tmb@idiap.ch
  13. Followup-To: comp.lang.c++
  14. Organization: IDIAP (Institut Dalle Molle d'Intelligence Artificielle
  15.     Perceptive)
  16. Lines: 109
  17. In-reply-to: tmb@arolla.idiap.ch's message of 29 Jul 92 16:53:22 GMT
  18.  
  19. I have been asked to post the following response for someone who can't
  20. post from his site:
  21.  
  22. From: Deviasse Robert N <a228devi@cdf.toronto.edu>
  23. Subject: Re: tagged unions, an alternative to RTTI (Re: run-time type checking)
  24. Newsgroups: comp.lang.c++,comp.std.c++
  25. In-Reply-To: <TMB.92Jul29125322@arolla.idiap.ch>
  26. References: <1992Jul24.234628.21196@cadsun.corp.mot.com> <1992Jul25.172045.24675@ucc.su.OZ.AU> <BryL9q.K5I@watcgl.waterloo.edu> <1992Jul28.183746.24287@ucc.su.OZ.AU>
  27. Organization: University of Toronto Computing Disciplines Facility
  28.  
  29. Could you post the following to the net (I don't have have write access to
  30. the net).
  31.  
  32. Tagged unions may be simulated in C++ by the method described in "The C++ 
  33. Programming language 2nd Ed" page 168. The example is good, however, it
  34. does not deal with the case of what to do if one of the fields in the union
  35. has a constructor or destructor. If you have access to the class, and can
  36. separate the struct-part (i.e. static members and functions, nonvirtual 
  37. functions excluding the constructor and destructor) from the class part (i.e.
  38. the constructor, destructor, and virtual functions), one can work around this 
  39. problem by placing the struct-part in the union and re-attach the class part 
  40. when necessary. This works, however it does not handle cases where this
  41. separation is not possible. The method below is not much more complicated
  42. but it should be generally applicable.
  43.  
  44. Anyway, while modifying a version of XLISP, I decided to add a Complex type
  45. to the types available to XLISP. The only problem is that, the Complex type
  46. I have is in a library and has a constructor, thus it cannot be included
  47. in the union{} describing the XLISP node structure. I got around the problem
  48. by declaring a char array in the union of size sizeof(Complex) and used
  49. the necessary casts. It also needed to call the appropriate constructors
  50. and destructors, It's ugly, but it works.
  51. Thus (using you syntax):
  52.  
  53.    enum Tag {C,M,I};
  54.    union Eg Tag {
  55.      case C: Complex c; /* Has constructor. */
  56.      case M: Matrix  m; /* Has constructor and destructor. */
  57.      case I: int     i; /* Has neither. */
  58.    };
  59.  
  60. would have to be rewritten as: 
  61. (Please forgive any minor typos, I'm writting this from memory.)
  62.  
  63.  
  64.    #define type_cheat(PointerType,pointer)   ((PointerType)(void*)(value))
  65.  
  66.    class Eg {
  67.      public:
  68.        enum Tag {C,M,I,UNDEFINED};
  69.      private:
  70.        Tag _tag;
  71.  
  72.        union {
  73.          char _c[sizeof(Complex)];
  74.          char _m[sizeof(Matrix)];
  75.          int  _i;
  76.        };
  77.  
  78.        void destroy(){
  79.           switch(tag){
  80.             case C: type_cheat(Complex*,&_c)->Complex::~Complex(); break;
  81.             case M: type_cheat(Matrix*,&_m)->Matrix::~Matrix();    break;
  82.             case I: /* nothing required to be done */ break;
  83.           }
  84.        }
  85.  
  86.        void enTag(Tag tag_){
  87.          if (tag_!=_tag)
  88.             destroy();
  89.          _tag=tag_;
  90.        }
  91.  
  92.        void checkTag(Tag tag_){
  93.          if (tag_!=_tag)
  94.             error();
  95.        }
  96.      public:
  97.        Eg()  { _tag=UNDEFINED; }
  98.        ~Eg() { destroy(); }
  99.  
  100.        /* getting member functions */
  101.        Complex c() const { checkTag(C); return *type_cheat(Complex*,&_c); }
  102.        Matrix  m() const { checkTag(M); return *type_cheat(Matrix*,&_m); }
  103.        int     i() const ( checkTag(I); return _i; }
  104.  
  105.        Tag   tag() const { return _tag; }
  106.  
  107.  
  108.        /* setting member functions  */
  109.        void c(Complex c_) { enTag(C); new(type_cheat(Complex*,&_c)) Complex(c_); }
  110.        void m(Matrix  m_) { enTag(M); new(type_cheat(Matrix*,&_m)) Matrix(m_); }
  111.        void i(int     i_) { enTag(I); _i=i_; }
  112.    };
  113.  
  114.  
  115. Yes, it's verbose, but this is the type of contortions that the compiler
  116. has to go through if tagged unions were added to C++ -- this is probably
  117. the reason why tagged unions were not introduced into C++ (besides, what
  118. is the error() function above, is it an exception, an assert(), ...)
  119.  
  120. It is possible to use downcasting to solve the above problem (instead of
  121. using a union, one could derive a ComplexNode, MatrixNode, IntNode from
  122. a general XLISP_Node), however, this would require a complete rewrite
  123. of XLISP, particularly the memory manager.
  124.  
  125. I'll be very interested to know if there is a simpler solution.
  126. Also, is the above method portable?
  127.  
  128.