GNU   davin.50webs.com/research
Bringing to you notes for the ages

       Main Menu          Research Projects         Photo Album            Curriculum Vitae      The Greatest Artists
    Email Address       Computer Games          Web Design          Java Training Wheels      The Fly (A Story)   
  Political Activism   Bob Dylan Quotes+       My Life Story          Smoking Cessation          Other Links      
Debugging Macros     String Class I     Linked List System I Java for C Programmers Naming Convention
    String Class II         How I use m4              Strings III                 Symmetrical I/O             Linked Lists II     
Run-Time Type Info   Virtual Methods      An Array System        Science & Religion            Submodes       
  Nested Packages      Memory Leaks    Garbage Collection      Internet & Poverty      What is Knowledge?
Limits of Evolution   Emacs Additions      Function Plotter           Romantic Love        The Next Big Thing
    Science Fiction     Faster Compilation Theory of Morality         Elisp Scoping               Elisp Advice      
  S.O.G.M. Pattern       Safe Properties         School Bullying          Charisma Control          Life and Death    
     Splitting Java          Multiple Ctors       Religious Beliefs         Conversation 1           Conversation 2    
   J.T.W. Language    Emacs Additions II      Build Counter             Relation Plotter          Lisp++ Language  
  Memory Leaks II   Super Constructors CRUD Implementation Order a Website Form There Is An Afterlife
More Occam's Razor C to Java Translator Theory of Morality II


Submodes in Java and C++ Free Stuff

Abstract

This article presents a Java/C++ design pattern which I call Submodes in which a single class is split into two classes so that control of setting and getting of properties can be managed. This is useful if a class has properties that can be meaningfully setted or getted if other properties have specific values. For example in a game, a timer variable explode_time may only be meaningful if another boolean (in Java) or bool (in C++) property explode_mode is set to true. In C++ variables of type bool, char, int, float, double and pointers are initialised to no specific value, just whatever is the contents of memory at the time the variable is constructed. Using Submodes, errors for uninitialised properties can be found at debug-time (when the symbol NDEBUG is not set), and the overhead of the extra testing code can be optimised away into nothing in release versions (when NDEBUG is set) for the same level of performance as if Submodes were not used.

1. The design pattern in Java

In complicated classes, some properties may only be meaningfully getted or setted if certain other variables are certain values. Consider the following class where the comments indicate which values the properties may have before they can be getted or setted.

class A
{
   private int a1;

   // The following property is meaningful if a1 is 0
   private int a2;
   
   public  int a3;
   
   // The following property is meaningful if a3 is 0
   public X a4;
}

Here is how the above class can be split into two classes:

class A_Inner
{
   private int a1;
   private int a2;
   private int a3;
   private X   a4;

   ////////////////////////////////////////////////////////////

   public int get_a1()
   {
      return a1;
   }
   public int set_a1(int value)
   {
      a1 = value;
   }

   ////////////////////////////////////////////////////////////
   
   public int get_a2()
   {
      if (a1 != 0) {
         throw new RuntimeException("a1 != 0");
      }
      return a2;
   }
   public int set_a2(int value)
   {
      if (a1 != 0) {
         throw new RuntimeException("a1 != 0");
      }
      a2 = value;
   }

   ////////////////////////////////////////////////////////////

   public int get_a3()
   {
      return a3;
   }
   public int set_a3(int value)
   {
      a3 = value;
   }

   ////////////////////////////////////////////////////////////

   public X get_a4()
   {
      if (a3 != 0) {
         throw new RuntimeException("a3 != 0");
      }
      return a4;
   }
   public void set_a4(X value)
   {
      if (a3 != 0) {
         throw new RuntimeException("a3 != 0");
      }
      a4 = value;
   }
}

class A
{
   private A_Inner inner;

   public int get_a3()
   {
      return inner.get_a3();
   }
   public void set_a3(int value)
   {
      return inner.set_a3(value);
   }
   public X get_a4()
   {
      return inner.get_a4();
   }
   public void set_a4(X value)
   {
      inner.set_a4(value);
   }
}

From this example, it should be self explanatory to generalise Submodes to arbitrary types and number of variables.

2. The design pattern in C++

Here is the above source file translated into C++ with submodes added. Note the use of preprocessor macros to minimise the amount of code that needs to be written:

class A_Inner
{
   SUBMODES_INNER_VAR(int,a1,,);
   SUBMODES_INNER_VAR(int,a2, { assert(get_a1() == 0); }, { assert(get_a1() == 0); });
   SUBMODES_INNER_VAR(int,a3,,);
   SUBMODES_INNER_VAR_STAR(X,a4, { assert(get_a3() == 0); }, { assert(get_a3() == 0); });
};

class A
{
private:
   A_Inner inner;

   SUBMODES_OUTER_GET(int,a3);
   SUBMODES_OUTER_SET(int,a3);

   SUBMODES_OUTER_GET_STAR(X,a4);
   SUBMODES_OUTER_SET_STAR(X,a4);
};

In the above the macros SUBMODES_INNER_VAR, SUBMODES_OUTER_GET and SUBMODES_OUTER_SET should be used for types that can be passed and returned by value. The macros SUBMODES_INNER_VAR_STAR, SUBMODES_OUTER_GET_STAR and SUBMODES_OUTER_SET_STAR should by used for types that are to be passed and returned by pointer.


Here is the definition of a class that is useful for debugging uninitialised properties. This class differs from the bool type in that safe_bool objects are initialised to false, compared with no specific value for bool objects.

class safe_bool
{
public:
   bool value;
   safe_bool()
   {
      value = false;
   }
   ///
   /// Needed for assignment sb = b
   /// 
   safe_bool(bool b)
   {
      value = b;
   }
   operator bool() const
   {
      ASSERT(this != null);
      return value;
   }
};

Here is the definition of the macros for the A_Inner class:
#ifdef NDEBUG                                               \
#define SUBMODES_INNER_VAR(Type,variable,get_test,set_test) \
private:                                                    \
Type variable;                                              \
public:                                                     \
Type get_ ## variable() const {                             \
   return variable;                                         \
}                                                           \
void set_ ## variable(Type value)                           \
{                                                           \
   variable = value;                                        \
}                                               
#else /* !NDEBUG */
#define SUBMODES_INNER_VAR(Type,variable,get_test,set_test) \
private:                                                    \
Type variable;                                              \
safe_bool is_set_ ## variable;                              \
public:                                                     \
Type get_ ## variable() const {                             \
   get_test;                                                \
   assert(is_set_ ## variable);                             \
   return variable;                                         \
}                                                           \
void set_ ## variable(Type value)                           \
{                                                           \
   set_test;                                                \
   is_set_ ## variable = true;                              \
   variable = value;                                        \
}                                               
#endif /* NDEBUG */

#ifdef NDEBUG
#define SUBMODES_INNER_VAR_STAR(Type,variable,get_test,set_test)  \
private:                                                          \
Type* variable;                                                   \
public:                                                           \
Type* get_ ## variable()                                          \
{                                                                 \
   return variable;                                               \
}                                                                 \
const Type* get_ ## variable ## _const() const                    \
{                                                                 \
   return variable;                                               \
}                                                                 \
void set_ ## variable(Type* new_value)                            \
{                                                                 \
   variable = new_value;                                          \
}
#else /* !NDEBUG */
#define SUBMODES_INNER_VAR_STAR(Type,variable,get_test,set_test)  \
private:                                                          \
Type* variable;                                                   \
safe_bool is_set_ ## variable;                                    \
public:                                                           \
Type* get_ ## variable()                                          \
{                                                                 \
   get_test;                                                      \
   assert(is_set_ ## variable);                                   \
   return variable;                                               \
}                                                                 \
const Type* get_ ## variable ## _const() const                    \
{                                                                 \
   get_test;                                                      \
   assert(is_set_ ## variable);                                   \
   return variable;                                               \
}                                                                 \
void set_ ## variable(Type* new_value)                            \
{                                                                 \
   set_test;                                                      \
   is_set_ ## variable = true;                                    \
   variable = new_value;                                          \
}
#endif /* NDEBUG */

Here is the definition of the macros for the A class:
#define SUBMODES_OUTER_GET(Type,variable)       \
public:                                         \
Type get_ ## variable() const                   \
{                                               \
   ASSERT(this != null);                        \
   return inner.get_ ## variable();             \
}

#define SUBMODES_OUTER_SET(Type,variable)       \
public:                                         \
void set_ ## variable(Type new_value)           \
{                                               \
   ASSERT(this != null);                        \
   inner.set_ ## variable(new_value);           \
}

#define SUBMODES_OUTER_GET_STAR(Type,variable)  \
public:                                         \
Type* get_ ## variable()                        \
{                                               \
   ASSERT(this != null);                        \
   return inner.get_ ## variable();             \
}                                               \
const Type* get_ ## variable ## _const() const  \
{                                               \
   return inner.get_ ## variable ## _const();   \
}

#define SUBMODES_OUTER_SET_STAR(Type,variable)  \
public:                                         \
void set_ ## variable(Type* new_value)          \
{                                               \
   ASSERT(this != null);                        \
   inner.set_ ## variable(new_value);           \
}


I have inspected assembler code generated by GNU C++ from source code that uses Submodes and have found that if the setting/getting tests are dropped when NDEBUG is set as is the case for the above macro definitions, then the resulting code is just as efficient as if Submodes were not used.



Back to Research Projects
This page has the following hit count:
| Main Menu | Research Projects | Photo Album | Curriculum Vitae | The Greatest Artists |
| Email Address | Computer Games | Web Design | Java Training Wheels | The Fly (A Story) |
| Political Activism | Bob Dylan Quotes+ | My Life Story | Smoking Cessation | Other Links |
| Debugging Macros | String Class I | Linked List System I | Java for C Programmers | Naming Convention |
| String Class II | How I use m4 | Strings III | Symmetrical I/O | Linked Lists II |
| Run-Time Type Info | Virtual Methods | An Array System | Science & Religion | Submodes |
| Nested Packages | Memory Leaks | Garbage Collection | Internet & Poverty | What is Knowledge? |
| Limits of Evolution | Emacs Additions | Function Plotter | Romantic Love | The Next Big Thing |
| Science Fiction | Faster Compilation | Theory of Morality | Elisp Scoping | Elisp Advice |
| S.O.G.M. Pattern | Safe Properties | School Bullying | Charisma Control | Life and Death |
| Splitting Java | Multiple Ctors | Religious Beliefs | Conversation 1 | Conversation 2 |
| J.T.W. Language | Emacs Additions II | Build Counter | Relation Plotter | Lisp++ Language |
| Memory Leaks II | Super Constructors | CRUD Implementation | Order a Website Form | There Is An Afterlife |
| More Occam's Razor | C to Java Translator | Theory of Morality II
Last modified: Sun Sep 25 16:11:47 NZDT 2016
Best viewed at 800x600 or above resolution.
© Copyright 1999-2016 Davin Pearson.
Please report any broken links to