Default values and nullification for thrift code

Summary: All things are null now, unless you specify a default value!

Reviewed By: marc


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664963 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
index 05b4331..e22830e 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -373,29 +373,53 @@
   vector<t_field*>::const_iterator m_iter; 
   const vector<t_field*>& members = tstruct->get_members();
   
-  // Default constructor
-  bool init_ctor = false;
   if (!pointers) {
+    // Default constructor
+    indent(out) <<
+      tstruct->get_name() << "()";
+
+    bool init_ctor = false;
+
     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
       t_type* t = (*m_iter)->get_type();
       while (t->is_typedef()) {
         t = ((t_typedef*)t)->get_type();
       }
-      if (t->is_base_type() &&
-          ((t_base_type*)t)->get_base() != t_base_type::TYPE_STRING) {
+      if (t->is_base_type() || t->is_enum()) {
+        string dval;
+        if (t->is_enum()) {
+          dval += "(" + t->get_name() + ")";
+        }
+        dval += t->is_string() ? "\"\"" : "0";
+        t_const_value* cv = (*m_iter)->get_value();
+        if (cv != NULL) {
+          dval = render_const_value(out, (*m_iter)->get_name(), t, cv);
+        }
         if (!init_ctor) {
           init_ctor = true;
-          indent(out) <<
-            tstruct->get_name() << "() : ";
-          out << (*m_iter)->get_name() << "(0)";
+          out << " : ";
+          out << (*m_iter)->get_name() << "(" << dval << ")";
         } else {
-          out << ", " << (*m_iter)->get_name() << "(0)";
+          out << ", " << (*m_iter)->get_name() << "(" << dval << ")";
         }
       }
     }
-  }
-  if (init_ctor) {
-    out << " {} " << endl;
+    out << " {" << endl;
+    indent_up();
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = (*m_iter)->get_type();
+      while (t->is_typedef()) {
+        t = ((t_typedef*)t)->get_type();
+      }
+      if (!t->is_base_type()) {
+        t_const_value* cv = (*m_iter)->get_value();
+        if (cv != NULL) {
+          print_const_value(out, (*m_iter)->get_name(), t, cv);
+        }
+      }
+    }
+    indent_down();
+    indent(out) << "} " << endl;
   }
   
   out <<
@@ -1696,6 +1720,7 @@
   string etype = tmp("_etype");
   
   indent(out) <<
+    prefix << ".clear();" << endl <<
     "uint32_t " << size << ";" << endl;
   
   // Declare variables, read header
diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
index ffe8b2a..e3a3166 100644
--- a/compiler/cpp/src/generate/t_java_generator.cc
+++ b/compiler/cpp/src/generate/t_java_generator.cc
@@ -146,23 +146,25 @@
  * is NOT performed in this function as it is always run beforehand using the
  * validate_types method in main.cc
  */
-void t_java_generator::print_const_value(ofstream& out, string name, t_type* type, t_const_value* value, bool in_static) {
+void t_java_generator::print_const_value(std::ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) {
+
+  indent(out);
+  if (!defval) {
+    out <<
+      (in_static ? "" : "public static final ") <<
+      type_name(type) << " ";
+  }
   if (type->is_base_type()) {
     string v2 = render_const_value(out, name, type, value);
-    indent(out) << "public static final " << type_name(type) << " " << name << " = " << v2 << ";" << endl <<
-      endl;
+    out << name << " = " << v2 << ";" << endl << endl;
   } else if (type->is_enum()) {
-    indent(out) << "public static final int " << name << " = " << value->get_integer() << ";" << endl <<
-      endl;
+    out << name << " = " << value->get_integer() << ";" << endl << endl;
   } else if (type->is_struct() || type->is_xception()) {
     const vector<t_field*>& fields = ((t_struct*)type)->get_members();
     vector<t_field*>::const_iterator f_iter;
     const map<t_const_value*, t_const_value*>& val = value->get_map();
     map<t_const_value*, t_const_value*>::const_iterator v_iter;
-    indent(out) <<
-      (in_static ? "" : "public static final ") <<
-      type_name(type) << " " << name <<
-      " = new " << type_name(type) << "();" << endl;
+    out << name << " = new " << type_name(type) << "();" << endl;
     if (!in_static) {
       indent(out) << "static {" << endl;
       indent_up();
@@ -187,9 +189,7 @@
     }
     out << endl;
   } else if (type->is_map()) {
-    indent(out) <<
-      (in_static ? "" : "public static final ") <<
-      type_name(type, true, true) << " " << name << " = new " << type_name(type, true, true) << "();" << endl;
+    out << name << " = new " << type_name(type, true, true) << "();" << endl;
     if (!in_static) {
       indent(out) << "static {" << endl;
       indent_up();
@@ -209,9 +209,7 @@
     }
     out << endl;
   } else if (type->is_list() || type->is_set()) {
-    indent(out) <<
-      (in_static ? "" : "public static final ") <<
-      type_name(type) << " " << name << " = new " << type_name(type) << "();" << endl;
+    out << name << " = new " << type_name(type) << "();" << endl;
     if (!in_static) {
       indent(out) << "static {" << endl;
       indent_up();
@@ -348,7 +346,7 @@
   vector<t_field*>::const_iterator m_iter; 
   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
     indent(out) <<
-      "public " << declare_field(*m_iter, true) << endl;
+      "public " << declare_field(*m_iter, false) << endl;
   }
 
   // Inner Isset class
@@ -368,6 +366,22 @@
       endl;
   }
   
+  // Default constructor
+  indent(out) <<
+    "public " << tstruct->get_name() << "() {" << endl;
+  indent_up();
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = (*m_iter)->get_type();
+    while (t->is_typedef()) {
+      t = ((t_typedef*)t)->get_type();
+    }
+    if (!t->is_base_type() && (*m_iter)->get_value() != NULL) {
+      print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
+    }
+  }
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
   generate_java_struct_reader(out, tstruct);
   if (is_result) {
     generate_java_struct_result_writer(out, tstruct);
@@ -1202,6 +1216,8 @@
     obj = tmp("_list");
   }
 
+  indent(out) << prefix << " = new " << type_name(ttype, false, true) << "(); // from me" << endl;
+
   // Declare variables, read header
   if (ttype->is_map()) {
     out <<
@@ -1214,7 +1230,6 @@
       indent() << "TList " << obj << " = iprot.readListBegin();" << endl;
   }
 
-
   // For loop iterates over elements
   string i = tmp("_i");
   indent(out) <<
@@ -1259,9 +1274,9 @@
   t_field fval(tmap->get_val_type(), val);
 
   indent(out) <<
-    declare_field(&fkey, true) << endl;
+    declare_field(&fkey) << endl;
   indent(out) <<
-    declare_field(&fval, true) << endl;
+    declare_field(&fval) << endl;
 
   generate_deserialize_field(out, &fkey);
   generate_deserialize_field(out, &fval);
@@ -1597,13 +1612,15 @@
     while (ttype->is_typedef()) {
       ttype = ((t_typedef*)ttype)->get_type();
     }
-    if (ttype->is_base_type()) {
+    if (ttype->is_base_type() && tfield->get_value() != NULL) {
+      ofstream dummy;
+      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+    } else if (ttype->is_base_type()) {
       t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
       switch (tbase) {
       case t_base_type::TYPE_VOID:
         throw "NO T_VOID CONSTRUCT";
       case t_base_type::TYPE_STRING:
-        // result += " = \"\"";
         result += " = null";
         break;
       case t_base_type::TYPE_BOOL:
@@ -1625,7 +1642,7 @@
     } else if (ttype->is_container()) {
       result += " = new " + type_name(ttype, false, true) + "()";
     } else {
-      result += " = null";
+      result += " = new " + type_name(ttype, false, true) + "()";;
     }
   }
   return result + ";";
diff --git a/compiler/cpp/src/generate/t_java_generator.h b/compiler/cpp/src/generate/t_java_generator.h
index 35748e5..3c7680e 100644
--- a/compiler/cpp/src/generate/t_java_generator.h
+++ b/compiler/cpp/src/generate/t_java_generator.h
@@ -40,7 +40,7 @@
   void generate_xception(t_struct*   txception);
   void generate_service (t_service*  tservice);
 
-  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool in_static);
+  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval=false);
   std::string render_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
 
   /**
@@ -138,7 +138,7 @@
       ttype->is_container() || 
       ttype->is_struct() ||
       ttype->is_xception() ||
-      (ttype->is_base_type() && (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING));
+      ttype->is_string();
   }
 
 
diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc
index 5418733..903aac0 100644
--- a/compiler/cpp/src/generate/t_php_generator.cc
+++ b/compiler/cpp/src/generate/t_php_generator.cc
@@ -123,7 +123,7 @@
   t_const_value* value = tconst->get_value();
   
   f_consts_ << "$GLOBALS['" << program_name_ << "_CONSTANTS']['" << name << "'] = "; 
-  print_const_value(type, value);
+  f_consts_ << render_const_value(type, value);
   f_consts_ << ";" << endl << endl;
 }
 
@@ -132,36 +132,40 @@
  * is NOT performed in this function as it is always run beforehand using the
  * validate_types method in main.cc
  */
-void t_php_generator::print_const_value(t_type* type, t_const_value* value) {
+string t_php_generator::render_const_value(t_type* type, t_const_value* value) {
+  std::ostringstream out;
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
   if (type->is_base_type()) {
     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
     switch (tbase) {
     case t_base_type::TYPE_STRING:
-      f_consts_ << "'" << value->get_string() << "'";
+      out << "'" << value->get_string() << "'";
       break;
     case t_base_type::TYPE_BOOL:
-      f_consts_ << (value->get_integer() > 0 ? "true" : "false");
+      out << (value->get_integer() > 0 ? "true" : "false");
       break;
     case t_base_type::TYPE_BYTE:
     case t_base_type::TYPE_I16:
     case t_base_type::TYPE_I32:
     case t_base_type::TYPE_I64:
-      f_consts_ << value->get_integer();
+      out << value->get_integer();
       break;
     case t_base_type::TYPE_DOUBLE:
       if (value->get_type() == t_const_value::CV_INTEGER) {
-        f_consts_ << value->get_integer();
+        out << value->get_integer();
       } else {
-        f_consts_ << value->get_double();
+        out << value->get_double();
       }
       break;
     default:
       throw "compiler error: no const of base type " + tbase;
     }
   } else if (type->is_enum()) {
-    indent(f_consts_) << value->get_integer();
+    indent(out) << value->get_integer();
   } else if (type->is_struct() || type->is_xception()) {
-    f_consts_ << "new " << php_namespace(type->get_program()) << type->get_name() << "(array(" << endl;
+    out << "new " << php_namespace(type->get_program()) << type->get_name() << "(array(" << endl;
     indent_up();
     const vector<t_field*>& fields = ((t_struct*)type)->get_members();
     vector<t_field*>::const_iterator f_iter;
@@ -177,30 +181,30 @@
       if (field_type == NULL) {
         throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
       }
-      f_consts_ << indent();
-      print_const_value(g_type_string, v_iter->first);
-      f_consts_ << " => ";
-      print_const_value(field_type, v_iter->second);
-      f_consts_ << endl;
+      out << indent();
+      out << render_const_value(g_type_string, v_iter->first);
+      out << " => ";
+      out << render_const_value(field_type, v_iter->second);
+      out << endl;
     }
     indent_down();
-    indent(f_consts_) << "))";
+    indent(out) << "))";
   } else if (type->is_map()) {
     t_type* ktype = ((t_map*)type)->get_key_type();
     t_type* vtype = ((t_map*)type)->get_val_type();
-    f_consts_ << "array(" << endl;
+    out << "array(" << endl;
     indent_up();
     const map<t_const_value*, t_const_value*>& val = value->get_map();
     map<t_const_value*, t_const_value*>::const_iterator v_iter;
     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      f_consts_ << indent();
-      print_const_value(ktype, v_iter->first);
-      f_consts_ << " => ";
-      print_const_value(vtype, v_iter->second);
-      f_consts_ << "," << endl;
+      out << indent();
+      out << render_const_value(ktype, v_iter->first);
+      out << " => ";
+      out << render_const_value(vtype, v_iter->second);
+      out << "," << endl;
     }
     indent_down();
-    indent(f_consts_) << ")";
+    indent(out) << ")";
   } else if (type->is_list() || type->is_set()) {
     t_type* etype;
     if (type->is_list()) {
@@ -208,21 +212,22 @@
     } else {
       etype = ((t_set*)type)->get_elem_type();
     }
-    f_consts_ << "array(" << endl;
+    out << "array(" << endl;
     indent_up();
     const vector<t_const_value*>& val = value->get_list();
     vector<t_const_value*>::const_iterator v_iter;
     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      f_consts_ << indent();
-      print_const_value(etype, *v_iter);
+      out << indent();
+      out << render_const_value(etype, *v_iter);
       if (type->is_set()) {
-        f_consts_ << " => true";
+        out << " => true";
       }
-      f_consts_ << "," << endl;
+      out << "," << endl;
     }
     indent_down();
-    indent(f_consts_) << ")";
+    indent(out) << ")";
   }
+  return out.str();
 }
 
 /**
@@ -273,8 +278,16 @@
   indent_up();
 
   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    string dval = "null";
+    t_type* t = (*m_iter)->get_type();
+    while (t->is_typedef()) {
+      t = ((t_typedef*)t)->get_type();
+    }
+    if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
+      dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
+    }
     indent(out) <<
-      "public $" << (*m_iter)->get_name() << " = null;" << endl;
+      "public $" << (*m_iter)->get_name() << " = " << dval << ";" << endl;
   }
  
   out << endl;
@@ -284,6 +297,17 @@
     out <<
       indent() << "public function __construct($vals=null) {" << endl;
     indent_up();
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = (*m_iter)->get_type();
+      while (t->is_typedef()) {
+        t = ((t_typedef*)t)->get_type();
+      }
+      if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
+        indent(out) << "$this->" << (*m_iter)->get_name() << " = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
+      }
+    }
+    
     out <<
       indent() << "if (is_array($vals)) {" << endl;
     indent_up();
@@ -821,7 +845,7 @@
     "class " << service_name_ << "Rest" << extends_if << " {" << endl;
   indent_up();
   f_service_ <<
-    indent() << "var $impl_;" << endl <<
+    indent() << "private $impl_;" << endl <<
     endl <<
     indent() << "public function __construct($impl) {" << endl <<
     indent() << "  $this->impl_ = $impl;" << endl <<
diff --git a/compiler/cpp/src/generate/t_php_generator.h b/compiler/cpp/src/generate/t_php_generator.h
index ddea1a2..8b9e971 100644
--- a/compiler/cpp/src/generate/t_php_generator.h
+++ b/compiler/cpp/src/generate/t_php_generator.h
@@ -43,7 +43,7 @@
   void generate_xception (t_struct*   txception);
   void generate_service  (t_service*  tservice);
 
-  void print_const_value (t_type* type, t_const_value* value);
+  std::string render_const_value(t_type* type, t_const_value* value);
 
   /**
    * Structs!
diff --git a/compiler/cpp/src/generate/t_py_generator.cc b/compiler/cpp/src/generate/t_py_generator.cc
index daf56bf..5190de3 100644
--- a/compiler/cpp/src/generate/t_py_generator.cc
+++ b/compiler/cpp/src/generate/t_py_generator.cc
@@ -123,8 +123,7 @@
   string name = tconst->get_name();
   t_const_value* value = tconst->get_value();
   
-  indent(f_consts_) << name << " = "; 
-  print_const_value(type, value);
+  indent(f_consts_) << name << " = " << render_const_value(type, value);
   f_consts_ << endl << endl;
 }
 
@@ -133,36 +132,38 @@
  * is NOT performed in this function as it is always run beforehand using the
  * validate_types method in main.cc
  */
-void t_py_generator::print_const_value(t_type* type, t_const_value* value) {
+string t_py_generator::render_const_value(t_type* type, t_const_value* value) {
+  std::ostringstream out;
+
   if (type->is_base_type()) {
     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
     switch (tbase) {
     case t_base_type::TYPE_STRING:
-      f_consts_ << "'" << value->get_string() << "'";
+      out << "'" << value->get_string() << "'";
       break;
     case t_base_type::TYPE_BOOL:
-      f_consts_ << (value->get_integer() > 0 ? "True" : "False");
+      out << (value->get_integer() > 0 ? "True" : "False");
       break;
     case t_base_type::TYPE_BYTE:
     case t_base_type::TYPE_I16:
     case t_base_type::TYPE_I32:
     case t_base_type::TYPE_I64:
-      f_consts_ << value->get_integer();
+      out << value->get_integer();
       break;
     case t_base_type::TYPE_DOUBLE:
       if (value->get_type() == t_const_value::CV_INTEGER) {
-        f_consts_ << value->get_integer();
+        out << value->get_integer();
       } else {
-        f_consts_ << value->get_double();
+        out << value->get_double();
       }
       break;
     default:
       throw "compiler error: no const of base type " + tbase;
     }
   } else if (type->is_enum()) {
-    indent(f_consts_) << value->get_integer();
+    indent(out) << value->get_integer();
   } else if (type->is_struct() || type->is_xception()) {
-    f_consts_ << type->get_name() << "({" << endl;
+    out << type->get_name() << "({" << endl;
     indent_up();
     const vector<t_field*>& fields = ((t_struct*)type)->get_members();
     vector<t_field*>::const_iterator f_iter;
@@ -178,30 +179,30 @@
       if (field_type == NULL) {
         throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
       }
-      f_consts_ << indent();
-      print_const_value(g_type_string, v_iter->first);
-      f_consts_ << " : ";
-      print_const_value(field_type, v_iter->second);
-      f_consts_ << "," << endl;
+      out << indent();
+      out << render_const_value(g_type_string, v_iter->first);
+      out << " : ";
+      out << render_const_value(field_type, v_iter->second);
+      out << "," << endl;
     }
     indent_down();
-    indent(f_consts_) << "})";
+    indent(out) << "})";
   } else if (type->is_map()) {
     t_type* ktype = ((t_map*)type)->get_key_type();
     t_type* vtype = ((t_map*)type)->get_val_type();
-    f_consts_ << "{" << endl;
+    out << "{" << endl;
     indent_up();
     const map<t_const_value*, t_const_value*>& val = value->get_map();
     map<t_const_value*, t_const_value*>::const_iterator v_iter;
     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      f_consts_ << indent();
-      print_const_value(ktype, v_iter->first);
-      f_consts_ << " : ";
-      print_const_value(vtype, v_iter->second);
-      f_consts_ << "," << endl;
+      out << indent();
+      out << render_const_value(ktype, v_iter->first);
+      out << " : ";
+      out << render_const_value(vtype, v_iter->second);
+      out << "," << endl;
     }
     indent_down();
-    indent(f_consts_) << "}";
+    indent(out) << "}";
   } else if (type->is_list() || type->is_set()) {
     t_type* etype;
     if (type->is_list()) {
@@ -210,23 +211,25 @@
       etype = ((t_set*)type)->get_elem_type();
     }
     if (type->is_set()) {
-      f_consts_ << "set(";
+      out << "set(";
     }
-    f_consts_ << "[" << endl;
+    out << "[" << endl;
     indent_up();
     const vector<t_const_value*>& val = value->get_list();
     vector<t_const_value*>::const_iterator v_iter;
     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      f_consts_ << indent();
-      print_const_value(etype, *v_iter);
-      f_consts_ << "," << endl;
+      out << indent();
+      out << render_const_value(etype, *v_iter);
+      out << "," << endl;
     }
     indent_down();
-    indent(f_consts_) << "]";
+    indent(out) << "]";
     if (type->is_set()) {
-      f_consts_ << ")";
+      out << ")";
     }
   }
+
+  return out.str();
 }
 
 /**
@@ -288,14 +291,9 @@
       "pass" <<endl;
   } else {
     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if (is_result) {
-        indent(out) <<
-          "self." << (*m_iter)->get_name() << " = None" << endl;
-      } else {
-        // This fills in default values, as opposed to nulls
-        indent(out) <<
-          declare_field(*m_iter, true) << endl;
-      }
+      // This fills in default values, as opposed to nulls
+      indent(out) <<
+        declare_field(*m_iter) << endl;
     }
 
     indent(out) <<
@@ -1393,51 +1391,16 @@
  *
  * @param ttype The type
  */
-string t_py_generator::declare_field(t_field* tfield, bool init, bool obj) {
+string t_py_generator::declare_field(t_field* tfield) {
   string result = "self." + tfield->get_name();
-  if (init) {
-    t_type* type = tfield->get_type();
-    while (type->is_typedef()) {
-      type = ((t_typedef*)type)->get_type();
-    }
-    if (type->is_base_type()) {
-      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
-      switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        break;
-      case t_base_type::TYPE_STRING:
-        result += " = ''";
-        break;
-      case t_base_type::TYPE_BOOL:
-        result += " = False";
-        break;
-      case t_base_type::TYPE_BYTE:
-      case t_base_type::TYPE_I16:
-      case t_base_type::TYPE_I32:
-      case t_base_type::TYPE_I64:
-        result += " = 0";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        result += " = 0.0";
-        break;
-      default:
-        throw "compiler error: no PHP initializer for base type " + tbase;
-      }
-    } else if (type->is_enum()) {
-      result += " = 0";
-    } else if (type->is_container()) {
-      if (type->is_map()) {
-        result += " = {}";
-      } else {
-        result += " = []";
-      }
-    } else if (type->is_struct() || type->is_xception()) {
-      if (obj) {
-        result += " = " + type_name((t_struct*)type) + "()";
-      } else {
-        result += " = None";
-      }
-    }
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+  if (tfield->get_value() != NULL) {
+    result += " = " + render_const_value(type, tfield->get_value());
+  } else {
+    result += " = None";
   }
   return result;
 }
diff --git a/compiler/cpp/src/generate/t_py_generator.h b/compiler/cpp/src/generate/t_py_generator.h
index c0afe60..e849e6b 100644
--- a/compiler/cpp/src/generate/t_py_generator.h
+++ b/compiler/cpp/src/generate/t_py_generator.h
@@ -38,7 +38,7 @@
   void generate_xception (t_struct*   txception);
   void generate_service  (t_service*  tservice);
 
-  void print_const_value (t_type* type, t_const_value* value);
+  std::string render_const_value(t_type* type, t_const_value* value);
 
   /**
    * Struct generation code
@@ -122,7 +122,7 @@
   std::string py_autogen_comment();
   std::string py_imports();
   std::string render_includes();
-  std::string declare_field(t_field* tfield, bool init=false, bool obj=false);
+  std::string declare_field(t_field* tfield);
   std::string type_name(t_type* ttype);
   std::string function_signature(t_function* tfunction, std::string prefix="");
   std::string argument_list(t_struct* tstruct);
diff --git a/compiler/cpp/src/generate/t_rb_generator.cc b/compiler/cpp/src/generate/t_rb_generator.cc
index e33a5ec..4636e43 100644
--- a/compiler/cpp/src/generate/t_rb_generator.cc
+++ b/compiler/cpp/src/generate/t_rb_generator.cc
@@ -132,8 +132,7 @@
   
   name[0] = toupper(name[0]);
 
-  indent(f_consts_) << name << " = "; 
-  print_const_value(type, value);
+  indent(f_consts_) << name << " = " << render_const_value(type, value);
   f_consts_ << endl << endl;
 }
 
@@ -142,36 +141,37 @@
  * is NOT performed in this function as it is always run beforehand using the
  * validate_types method in main.cc
  */
-void t_rb_generator::print_const_value(t_type* type, t_const_value* value) {
+string t_rb_generator::render_const_value(t_type* type, t_const_value* value) {
+  std::ostringstream out;
   if (type->is_base_type()) {
     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
     switch (tbase) {
     case t_base_type::TYPE_STRING:
-      f_consts_ << "'" << value->get_string() << "'";
+      out << "'" << value->get_string() << "'";
       break;
     case t_base_type::TYPE_BOOL:
-      f_consts_ << (value->get_integer() > 0 ? "true" : "false");
+      out << (value->get_integer() > 0 ? "true" : "false");
       break;
     case t_base_type::TYPE_BYTE:
     case t_base_type::TYPE_I16:
     case t_base_type::TYPE_I32:
     case t_base_type::TYPE_I64:
-      f_consts_ << value->get_integer();
+      out << value->get_integer();
       break;
     case t_base_type::TYPE_DOUBLE:
       if (value->get_type() == t_const_value::CV_INTEGER) {
-        f_consts_ << value->get_integer();
+        out << value->get_integer();
       } else {
-        f_consts_ << value->get_double();
+        out << value->get_double();
       }
       break;
     default:
       throw "compiler error: no const of base type " + tbase;
     }
   } else if (type->is_enum()) {
-    indent(f_consts_) << value->get_integer();
+    indent(out) << value->get_integer();
   } else if (type->is_struct() || type->is_xception()) {
-    f_consts_ << type->get_name() << "({" << endl;
+    out << type->get_name() << "({" << endl;
     indent_up();
     const vector<t_field*>& fields = ((t_struct*)type)->get_members();
     vector<t_field*>::const_iterator f_iter;
@@ -187,30 +187,30 @@
       if (field_type == NULL) {
         throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
       }
-      f_consts_ << indent();
-      print_const_value(g_type_string, v_iter->first);
-      f_consts_ << " => ";
-      print_const_value(field_type, v_iter->second);
-      f_consts_ << "," << endl;
+      out << indent();
+      out << render_const_value(g_type_string, v_iter->first);
+      out << " => ";
+      out << render_const_value(field_type, v_iter->second);
+      out << "," << endl;
     }
     indent_down();
-    indent(f_consts_) << "})";
+    indent(out) << "})";
   } else if (type->is_map()) {
     t_type* ktype = ((t_map*)type)->get_key_type();
     t_type* vtype = ((t_map*)type)->get_val_type();
-    f_consts_ << "{" << endl;
+    out << "{" << endl;
     indent_up();
     const map<t_const_value*, t_const_value*>& val = value->get_map();
     map<t_const_value*, t_const_value*>::const_iterator v_iter;
     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      f_consts_ << indent();
-      print_const_value(ktype, v_iter->first);
-      f_consts_ << " =>x ";
-      print_const_value(vtype, v_iter->second);
-      f_consts_ << "," << endl;
+      out << indent();
+      out << render_const_value(ktype, v_iter->first);
+      out << " => ";
+      out << render_const_value(vtype, v_iter->second);
+      out << "," << endl;
     }
     indent_down();
-    indent(f_consts_) << "}";
+    indent(out) << "}";
   } else if (type->is_list() || type->is_set()) {
     t_type* etype;
     if (type->is_list()) {
@@ -219,28 +219,29 @@
       etype = ((t_set*)type)->get_elem_type();
     }
     if (type->is_set()) {
-      f_consts_ << "{";
+      out << "{";
     } else {
-      f_consts_ << "[" << endl;
+      out << "[" << endl;
     }
     indent_up();
     const vector<t_const_value*>& val = value->get_list();
     vector<t_const_value*>::const_iterator v_iter;
     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      f_consts_ << indent();
-      print_const_value(etype, *v_iter);
+      out << indent();
+      out << render_const_value(etype, *v_iter);
       if (type->is_set()) {
-        f_consts_ << " => true";
+        out << " => true";
       }
-      f_consts_ << "," << endl;
+      out << "," << endl;
     }
     indent_down();
     if (type->is_set()) {
-      indent(f_consts_) << "}";
+      indent(out) << "}";
     } else {
-      indent(f_consts_) << "]";
+      indent(out) << "]";
     }
   }
+  return out.str();
 }
 
 /**
@@ -323,6 +324,11 @@
   indent_up();
 
   if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if ((*m_iter)->get_value() != NULL) {
+        indent(out) << declare_field(*m_iter) << endl;
+      }
+    }
     indent(out) <<
       "if (d != nil)" << endl;
     indent_up();
@@ -1435,51 +1441,16 @@
  *
  * @param ttype The type
  */
-string t_rb_generator::declare_field(t_field* tfield, bool init, bool obj) {
+string t_rb_generator::declare_field(t_field* tfield) {
   string result = "@" + tfield->get_name();
-  if (init) {
-    t_type* type = tfield->get_type();
-    while (type->is_typedef()) {
-      type = ((t_typedef*)type)->get_type();
-    }
-    if (type->is_base_type()) {
-      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
-      switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        break;
-      case t_base_type::TYPE_STRING:
-        result += " = ''";
-        break;
-      case t_base_type::TYPE_BOOL:
-        result += " = false";
-        break;
-      case t_base_type::TYPE_BYTE:
-      case t_base_type::TYPE_I16:
-      case t_base_type::TYPE_I32:
-      case t_base_type::TYPE_I64:
-        result += " = 0";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        result += " = 0.0";
-        break;
-      default:
-        throw "compiler error: no PHP initializer for base type " + tbase;
-      }
-    } else if (type->is_enum()) {
-      result += " = 0";
-    } else if (type->is_container()) {
-      if (type->is_map() || type->is_set()) {
-        result += " = {}";
-      } else {
-        result += " = []";
-      }
-    } else if (type->is_struct() || type->is_xception()) {
-      if (obj) {
-        result += " = " + type_name((t_struct*)type) + "()";
-      } else {
-        result += " = nil";
-      }
-    }
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+  if (tfield->get_value() != NULL) {
+    result += " = " + render_const_value(type, tfield->get_value());
+  } else {
+    result += " = nil";
   }
   return result;
 }
diff --git a/compiler/cpp/src/generate/t_rb_generator.h b/compiler/cpp/src/generate/t_rb_generator.h
index 9299f3e..bb74db6 100644
--- a/compiler/cpp/src/generate/t_rb_generator.h
+++ b/compiler/cpp/src/generate/t_rb_generator.h
@@ -38,7 +38,7 @@
   void generate_xception (t_struct*   txception);
   void generate_service  (t_service*  tservice);
 
-  void print_const_value (t_type* type, t_const_value* value);
+  std::string render_const_value(t_type* type, t_const_value* value);
 
   /**
    * Struct generation code
@@ -122,7 +122,7 @@
   std::string rb_autogen_comment();
   std::string rb_imports();
   std::string render_includes();
-  std::string declare_field(t_field* tfield, bool init=false, bool obj=false);
+  std::string declare_field(t_field* tfield);
   std::string type_name(t_type* ttype);
   std::string function_signature(t_function* tfunction, std::string prefix="");
   std::string argument_list(t_struct* tstruct);
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index 24dca83..a582436 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -415,6 +415,13 @@
 }
 
 /**
+ * Check the type of a default value assigned to a field.
+ */
+void validate_field_value(t_field* field, t_const_value* cv) {
+  validate_const_rec(field->get_name(), field->get_type(), cv);
+}
+
+/**
  * Parses a program
  */
 void parse(t_program* program, t_program* parent_program) {  
diff --git a/compiler/cpp/src/main.h b/compiler/cpp/src/main.h
index a7c1d3d..470ac7f 100644
--- a/compiler/cpp/src/main.h
+++ b/compiler/cpp/src/main.h
@@ -3,6 +3,7 @@
 
 #include <string>
 #include "parse/t_const.h"
+#include "parse/t_field.h"
 
 /**
  * Defined in the flex library
@@ -38,6 +39,11 @@
 void validate_const_type(t_const* c);
 
 /**
+ * Check constant types
+ */
+void validate_field_value(t_field* field, t_const_value* cv);
+
+/**
  * Converts a string filename into a thrift program name
  */
 std::string program_name(std::string filename);
diff --git a/compiler/cpp/src/parse/t_field.h b/compiler/cpp/src/parse/t_field.h
index 35414ef..058b9fb 100644
--- a/compiler/cpp/src/parse/t_field.h
+++ b/compiler/cpp/src/parse/t_field.h
@@ -15,12 +15,14 @@
     type_(type),
     name_(name),
     key_(0),
+    value_(NULL),
     xsd_optional_(false) {}
 
   t_field(t_type* type, std::string name, int32_t key) :
     type_(type),
     name_(name),
     key_(key),
+    value_(NULL),
     xsd_optional_(false) {}
 
   ~t_field() {}
@@ -45,10 +47,19 @@
     return xsd_optional_;
   }
 
+  void set_value(t_const_value* value) {
+    value_ = value;
+  }
+
+  t_const_value* get_value() {
+    return value_;
+  }
+
  private:
   t_type* type_;
   std::string name_;
   int32_t key_;
+  t_const_value* value_;
   
   bool xsd_optional_;
 
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index a90d64b..a6492fe 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -123,7 +123,9 @@
 %type<ttype>     DefinitionType
 
 %type<tfield>    Field
+%type<iconst>    FieldIdentifier
 %type<ttype>     FieldType
+%type<tconstv>   FieldValue
 %type<tstruct>   FieldList
 
 %type<tenum>     Enum
@@ -575,32 +577,46 @@
     }
 
 Field:
-  tok_int_constant ':' FieldType tok_identifier XsdOptional CommaOrSemicolonOptional
+  FieldIdentifier FieldType tok_identifier FieldValue XsdOptional CommaOrSemicolonOptional
     {
       pdebug("tok_int_constant : Field -> FieldType tok_identifier");
-      if ($1 <= 0) {
-        pwarning(1, "Nonpositive value (%d) not allowed as a field key for '%s'.\n", $1, $4);
-        $1 = y_field_val--;
+      if ($1 < 0) {
+        pwarning(2, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $3);
       }
-      $$ = new t_field($3, $4, $1);
+      $$ = new t_field($2, $3, $1);
+      if ($4 != NULL) {
+        validate_field_value($$, $4);
+        $$->set_value($4);
+      }
       $$->set_xsd_optional($5);
     }
-| FieldType tok_identifier XsdOptional CommaOrSemicolonOptional
+
+FieldIdentifier:
+  tok_int_constant ':'
     {
-      pdebug("Field -> FieldType tok_identifier");
-      pwarning(2, "No field key specified for '%s', resulting protocol may have conflicts or not be backwards compatible!\n", $2);
-      $$ = new t_field($1, $2, y_field_val--);
-      $$->set_xsd_optional($3);
-    }
-| FieldType tok_identifier '=' tok_int_constant CommaOrSemicolonOptional
-    {
-      pwarning(1, "Trailing = id notation is deprecated. Use 'Id: Type Name' notation instead"); 
-      pdebug("Field -> FieldType tok_identifier = tok_int_constant");
-      if ($4 <= 0) {
-        pwarning(1, "Nonpositive value (%d) not allowed as a field key for '%s'.\n", $4, $2);
-        $4 = y_field_val--;
+      if ($1 <= 0) {
+        pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n", $1);
+        $1 = y_field_val--;
       }
-      $$ = new t_field($1, $2, $4);
+      $$ = $1;
+    }
+|
+    {
+      $$ = y_field_val--;
+    }
+
+FieldValue:
+  '=' ConstValue
+    {
+      if (g_parse_mode == PROGRAM) {     
+        $$ = $2;
+      } else {
+        $$ = NULL;
+      }
+    }
+|
+    {
+      $$ = NULL;
     }
 
 DefinitionType: