You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by je...@apache.org on 2013/06/18 22:29:13 UTC

[09/10] THRIFT-2012 Modernizing Go

http://git-wip-us.apache.org/repos/asf/thrift/blob/0e87c46c/compiler/cpp/src/generate/t_go_generator.cc
----------------------------------------------------------------------
diff --git a/compiler/cpp/src/generate/t_go_generator.cc b/compiler/cpp/src/generate/t_go_generator.cc
index 0b9f16e..82af8a8 100644
--- a/compiler/cpp/src/generate/t_go_generator.cc
+++ b/compiler/cpp/src/generate/t_go_generator.cc
@@ -17,6 +17,14 @@
  * under the License.
  */
 
+/*
+ * This file is programmatically sanitized for style:
+ * astyle --style=1tbs -f -p -H -j -U t_go_generator.cc
+ *
+ * The output of astyle should not be taken unquestioningly, but it is a good
+ * guide for ensuring uniformity and readability.
+ */
+
 #include <string>
 #include <fstream>
 #include <iostream>
@@ -31,325 +39,387 @@
 #include "platform.h"
 #include "version.h"
 
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
+using namespace std;
+
+/**
+ * A helper for automatically formatting the emitted Go code from the Thrift
+ * IDL per the Go style guide.
+ *
+ * Returns:
+ *  - true, if the formatting process succeeded.
+ *  - false, if the formatting process failed, which means the basic output was
+ *           still generated.
+ */
+bool format_go_output(const string &file_path);
 
-static const string endl = "\n";  // avoid ostream << std::endl flushes
+const string default_thrift_import = "git.apache.org/thrift.git/lib/go/thrift";
 
 /**
  * Go code generator.
- *
  */
-class t_go_generator : public t_generator {
- public:
-  t_go_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_generator(program)
-  {
-    (void) parsed_options;
-    (void) option_string;
-    std::map<std::string, std::string>::const_iterator iter;
-    out_dir_base_ = "gen-go";
-  }
-
-  /**
-   * Init and close methods
-   */
-
-  void init_generator();
-  void close_generator();
-
-  /**
-   * Program-level generation functions
-   */
-
-  void generate_typedef  (t_typedef*  ttypedef);
-  void generate_enum     (t_enum*     tenum);
-  void generate_const    (t_const*    tconst);
-  void generate_struct   (t_struct*   tstruct);
-  void generate_xception (t_struct*   txception);
-  void generate_service  (t_service*  tservice);
-
-  std::string render_const_value(t_type* type, t_const_value* value, const string& name);
-
-  /**
-   * Struct generation code
-   */
-
-  void generate_go_struct(t_struct* tstruct, bool is_exception);
-  void generate_go_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
-  void generate_go_struct_reader(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result=false);
-  void generate_go_struct_writer(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result=false);
-  void generate_go_function_helpers(t_function* tfunction);
-
-  /**
-   * Service-level generation functions
-   */
-
-  void generate_service_helpers   (t_service*  tservice);
-  void generate_service_interface (t_service* tservice);
-  void generate_service_client    (t_service* tservice);
-  void generate_service_remote    (t_service* tservice);
-  void generate_service_server    (t_service* tservice);
-  void generate_process_function  (t_service* tservice, t_function* tfunction);
-
-  /**
-   * Serialization constructs
-   */
-
-  void generate_deserialize_field        (std::ofstream &out,
-                                          t_field*    tfield,
-                                          bool        declare,
-                                          std::string prefix="",
-                                          std::string err="err",
-                                          bool inclass=false,
-                                          bool coerceData=false);
+class t_go_generator : public t_generator
+{
+public:
+    t_go_generator(
+        t_program* program,
+        const std::map<std::string, std::string>& parsed_options,
+        const std::string& option_string)
+        : t_generator(program) {
+        std::map<std::string, std::string>::const_iterator iter;
+        out_dir_base_ = "gen-go";
+        gen_thrift_import_ = default_thrift_import;
+
+        iter = parsed_options.find("package_prefix");
+
+        if (iter != parsed_options.end()) {
+            gen_package_prefix_ = (iter->second);
+        }
 
-  void generate_deserialize_struct       (std::ofstream &out,
-                                          t_struct*   tstruct,
-                                          bool        declare,
-                                          std::string prefix="",
-                                          std::string err="err");
+        iter = parsed_options.find("thrift_import");
 
-  void generate_deserialize_container    (std::ofstream &out,
-                                          t_type*     ttype,
-                                          bool        declare,
-                                          std::string prefix="",
-                                          std::string err="err");
+        if (iter != parsed_options.end()) {
+            gen_thrift_import_ = (iter->second);
+        }
+    }
 
-  void generate_deserialize_set_element  (std::ofstream &out,
+    /**
+     * Init and close methods
+     */
+
+    void init_generator();
+    void close_generator();
+
+    /**
+     * Program-level generation functions
+     */
+
+    void generate_typedef(t_typedef*  ttypedef);
+    void generate_enum(t_enum*     tenum);
+    void generate_const(t_const*    tconst);
+    void generate_struct(t_struct*   tstruct);
+    void generate_xception(t_struct*   txception);
+    void generate_service(t_service*  tservice);
+
+    std::string render_const_value(t_type* type, t_const_value* value, const string& name);
+
+    /**
+     * Struct generation code
+     */
+
+    void generate_go_struct(t_struct* tstruct, bool is_exception);
+    void generate_go_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception = false, bool is_result = false);
+    void generate_isset_helpers(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result = false);
+    void generate_go_struct_reader(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result = false);
+    void generate_go_struct_writer(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result = false);
+    void generate_go_function_helpers(t_function* tfunction);
+
+    /**
+     * Service-level generation functions
+     */
+
+    void generate_service_helpers(t_service*  tservice);
+    void generate_service_interface(t_service* tservice);
+    void generate_service_client(t_service* tservice);
+    void generate_service_remote(t_service* tservice);
+    void generate_service_server(t_service* tservice);
+    void generate_process_function(t_service* tservice, t_function* tfunction);
+
+    /**
+     * Serialization constructs
+     */
+
+    void generate_deserialize_field(std::ofstream &out,
+                                    t_field*    tfield,
+                                    bool        declare,
+                                    std::string prefix = "",
+                                    bool inclass = false,
+                                    bool coerceData = false);
+
+    void generate_deserialize_struct(std::ofstream &out,
+                                     t_struct*   tstruct,
+                                     bool        declare,
+                                     std::string prefix = "");
+
+    void generate_deserialize_container(std::ofstream &out,
+                                        t_type*     ttype,
+                                        bool        declare,
+                                        std::string prefix = "");
+
+    void generate_deserialize_set_element(std::ofstream &out,
                                           t_set*      tset,
                                           bool        declare,
-                                          std::string prefix="",
-                                          std::string err="err");
+                                          std::string prefix = "");
 
-  void generate_deserialize_map_element  (std::ofstream &out,
+    void generate_deserialize_map_element(std::ofstream &out,
                                           t_map*      tmap,
                                           bool        declare,
-                                          std::string prefix="",
-                                          std::string err="err");
+                                          std::string prefix = "");
+
+    void generate_deserialize_list_element(std::ofstream &out,
+                                           t_list*     tlist,
+                                           bool        declare,
+                                           std::string prefix = "");
+
+    void generate_serialize_field(std::ofstream &out,
+                                  t_field*    tfield,
+                                  std::string prefix = "");
+
+    void generate_serialize_struct(std::ofstream &out,
+                                   t_struct*   tstruct,
+                                   std::string prefix = "");
+
+    void generate_serialize_container(std::ofstream &out,
+                                      t_type*     ttype,
+                                      std::string prefix = "");
+
+    void generate_serialize_map_element(std::ofstream &out,
+                                        t_map*      tmap,
+                                        std::string kiter,
+                                        std::string viter);
+
+    void generate_serialize_set_element(std::ofstream &out,
+                                        t_set*      tmap,
+                                        std::string iter);
+
+    void generate_serialize_list_element(std::ofstream &out,
+                                         t_list*     tlist,
+                                         std::string iter);
+
+    void generate_go_docstring(std::ofstream& out,
+                               t_struct* tstruct);
+
+    void generate_go_docstring(std::ofstream& out,
+                               t_function* tfunction);
+
+    void generate_go_docstring(std::ofstream& out,
+                               t_doc*    tdoc,
+                               t_struct* tstruct,
+                               const char* subheader);
+
+    void generate_go_docstring(std::ofstream& out,
+                               t_doc* tdoc);
+
+    /**
+     * Helper rendering functions
+     */
+
+    std::string go_autogen_comment();
+    std::string go_package();
+    std::string go_imports_begin();
+    std::string go_imports_end();
+    std::string render_includes();
+    std::string render_fastbinary_includes();
+    std::string declare_argument(t_field* tfield);
+    std::string render_field_default_value(t_field* tfield, const string& name);
+    std::string type_name(t_type* ttype);
+    std::string function_signature(t_function* tfunction, std::string prefix = "");
+    std::string function_signature_if(t_function* tfunction, std::string prefix = "", bool addError = false);
+    std::string argument_list(t_struct* tstruct);
+    std::string type_to_enum(t_type* ttype);
+    std::string type_to_go_type(t_type* ttype);
+    std::string type_to_go_key_type(t_type* ttype);
+    std::string type_to_spec_args(t_type* ttype);
+
+    static std::string get_real_go_module(const t_program* program) {
+        std::string real_module = program->get_namespace("go");
+
+        if (real_module.empty()) {
+            return program->get_name();
+        }
 
-  void generate_deserialize_list_element (std::ofstream &out,
-                                          t_list*     tlist,
-                                          bool        declare,
-                                          std::string prefix="",
-                                          std::string err="err");
+        return real_module;
+    }
 
-  void generate_serialize_field          (std::ofstream &out,
-                                          t_field*    tfield,
-                                          std::string prefix="",
-                                          std::string err="err");
+private:
 
-  void generate_serialize_struct         (std::ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="",
-                                          std::string err="err");
+    std::string gen_package_prefix_;
+    std::string gen_thrift_import_;
 
-  void generate_serialize_container      (std::ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="",
-                                          std::string err="err");
+    /**
+     * File streams
+     */
 
-  void generate_serialize_map_element    (std::ofstream &out,
-                                          t_map*      tmap,
-                                          std::string kiter,
-                                          std::string viter,
-                                          std::string err="err");
-
-  void generate_serialize_set_element    (std::ofstream &out,
-                                          t_set*      tmap,
-                                          std::string iter,
-                                          std::string err="err");
-
-  void generate_serialize_list_element   (std::ofstream &out,
-                                          t_list*     tlist,
-                                          std::string iter,
-                                          std::string err="err");
-
-  void generate_go_docstring         (std::ofstream& out,
-                                          t_struct* tstruct);
-
-  void generate_go_docstring         (std::ofstream& out,
-                                          t_function* tfunction);
-
-  void generate_go_docstring         (std::ofstream& out,
-                                          t_doc*    tdoc,
-                                          t_struct* tstruct,
-                                          const char* subheader);
-
-  void generate_go_docstring         (std::ofstream& out,
-                                          t_doc* tdoc);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string go_autogen_comment();
-  std::string go_package();
-  std::string go_imports();
-  std::string render_includes();
-  std::string render_fastbinary_includes();
-  std::string declare_argument(t_field* tfield);
-  std::string render_field_default_value(t_field* tfield, const string& name);
-  std::string type_name(t_type* ttype);
-  std::string function_signature(t_function* tfunction, std::string prefix="");
-  std::string function_signature_if(t_function* tfunction, std::string prefix="", bool addOsError=false);
-  std::string argument_list(t_struct* tstruct);
-  std::string type_to_enum(t_type* ttype);
-  std::string type_to_go_type(t_type* ttype);
-  std::string type_to_spec_args(t_type* ttype);
-
-  static std::string get_real_go_module(const t_program* program) {
-    std::string real_module = program->get_namespace("go");
-    if (real_module.empty()) {
-      return program->get_name();
-    }
-    return real_module;
-  }
-
- private:
-  
-  /**
-   * File streams
-   */
-
-  std::ofstream f_types_;
-  std::stringstream f_consts_;
-  std::ofstream f_service_;
-
-  std::string package_name_;
-  std::string package_dir_;
-  
-  static std::string publicize(const std::string& value);
-  static std::string privatize(const std::string& value);
-  static std::string variable_name_to_go_name(const std::string& value);
-  static bool can_be_nil(t_type* value);
+    std::ofstream f_types_;
+    std::string f_types_name_;
+    std::ofstream f_consts_;
+    std::string f_consts_name_;
+    std::stringstream f_const_values_;
+    std::ofstream f_service_;
+
+    std::string package_name_;
+    std::string package_dir_;
+
+    static std::string publicize(const std::string& value);
+    static std::string privatize(const std::string& value);
+    static std::string variable_name_to_go_name(const std::string& value);
+    static bool can_be_nil(t_type* value);
 
 };
 
 
-std::string t_go_generator::publicize(const std::string& value) {
-  if(value.size() <= 0) return value;
-  std::string value2(value);
-  if(!isupper(value2[0]))
-    value2[0] = toupper(value2[0]);
-  // as long as we are changing things, let's change _ followed by lowercase to capital
-  for(string::size_type i=1; i<value2.size()-1; ++i) {
-    if(value2[i] == '_' && isalpha(value2[i+1])) {
-      value2.replace(i, 2, 1, toupper(value2[i+1]));
+std::string t_go_generator::publicize(const std::string& value)
+{
+    if (value.size() <= 0) {
+        return value;
+    }
+
+    std::string value2(value);
+
+    if (!isupper(value2[0])) {
+        value2[0] = toupper(value2[0]);
+    }
+
+    // as long as we are changing things, let's change _ followed by lowercase to capital
+    for (string::size_type i = 1; i < value2.size() - 1; ++i) {
+        if (value2[i] == '_' && islower(value2[i + 1])) {
+            value2.replace(i, 2, 1, toupper(value2[i + 1]));
+        }
     }
-  }
-  return value2;
+
+    return value2;
 }
 
-std::string t_go_generator::privatize(const std::string& value) {
-  if(value.size() <= 0) return value;
-  std::string value2(value);
-  if(!islower(value2[0])) {
-    value2[0] = tolower(value2[0]);
-  }
-  // as long as we are changing things, let's change _ followed by lowercase to capital
-  for(string::size_type i=1; i<value2.size()-1; ++i) {
-    if(value2[i] == '_' && isalpha(value2[i+1])) {
-      value2.replace(i, 2, 1, toupper(value2[i+1]));
-    }
-  }
-  return value2;
+std::string t_go_generator::privatize(const std::string& value)
+{
+    if (value.size() <= 0) {
+        return value;
+    }
+
+    std::string value2(value);
+
+    if (!islower(value2[0])) {
+        value2[0] = tolower(value2[0]);
+    }
+
+    // as long as we are changing things, let's change _ followed by lowercase to capital
+    for (string::size_type i = 1; i < value2.size() - 1; ++i) {
+        if (value2[i] == '_' && isalpha(value2[i + 1])) {
+            value2.replace(i, 2, 1, toupper(value2[i + 1]));
+        }
+    }
+
+    return value2;
 }
 
-std::string t_go_generator::variable_name_to_go_name(const std::string& value) {
-  if(value.size() <= 0) return value;
-  std::string value2(value);
-  std::transform(value2.begin(), value2.end(), value2.begin(), ::tolower);
-  switch(value[0]) {
+std::string t_go_generator::variable_name_to_go_name(const std::string& value)
+{
+    if (value.size() <= 0) {
+        return value;
+    }
+
+    std::string value2(value);
+    std::transform(value2.begin(), value2.end(), value2.begin(), ::tolower);
+
+    switch (value[0]) {
     case 'b':
     case 'B':
-      if(value2 != "break") {
-        return value;
-      }
-      break;
+        if (value2 != "break") {
+            return value;
+        }
+
+        break;
+
     case 'c':
     case 'C':
-      if(value2 != "case" && value2 != "chan" && value2 != "const" && value2 != "continue") {
-        return value;
-      }
-      break;
+        if (value2 != "case" && value2 != "chan" && value2 != "const" && value2 != "continue") {
+            return value;
+        }
+
+        break;
+
     case 'd':
     case 'D':
-      if(value2 != "default" && value2 != "defer") {
-        return value;
-      }
-      break;
+        if (value2 != "default" && value2 != "defer") {
+            return value;
+        }
+
+        break;
+
     case 'e':
     case 'E':
-      if(value2 != "else") {
-        return value;
-      }
-      break;
+        if (value2 != "else" && value2 != "error") {
+            return value;
+        }
+
+        break;
+
     case 'f':
     case 'F':
-      if(value2 != "fallthrough" && value2 != "for" && value2 != "func") {
-        return value;
-      }
-      break;
+        if (value2 != "fallthrough" && value2 != "for" && value2 != "func") {
+            return value;
+        }
+
+        break;
+
     case 'g':
     case 'G':
-      if(value2 != "go" && value2 != "goto") {
-        return value;
-      }
-      break;
+        if (value2 != "go" && value2 != "goto") {
+            return value;
+        }
+
+        break;
+
     case 'i':
     case 'I':
-      if(value2 != "if" && value2 != "import" && value2 != "interface") {
-        return value;
-      }
-      break;
+        if (value2 != "if" && value2 != "import" && value2 != "interface") {
+            return value;
+        }
+
+        break;
+
     case 'm':
     case 'M':
-      if(value2 != "map") {
-        return value;
-      }
-      break;
+        if (value2 != "map") {
+            return value;
+        }
+
+        break;
+
     case 'p':
     case 'P':
-      if(value2 != "package") {
-        return value;
-      }
-      break;
+        if (value2 != "package") {
+            return value;
+        }
+
+        break;
+
     case 'r':
     case 'R':
-      if(value2 != "range" && value2 != "return") {
-        return value;
-      }
-      break;
+        if (value2 != "range" && value2 != "return") {
+            return value;
+        }
+
+        break;
+
     case 's':
     case 'S':
-      if(value2 != "select" && value2 != "struct" && value2 != "switch") {
-        return value;
-      }
-      break;
+        if (value2 != "select" && value2 != "struct" && value2 != "switch") {
+            return value;
+        }
+
+        break;
+
     case 't':
     case 'T':
-      if(value2 != "type") {
-        return value;
-      }
-      break;
+        if (value2 != "type") {
+            return value;
+        }
+
+        break;
+
     case 'v':
     case 'V':
-      if(value2 != "var") {
-        return value;
-      }
-      break;
+        if (value2 != "var") {
+            return value;
+        }
+
+        break;
+
     default:
-      return value;
-  }
-  return value2 + "_a1";
+        return value;
+    }
+
+    return value2 + "_a1";
 }
 
 
@@ -359,158 +429,162 @@ std::string t_go_generator::variable_name_to_go_name(const std::string& value) {
  *
  * @param tprogram The program to generate
  */
-void t_go_generator::init_generator() {
-  // Make output directory
-  string module = get_real_go_module(program_);
-  string target = module;
-  package_dir_ = get_out_dir();
-  while (true) {
-    // TODO: Do better error checking here.
-    MKDIR(package_dir_.c_str());
-    if (module.empty()) {
-      break;
-    }
-    string::size_type pos = module.find('.');
-    if (pos == string::npos) {
-      package_dir_ += "/";
-      package_dir_ += module;
-      package_name_ = module;
-      module.clear();
-    } else {
-      package_dir_ += "/";
-      package_dir_ += module.substr(0, pos);
-      module.erase(0, pos+1);
-    }
-  }
-  string::size_type loc;
-  while((loc = target.find(".")) != string::npos) {
-    target.replace(loc, 1, 1, '/');
-  }
-  
-  // Make output file
-  string f_types_name = package_dir_+"/"+"ttypes.go";
-  f_types_.open(f_types_name.c_str());
-  f_consts_ << "func init() {" << endl;
-  
-  vector<t_service*> services = program_->get_services();
-  vector<t_service*>::iterator sv_iter;
-  string f_init_name = package_dir_+"/Makefile";
-  ofstream f_init;
-  f_init.open(f_init_name.c_str());
-  f_init  << 
-    endl <<
-    "include $(GOROOT)/src/Make.inc" << endl << endl <<
-    "all: install" << endl << endl <<
-    "TARG=thriftlib/" << target << endl << endl <<
-    "DIRS=\\" << endl;
-  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
-    f_init << "  " << (*sv_iter)->get_name() << "\\" << endl;
-  }
-  f_init << endl <<
-    "GOFILES=\\" << endl <<
-    "  ttypes.go\\" << endl;
-  //  "   constants.go\\" << endl;
-  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
-    f_init << "  " << (*sv_iter)->get_name() << ".go\\" << endl;
-  }
-  f_init << endl << endl <<
-    "include $(GOROOT)/src/Make.pkg" << endl << endl;
-  f_init.close();
-
-  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
-    string service_dir = package_dir_+"/"+(*sv_iter)->get_name();
+void t_go_generator::init_generator()
+{
+    // Make output directory
+    string module = get_real_go_module(program_);
+    string target = module;
+    package_dir_ = get_out_dir();
+
+    while (true) {
+        // TODO: Do better error checking here.
+        MKDIR(package_dir_.c_str());
+
+        if (module.empty()) {
+            break;
+        }
+
+        string::size_type pos = module.find('.');
+
+        if (pos == string::npos) {
+            package_dir_ += "/";
+            package_dir_ += module;
+            package_name_ = module;
+            module.clear();
+        } else {
+            package_dir_ += "/";
+            package_dir_ += module.substr(0, pos);
+            module.erase(0, pos + 1);
+        }
+    }
+
+    string::size_type loc;
+
+    while ((loc = target.find(".")) != string::npos) {
+        target.replace(loc, 1, 1, '/');
+    }
+
+    // Make output files
+    f_types_name_ = package_dir_ + "/" + "ttypes.go";
+    f_types_.open(f_types_name_.c_str());
+
+    f_consts_name_ = package_dir_ + "/" + "constants.go";
+    f_consts_.open(f_consts_name_.c_str());
+
+    vector<t_service*> services = program_->get_services();
+    vector<t_service*>::iterator sv_iter;
+
+    for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+        string service_dir = package_dir_ + "/" + underscore((*sv_iter)->get_name()) + "-remote";
 #ifdef MINGW
-    mkdir(service_dir.c_str());
+        mkdir(service_dir.c_str());
 #else
-    mkdir(service_dir.c_str(), 0755);
+        mkdir(service_dir.c_str(), 0755);
 #endif
-    string f_init_name = service_dir+"/Makefile";
-    ofstream f_init;
-    f_init.open(f_init_name.c_str());
-    f_init  <<
-      endl <<
-      "include $(GOROOT)/src/Make.inc" << endl << endl <<
-      "all: install" << endl << endl <<
-      "TARG=" << publicize((*sv_iter)->get_name()) << "-remote" << endl << endl <<
-      "DIRS=\\" << endl << endl <<
-      "GOFILES=\\" << endl <<
-      "  " << (*sv_iter)->get_name() << "-remote.go\\" << endl << endl <<
-      "include $(GOROOT)/src/Make.cmd" << endl << endl;
-    f_init.close();
-  }
-
-  // Print header
-  f_types_ <<
-    go_autogen_comment() <<
-    go_package() << 
-    go_imports() <<
-    render_includes() <<
-    render_fastbinary_includes() << endl << endl;
+    }
+
+    // Print header
+    f_types_ <<
+             go_package() <<
+             go_autogen_comment() <<
+             go_imports_begin() <<
+             render_fastbinary_includes() <<
+             go_imports_end();
+
+    f_consts_ <<
+              go_package() <<
+              go_autogen_comment();
+
+    f_const_values_ << endl << "func init() {" << endl;
+
 }
 
 /**
  * Renders all the imports necessary for including another Thrift program
  */
-string t_go_generator::render_includes() {
-  const vector<t_program*>& includes = program_->get_includes();
-  string result = "";
-  for (size_t i = 0; i < includes.size(); ++i) {
-    result += "import \"thriftlib/" + get_real_go_module(includes[i]) + "\"\n";
-  }
-  if (includes.size() > 0) {
-    result += "\n";
-  }
-  return result;
+string t_go_generator::render_includes()
+{
+    const vector<t_program*>& includes = program_->get_includes();
+    string result = "";
+
+    for (size_t i = 0; i < includes.size(); ++i) {
+        result += "\t\"" + gen_package_prefix_ + get_real_go_module(includes[i]) + "\"\n";
+    }
+
+    if (includes.size() > 0) {
+        result += "\n";
+    }
+
+    return result;
 }
 
 /**
  * Renders all the imports necessary to use the accelerated TBinaryProtocol
  */
-string t_go_generator::render_fastbinary_includes() {
-  return "";
+string t_go_generator::render_fastbinary_includes()
+{
+    return "";
 }
 
 /**
  * Autogen'd comment
  */
-string t_go_generator::go_autogen_comment() {
-  return
-    std::string() +
-	"/* Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
-    " *\n"
-    " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"
-    " */\n";
+string t_go_generator::go_autogen_comment()
+{
+    return
+        std::string() +
+        "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
+        "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n\n";
 }
 
 /**
  * Prints standard thrift package
  */
-string t_go_generator::go_package() {
-  return
-    string("package ") + package_name_ + ";\n\n";
+string t_go_generator::go_package()
+{
+    return string("package ") + package_name_ + "\n\n";
+}
+
+/**
+ * Render the beginning of the import statement
+ */
+string t_go_generator::go_imports_begin()
+{
+    return
+        string("import (\n"
+               "\t\"fmt\"\n"
+               "\t\"math\"\n"
+               "\t\"" + gen_thrift_import_ + "\"\n");
 }
 
 /**
- * Prints standard thrift imports
+ * End the import statement, include undscore-assignments
+ *
+ * These "_ =" prevent the go compiler complaining about used imports.
+ * This will have to do in lieu of more intelligent import statement construction
  */
-string t_go_generator::go_imports() {
-  return
-    string("import (\n"
-           "        \"thrift\"\n"
-//           "        \"strings\"\n"
-           "        \"fmt\"\n"
-           ")\n\n");
+string t_go_generator::go_imports_end()
+{
+    return
+        string(
+            ")\n\n"
+            "// (needed to ensure safety because of naive import list constrution.)\n"
+            "var _ = math.MinInt32\n\n");
 }
 
 /**
  * Closes the type files
  */
-void t_go_generator::close_generator() {
-  // Close types file
-  f_consts_ << "}" << endl;
-  f_types_ << f_consts_.str() << endl;
-  f_types_.close();
-  f_consts_.clear();
+void t_go_generator::close_generator()
+{
+    f_const_values_ << "}" << endl << endl;
+    f_consts_ << f_const_values_.str();
+
+    // Close types and constants files
+    f_consts_.close();
+    f_types_.close();
+    format_go_output(f_types_name_);
+    format_go_output(f_consts_name_);
 }
 
 /**
@@ -518,15 +592,18 @@ void t_go_generator::close_generator() {
  *
  * @param ttypedef The type definition
  */
-void t_go_generator::generate_typedef(t_typedef* ttypedef) {
-  
-  generate_go_docstring(f_types_, ttypedef);
-  string newTypeDef(publicize(ttypedef->get_symbolic()));
-  string baseType(type_to_go_type(ttypedef->get_type()));
-  if(baseType == newTypeDef)
-    return;
-  f_types_ <<
-    "type " << newTypeDef << " " << baseType << endl << endl;
+void t_go_generator::generate_typedef(t_typedef* ttypedef)
+{
+    generate_go_docstring(f_types_, ttypedef);
+    string newTypeDef(publicize(ttypedef->get_symbolic()));
+    string baseType(type_to_go_type(ttypedef->get_type()));
+
+    if (baseType == newTypeDef) {
+        return;
+    }
+
+    f_types_ <<
+             "type " << newTypeDef << " " << baseType << endl << endl;
 }
 
 /**
@@ -535,83 +612,85 @@ void t_go_generator::generate_typedef(t_typedef* ttypedef) {
  *
  * @param tenum The enumeration
  */
-void t_go_generator::generate_enum(t_enum* tenum) {
-  std::ostringstream to_string_mapping, from_string_mapping;
-  std::string tenum_name(publicize(tenum->get_name()));
-
-  generate_go_docstring(f_types_, tenum);
-  f_types_ <<
-    "type " << tenum_name << " int" << endl <<
-    "const (" << endl;
-  
-  to_string_mapping <<
-    indent() << "func (p " << tenum_name << ") String() string {" << endl <<
-    indent() << "  switch p {" << endl;
-  from_string_mapping <<
-    indent() << "func From" << tenum_name << "String(s string) " << tenum_name << " {" << endl <<
-    indent() << "  switch s {" << endl;
-
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  int value = -1;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    if ((*c_iter)->has_value()) {
-      value = (*c_iter)->get_value();
-    } else {
-      ++value;
-    }
-    string iter_std_name(escape_string((*c_iter)->get_name()));
-    string iter_name((*c_iter)->get_name());
+void t_go_generator::generate_enum(t_enum* tenum)
+{
+    std::ostringstream to_string_mapping, from_string_mapping;
+    std::string tenum_name(publicize(tenum->get_name()));
+    generate_go_docstring(f_types_, tenum);
     f_types_ <<
-      indent() << "  " << iter_name << ' ' << tenum_name << " = " << value << endl;
-    
-    // Dictionaries to/from string names of enums
+             "type " << tenum_name << " int64" << endl <<
+             "const (" << endl;
     to_string_mapping <<
-      indent() << "  case " << iter_name << ": return \"" << iter_std_name << "\"" << endl;
-    if(iter_std_name != escape_string(iter_name)) {
-      from_string_mapping <<
-        indent() << "  case \"" << iter_std_name << "\", \"" << escape_string(iter_name) << "\": return " << iter_name << endl;
-    } else {
-      from_string_mapping <<
-        indent() << "  case \"" << iter_std_name << "\": return " << iter_name << endl;
-    }
-  }
-  to_string_mapping <<
-    indent() << "  }" << endl <<
-    indent() << "  return \"\"" << endl <<
-    indent() << "}" << endl;
-  from_string_mapping <<
-    indent() << "  }" << endl <<
-    indent() << "  return " << tenum_name << "(-10000)" << endl <<
-    indent() << "}" << endl;
-
-  f_types_ <<
-    indent() << ")" << endl <<
-    to_string_mapping.str() << endl << from_string_mapping.str() << endl <<
-    indent() << "func (p " << tenum_name << ") Value() int {" << endl <<
-    indent() << "  return int(p)" << endl <<
-    indent() << "}" << endl << endl <<
-    indent() << "func (p " << tenum_name << ") IsEnum() bool {" << endl <<
-    indent() << "  return true" << endl <<
-    indent() << "}" << endl << endl;
+                      indent() << "func (p " << tenum_name << ") String() string {" << endl <<
+                      indent() << "  switch p {" << endl;
+    from_string_mapping <<
+                        indent() << "func " << tenum_name << "FromString(s string) (" << tenum_name << ", error) {" << endl <<
+                        indent() << "  switch s {" << endl;
+    vector<t_enum_value*> constants = tenum->get_constants();
+    vector<t_enum_value*>::iterator c_iter;
+    int value = -1;
+
+    for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+        if ((*c_iter)->has_value()) {
+            value = (*c_iter)->get_value();
+        } else {
+            ++value;
+        }
+
+        string iter_std_name(escape_string((*c_iter)->get_name()));
+        string iter_name((*c_iter)->get_name());
+        f_types_ <<
+                 indent() << "  " << tenum_name << "_" << iter_name << ' ' << tenum_name << " = " << value << endl;
+        // Dictionaries to/from string names of enums
+        to_string_mapping <<
+                          indent() << "  case " << tenum_name << "_" << iter_name << ": return \"" << tenum_name << "_" << iter_std_name << "\"" << endl;
+
+        if (iter_std_name != escape_string(iter_name)) {
+            from_string_mapping <<
+                                indent() << "  case \"" << tenum_name << "_" << iter_std_name << "\", \"" << escape_string(iter_name) << "\": return " <<
+                                tenum_name << "_" << iter_name << ", nil " << endl;
+        } else {
+            from_string_mapping <<
+                                indent() << "  case \"" << tenum_name << "_" << iter_std_name << "\": return " <<
+                                tenum_name << "_" << iter_name << ", nil "  << endl;
+        }
+    }
+
+    to_string_mapping <<
+                      indent() << "  }" << endl <<
+                      indent() << "  return \"<UNSET>\"" << endl <<
+                      indent() << "}" << endl;
+    from_string_mapping <<
+                        indent() << "  }" << endl <<
+                        indent() << "  return " << tenum_name << "(math.MinInt32 - 1)," <<
+                        " fmt.Errorf(\"not a valid " << tenum_name << " string\")" << endl <<
+                        indent() << "}" << endl;
+
+    f_types_ << ")" << endl << endl
+             << to_string_mapping.str() << endl
+             << from_string_mapping.str() << endl << endl;
+
 }
 
+
 /**
  * Generate a constant value
  */
-void t_go_generator::generate_const(t_const* tconst) {
-  t_type* type = tconst->get_type();
-  string name = publicize(tconst->get_name());
-  t_const_value* value = tconst->get_value();
-  
-  if(type->is_base_type() || type->is_enum()) {
-    indent(f_types_) << "const " << name << " = " << render_const_value(type, value, name) << endl;
-  } else {
-    f_types_ <<
-      indent() << "var " << name << " " << " " << type_to_go_type(type) << endl;
-    f_consts_ <<
-      "  " << name << " = " << render_const_value(type, value, name) << endl;
-  }
+void t_go_generator::generate_const(t_const* tconst)
+{
+    t_type* type = tconst->get_type();
+    string name = publicize(tconst->get_name());
+    t_const_value* value = tconst->get_value();
+
+    if (type->is_base_type() || type->is_enum()) {
+        indent(f_consts_) << "const " << name << " = " << render_const_value(type, value, name) << endl;
+    } else {
+        f_const_values_ <<
+                        indent() << name << " = " << render_const_value(type, value, name) << endl << endl;
+
+        f_consts_ <<
+                  indent() << "var " << name << " " << type_to_go_type(type) << endl;
+    }
 }
 
 /**
@@ -619,136 +698,150 @@ void t_go_generator::generate_const(t_const* tconst) {
  * is NOT performed in this function as it is always run beforehand using the
  * validate_types method in main.cc
  */
-string t_go_generator::render_const_value(t_type* type, t_const_value* value, const string& name) {
-  type = get_true_type(type);
-  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:
-      out << '"' << get_escaped_string(value) << '"';
-      break;
-    case t_base_type::TYPE_BOOL:
-      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:
-      out << value->get_integer();
-      break;
-    case t_base_type::TYPE_DOUBLE:
-      if (value->get_type() == t_const_value::CV_INTEGER) {
-        out << value->get_integer();
-      } else {
-        out << value->get_double();
-      }
-      break;
-    default:
-      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
-    }
-  } else if (type->is_enum()) {
-    indent(out) << value->get_integer();
-  } else if (type->is_struct() || type->is_xception()) {
-    out << 
-      "New" << publicize(type->get_name()) << "()" << endl <<
-      indent() << "{" << endl;
-    indent_up();
-    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;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      t_type* field_type = NULL;
-      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
-          field_type = (*f_iter)->get_type();
+string t_go_generator::render_const_value(t_type* type, t_const_value* value, const string& name)
+{
+    type = get_true_type(type);
+    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:
+            if (((t_base_type*)type)->is_binary()) {
+                out << "[]byte(\"" << get_escaped_string(value) << "\")";
+            } else {
+                out << '"' << get_escaped_string(value) << '"';
+            }
+
+            break;
+
+        case t_base_type::TYPE_BOOL:
+            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:
+            out << value->get_integer();
+            break;
+
+        case t_base_type::TYPE_DOUBLE:
+            if (value->get_type() == t_const_value::CV_INTEGER) {
+                out << value->get_integer();
+            } else {
+                out << value->get_double();
+            }
+
+            break;
+
+        default:
+            throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
         }
-      }
-      if (field_type == NULL) {
-        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
-      }
-      if(field_type->is_base_type() || field_type->is_enum()) {
+    } else if (type->is_enum()) {
+        indent(out) << value->get_integer();
+    } else if (type->is_struct() || type->is_xception()) {
         out <<
-          indent() << name << "." << publicize(v_iter->first->get_string()) << " = " << render_const_value(field_type, v_iter->second, name) << endl;
-      } else {
-        string k(tmp("k"));
-        string v(tmp("v"));
+            "&" << publicize(type->get_name()) << "{";
+        indent_up();
+        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;
+
+        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+            t_type* field_type = NULL;
+
+            for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+                if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+                    field_type = (*f_iter)->get_type();
+                }
+            }
+
+            if (field_type == NULL) {
+                throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+            }
+
+            if (field_type->is_base_type() || field_type->is_enum()) {
+                out << endl <<
+                    indent() << publicize(v_iter->first->get_string()) << ": " << render_const_value(field_type, v_iter->second, name) << ",";
+            } else {
+                string k(tmp("k"));
+                string v(tmp("v"));
+                out << endl <<
+                    indent() << v << " := " << render_const_value(field_type, v_iter->second, v) << endl <<
+                    indent() << name << "." << publicize(v_iter->first->get_string()) << " = " << v;
+            }
+        }
+
+        out << "}";
+
+        indent_down();
+    } else if (type->is_map()) {
+        t_type* ktype = ((t_map*)type)->get_key_type();
+        t_type* vtype = ((t_map*)type)->get_val_type();
+        const map<t_const_value*, t_const_value*>& val = value->get_map();
         out <<
-          indent() << v << " := " << render_const_value(field_type, v_iter->second, v) << endl <<
-          indent() << name << "." << publicize(v_iter->first->get_string()) << " = " << v << endl;
-      }
-    }
-    indent_down();
-    out <<
-      indent() << "}";
-  } else if (type->is_map()) {
-    t_type* ktype = ((t_map*)type)->get_key_type();
-    t_type* vtype = ((t_map*)type)->get_val_type();
-    const map<t_const_value*, t_const_value*>& val = value->get_map();
-    out << 
-      "thrift.NewTMap(" << type_to_enum(ktype) << ", " << type_to_enum(vtype) << ", " << val.size() << ")" << endl <<
-      indent() << "{" << endl;
-    indent_up();
-    map<t_const_value*, t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string k(tmp("k"));
-      string v(tmp("v"));
-      out <<
-        indent() << k << " := " << render_const_value(ktype, v_iter->first, k) << endl <<
-        indent() << v << " := " << render_const_value(vtype, v_iter->second, v) << endl <<
-        indent() << name << ".Set(" << k << ", " << v << ")" << endl;
-    }
-    indent_down();
-    out <<
-      indent() << "}" << endl;
-  } else if (type->is_list()) {
-    t_type* etype = ((t_list*)type)->get_elem_type();
-    const vector<t_const_value*>& val = value->get_list();
-    out <<
-      "thrift.NewTList(" << type_to_enum(etype) << ", " << val.size() << ")" << endl <<
-      indent() << "{" << endl;
-    indent_up();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string v(tmp("v"));
-      out <<
-        indent() << v << " := " << render_const_value(etype, *v_iter, v) << endl <<
-        indent() << name << ".Push(" << v << ")" << endl;
-    }
-    indent_down();
-    out <<
-      indent() << "}" << endl;
-  } else if (type->is_set()) {
-    t_type* etype = ((t_set*)type)->get_elem_type();
-    const vector<t_const_value*>& val = value->get_list();
-    out <<
-      "thrift.NewTSet(" << type_to_enum(etype) << ", " << val.size() << ")" << endl <<
-      indent() << "{" << endl;
-    indent_up();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string v(tmp("v"));
-      out <<
-        indent() << v << " := " << render_const_value(etype, *v_iter, v) << endl <<
-        indent() << name << ".Add(" << v << ")" << endl;
+            "map[" << type_to_go_type(ktype) << "]" << type_to_go_type(vtype) << "{" << endl;
+        indent_up();
+        map<t_const_value*, t_const_value*>::const_iterator v_iter;
+
+        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+            out <<
+                indent() << render_const_value(ktype, v_iter->first, name) << ": " <<
+                render_const_value(vtype, v_iter->second, name) << "," << endl;
+        }
+
+        indent_down();
+        out <<
+            indent() << "}";
+    } else if (type->is_list()) {
+        t_type* etype = ((t_list*)type)->get_elem_type();
+        const vector<t_const_value*>& val = value->get_list();
+        out <<
+            "[]" << type_to_go_type(etype) << "{" << endl;
+        indent_up();
+        vector<t_const_value*>::const_iterator v_iter;
+
+        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+            out <<
+                indent() << render_const_value(etype, *v_iter, name) << ", ";
+        }
+
+        indent_down();
+        out <<
+            indent() << "}";
+    } else if (type->is_set()) {
+        t_type* etype = ((t_set*)type)->get_elem_type();
+        const vector<t_const_value*>& val = value->get_list();
+        out <<
+            "map[" << type_to_go_key_type(etype) << "]bool{" << endl;
+        indent_up();
+        vector<t_const_value*>::const_iterator v_iter;
+
+        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+            out <<
+                indent() << render_const_value(etype, *v_iter, name) << ": true," << endl;
+
+        }
+
+        indent_down();
+        out <<
+            indent() << "}";
+    } else {
+        throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
     }
-    indent_down();
-    out <<
-      indent() << "}" << endl;
-  } else {
-    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
-  }
 
-  return out.str();
+    return out.str();
 }
 
 /**
  * Generates a go struct
  */
-void t_go_generator::generate_struct(t_struct* tstruct) {
-  generate_go_struct(tstruct, false);
+void t_go_generator::generate_struct(t_struct* tstruct)
+{
+    generate_go_struct(tstruct, false);
 }
 
 /**
@@ -757,16 +850,18 @@ void t_go_generator::generate_struct(t_struct* tstruct) {
  *
  * @param txception The struct definition
  */
-void t_go_generator::generate_xception(t_struct* txception) {
-  generate_go_struct(txception, true);
+void t_go_generator::generate_xception(t_struct* txception)
+{
+    generate_go_struct(txception, true);
 }
 
 /**
  * Generates a go struct
  */
 void t_go_generator::generate_go_struct(t_struct* tstruct,
-                                        bool is_exception) {
-  generate_go_struct_definition(f_types_, tstruct, is_exception);
+                                        bool is_exception)
+{
+    generate_go_struct_definition(f_types_, tstruct, is_exception);
 }
 
 /**
@@ -775,459 +870,472 @@ void t_go_generator::generate_go_struct(t_struct* tstruct,
  * @param tstruct The struct definition
  */
 void t_go_generator::generate_go_struct_definition(ofstream& out,
-                                                   t_struct* tstruct,
-                                                   bool is_exception,
-                                                   bool is_result) {
-
-  (void) is_exception;
-  const vector<t_field*>& members = tstruct->get_members();
-  const vector<t_field*>& sorted_members = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  generate_go_docstring(out, tstruct);
-  std::string tstruct_name(publicize(tstruct->get_name()));
-  out << 
-    indent() << "type " << tstruct_name << " struct {" << endl <<
-    indent() << "  thrift.TStruct" << endl;
-
-  /*
-     Here we generate the structure specification for the fastbinary codec.
-     These specifications have the following structure:
-     thrift_spec -> tuple of item_spec
-     item_spec -> nil | (tag, type_enum, name, spec_args, default)
-     tag -> integer
-     type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
-     name -> string_literal
-     default -> nil  # Handled by __init__
-     spec_args -> nil  # For simple types
-                | (type_enum, spec_args)  # Value type for list/set
-                | (type_enum, spec_args, type_enum, spec_args)
-                  # Key and value for map
-                | (class_name, spec_args_ptr) # For struct/exception
-     class_name -> identifier  # Basically a pointer to the class
-     spec_args_ptr -> expression  # just class_name.spec_args
-
-     TODO(dreiss): Consider making this work for structs with negative tags.
-  */
-
-  // TODO(dreiss): Look into generating an empty tuple instead of nil
-  // for structures with no members.
-  // TODO(dreiss): Test encoding of structs where some inner structs
-  // don't have thrift_spec.
-  indent_up();
-  if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
-    int sorted_keys_pos = 0;
-    for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
-
-      for (; sorted_keys_pos != (*m_iter)->get_key(); sorted_keys_pos++) {
-        if (sorted_keys_pos != 0) {
-          indent(out) << "_ interface{} \"" << escape_string((*m_iter)->get_name()) << "\"; // nil # " << sorted_keys_pos << endl;
-        }
-      }
-      t_type* fieldType = (*m_iter)->get_type();
-      string goType(type_to_go_type(fieldType));
-      indent(out) << publicize(variable_name_to_go_name((*m_iter)->get_name())) << " " 
-                  << goType << " \"" << escape_string((*m_iter)->get_name())
-                  << "\"; // " << sorted_keys_pos
-                  << endl;
+        t_struct* tstruct,
+        bool is_exception,
+        bool is_result)
+{
+    const vector<t_field*>& members = tstruct->get_members();
+    const vector<t_field*>& sorted_members = tstruct->get_sorted_members();
+    vector<t_field*>::const_iterator m_iter;
+
+    std::string tstruct_name(publicize(tstruct->get_name()));
+    out <<
+        indent() << "type " << tstruct_name << " struct {" << endl;
+    /*
+       Here we generate the structure specification for the fastbinary codec.
+       These specifications have the following structure:
+       thrift_spec -> tuple of item_spec
+       item_spec -> nil | (tag, type_enum, name, spec_args, default)
+       tag -> integer
+       type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
+       name -> string_literal
+       default -> nil  # Handled by __init__
+       spec_args -> nil  # For simple types
+                  | (type_enum, spec_args)  # Value type for list/set
+                  | (type_enum, spec_args, type_enum, spec_args)
+                    # Key and value for map
+                  | (class_name, spec_args_ptr) # For struct/exception
+       class_name -> identifier  # Basically a pointer to the class
+       spec_args_ptr -> expression  # just class_name.spec_args
+
+       TODO(dreiss): Consider making this work for structs with negative tags.
+    */
+    // TODO(dreiss): Look into generating an empty tuple instead of nil
+    // for structures with no members.
+    // TODO(dreiss): Test encoding of structs where some inner structs
+    // don't have thrift_spec.
+    indent_up();
+
+    if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
+        int sorted_keys_pos = 0;
+
+        for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
+            for (; sorted_keys_pos != (*m_iter)->get_key(); sorted_keys_pos++) {
+                if (sorted_keys_pos != 0) {
+                    indent(out) << "// unused field # " << sorted_keys_pos << endl;
+                }
+            }
 
-      sorted_keys_pos ++;
+            t_type* fieldType = (*m_iter)->get_type();
+            string goType(type_to_go_type(fieldType));
+
+            indent(out) << publicize(variable_name_to_go_name((*m_iter)->get_name())) << " "
+                        << goType << " `thrift:\""
+                        << escape_string((*m_iter)->get_name())
+                        << "," << sorted_keys_pos;
+
+            if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
+                out << ",required";
+            }
+
+            out << "\"`" << endl;
+            sorted_keys_pos ++;
+        }
+    } else {
+        for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+            // This fills in default values, as opposed to nulls
+            out <<
+                indent() << publicize((*m_iter)->get_name()) << " " <<
+                type_to_go_type((*m_iter)->get_type()) << endl;
+        }
     }
 
-  } else {
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      // This fills in default values, as opposed to nulls
-      out <<
-        indent() << publicize((*m_iter)->get_name()) << " " <<
-                    type_to_enum((*m_iter)->get_type()) << endl;
-    }
-  }
-  indent_down();
-  out <<
-    indent() << "}" << endl << endl <<
-    indent() << "func New" << tstruct_name << "() *" << tstruct_name << " {" << endl <<
-    indent() << "  output := &" << tstruct_name << "{" << endl <<
-    indent() << "    TStruct:thrift.NewTStruct(\"" << escape_string(tstruct->get_name()) << "\", []thrift.TField{" << endl;
-  indent_up();
-  indent_up();
-  for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    string thrift_name((*m_iter)->get_name());
+    indent_down();
     out <<
-      indent() << "thrift.NewTField(\"" << escape_string(thrift_name) << "\", " << type_to_enum((*m_iter)->get_type()) << ", "<< (*m_iter)->get_key() << ")," << endl;
-  }
-  out << 
-    indent() << "})," << endl;
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    indent() << "{" << endl;
-  indent_up();
-  
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    // Initialize fields
-    //t_type* type = (*m_iter)->get_type();
-    string fieldName(publicize((*m_iter)->get_name()));
-    string fullFieldName = "output." + fieldName;
-    if ((*m_iter)->get_value() != NULL) {
-      out <<
-        indent() << fullFieldName << " = " <<
-        render_field_default_value(*m_iter, fullFieldName) << endl;
-    }
-  }
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    indent() << "return output" << endl;
-  indent_down();
-  out <<
-    indent() << "}" << endl << endl;
-
-  generate_go_struct_reader(out, tstruct, tstruct_name, is_result);
-  generate_go_struct_writer(out, tstruct, tstruct_name, is_result);
-  
-  // Printing utilities so that on the command line thrift
-  // structs look pretty like dictionaries
-  out << 
-    indent() << "func (p *" << tstruct_name << ") TStructName() string {" << endl <<
-    indent() << "  return \"" << escape_string(tstruct_name) << "\"" << endl <<
-    indent() << "}" << endl << endl;
-  
-  out << 
-    indent() << "func (p *" << tstruct_name << ") ThriftName() string {" << endl <<
-    indent() << "  return \"" << escape_string(tstruct->get_name()) << "\"" << endl <<
-    indent() << "}" << endl << endl;
-  
-  out <<
-    indent() << "func (p *" << tstruct_name << ") String() string {" << endl <<
-    indent() << "  if p == nil {" << endl <<
-    indent() << "    return \"<nil>\"" << endl <<
-    indent() << "  }" << endl <<
-    indent() << "  return fmt.Sprintf(\"" << escape_string(tstruct_name) << "(%+v)\", *p)" << endl <<
-    indent() << "}" << endl << endl;
-
-  // Equality and inequality methods that compare by value
-  if(members.size() <= 0) {
-    out <<
-      indent() << "func (p *" << tstruct_name << ") CompareTo(other interface{}) (int, bool) {" << endl <<
-      indent() << "  if other == nil {" << endl <<
-      indent() << "    return 1, true" << endl <<
-      indent() << "  }" << endl <<
-      indent() << "  _, ok := other.(*" << tstruct_name << ")" << endl <<
-      indent() << "  if !ok {" << endl <<
-      indent() << "    return 0, false" << endl <<
-      indent() << "  }" << endl <<
-      indent() << "  return 0, true" << endl <<
-      indent() << "}" << endl << endl;
-  } else {
-    out <<
-      indent() << "func (p *" << tstruct_name << ") CompareTo(other interface{}) (int, bool) {" << endl <<
-      indent() << "  if other == nil {" << endl <<
-      indent() << "    return 1, true" << endl <<
-      indent() << "  }" << endl <<
-      indent() << "  data, ok := other.(*" << tstruct_name << ")" << endl <<
-      indent() << "  if !ok {" << endl <<
-      indent() << "    return 0, false" << endl <<
-      indent() << "  }" << endl;
-    indent_up();
-    for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      t_type* orig_type = (*m_iter)->get_type();
-      t_type* type = get_true_type(orig_type);
-      string field_name(publicize(variable_name_to_go_name((*m_iter)->get_name())));
-      if(type->is_base_type() || type->is_enum()) {
-        if(type->is_bool()) {
-          out <<
-            indent() << "if cmp := thrift.CompareBool(p." << field_name << ", data." << field_name << "); cmp != 0 {" << endl <<
-            indent() << "  return cmp, true" << endl <<
-            indent() << "}" << endl;
-        } else {
-          out <<
-            indent() << "if p." << field_name << " != data." << field_name << " {" << endl <<
-            indent() << "  if p." << field_name << " < data." << field_name << " {" << endl <<
-            indent() << "    return -1, true" << endl <<
-            indent() << "  }" << endl <<
-            indent() << "  return 1, true" << endl <<
-            indent() << "}" << endl;
+        indent() << "}" << endl << endl <<
+        indent() << "func New" << tstruct_name << "() *" << tstruct_name << " {" << endl <<
+        indent() << "  return &" << tstruct_name << "{";
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        // Initialize fields
+        const string base_field_name = (*m_iter)->get_name();
+        const string escaped_field_name = escape_string(base_field_name);
+        const string go_safe_name = variable_name_to_go_name(escaped_field_name);
+        const string publicized_name = publicize(go_safe_name);
+        const t_type* type = get_true_type((*m_iter)->get_type());
+        const bool has_default_value = (*m_iter)->get_value() != NULL;
+        const bool type_is_enum = type->is_enum();
+
+        if (has_default_value) {
+            out << endl << indent() << publicized_name << ": " << render_field_default_value(*m_iter, base_field_name) << "," << endl;
+        } else if (type_is_enum) {
+            out << endl << indent() << publicized_name << ": math.MinInt32 - 1, // unset sentinal value" << endl;
         }
-      } else if(type->is_container() || type->is_struct() || type->is_xception()) {
-        out <<
-          indent() << "if cmp, ok := p." << field_name << ".CompareTo(data." << field_name << "); !ok || cmp != 0 {" << endl <<
-          indent() << "  return cmp, ok" << endl <<
-          indent() << "}" << endl;
-      } else {
-        throw "INVALID TYPE IN generate_go_struct_definition: " + type->get_name();
-      }
     }
-    indent_down();
-    out << 
-      indent() << "  return 0, true" << endl <<
-      indent() << "}" << endl << endl;
-  }
-  
-  // Equality and inequality methods that compare by value
-  out <<
-    indent() << "func (p *" << tstruct_name << ") AttributeByFieldId(id int) interface{} {" << endl <<
-    indent() << "  switch id {" << endl <<
-    indent() << "  default: return nil" << endl;
-  indent_up();
-  for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    string field_name(publicize(variable_name_to_go_name((*m_iter)->get_name())));
-    out <<
-      indent() << "case " << (*m_iter)->get_key() << ": return p." << field_name << endl;
-  }
-  indent_down();
-  out <<
-    indent() << "  }" << endl <<
-    indent() << "  return nil" << endl <<
-    indent() << "}" << endl << endl;
-  
-  out <<
-    indent() << "func (p *" << tstruct_name << ") TStructFields() thrift.TFieldContainer {" << endl <<
-    indent() << "  return thrift.NewTFieldContainer([]thrift.TField{" << endl;
-  indent_up();
-  indent_up();
-  for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    string thrift_name((*m_iter)->get_name());
+
+    out << "}" << endl;
+    out << "}" << endl << endl;
+    generate_isset_helpers(out, tstruct, tstruct_name, is_result);
+    generate_go_struct_reader(out, tstruct, tstruct_name, is_result);
+    generate_go_struct_writer(out, tstruct, tstruct_name, is_result);
+
     out <<
-      indent() << "thrift.NewTField(\"" << escape_string(thrift_name) << "\", " << type_to_enum((*m_iter)->get_type()) << ", "<< (*m_iter)->get_key() << ")," << endl;
-  }
-  out << 
-    indent() << "})" << endl;
-  indent_down();
-  indent_down();
-  out <<
-    indent() << "}" << endl << endl;
+        indent() << "func (p *" << tstruct_name << ") String() string {" << endl <<
+        indent() << "  if p == nil {" << endl <<
+        indent() << "    return \"<nil>\"" << endl <<
+        indent() << "  }" << endl <<
+        indent() << "  return fmt.Sprintf(\"" << escape_string(tstruct_name) << "(%+v)\", *p)" << endl <<
+        indent() << "}" << endl << endl;
+
+}
+
+/**
+ * Generates the IsSet helper methods for a struct
+ */
+void t_go_generator::generate_isset_helpers(ofstream& out,
+        t_struct* tstruct,
+        const string& tstruct_name,
+        bool is_result)
+{
+    const vector<t_field*>& fields = tstruct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const string escaped_tstruct_name(escape_string(tstruct->get_name()));
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        t_type* type = get_true_type((*f_iter)->get_type());
+
+        if ((*f_iter)->get_req() == t_field::T_OPTIONAL || type->is_enum()) {
+            const string field_name(publicize(variable_name_to_go_name(escape_string((*f_iter)->get_name()))));
+            t_const_value* field_default_value = (*f_iter)->get_value();
+            out <<
+                indent() << "func (p *" << tstruct_name << ") IsSet" << field_name << "() bool {" << endl;
+            indent_up();
+            string s_check_value;
+            int64_t i_check_value;
+            double d_check_value;
+
+            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:
+                    if (((t_base_type*)type)->is_binary()) {
+                        // ignore default value for binary
+                        out <<
+                            indent() << "return p." << field_name << " != nil" << endl;
+                    } else {
+                        s_check_value = (field_default_value == NULL) ? "\"\"" : render_const_value(type, field_default_value, tstruct_name);
+                        out <<
+                            indent() << "return p." << field_name << " != " << s_check_value << endl;
+                    }
+
+                    break;
+
+                case t_base_type::TYPE_BOOL:
+                    s_check_value = (field_default_value != NULL && field_default_value->get_integer() > 0) ? "true" : "false";
+                    out <<
+                        indent() << "return p." << field_name << " != " << s_check_value << endl;
+                    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:
+                    i_check_value = (field_default_value == NULL) ? 0 : field_default_value->get_integer();
+                    out <<
+                        indent() << "return p." << field_name << " != " << i_check_value << endl;
+                    break;
+
+                case t_base_type::TYPE_DOUBLE:
+                    d_check_value = (field_default_value == NULL) ? 0.0 : field_default_value->get_double();
+                    out <<
+                        indent() << "return p." << field_name << " != " << d_check_value << endl;
+                    break;
+
+                default:
+                    throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+                }
+            } else if (type->is_enum()) {
+                out << indent() << "return int64(p." << field_name << ") != "
+                    << "math.MinInt32 - 1" << endl;
+            } else if (type->is_struct() || type->is_xception()) {
+                out <<
+                    indent() << "return p." << field_name << " != nil" << endl;
+            } else if (type->is_list() || type->is_set()) {
+                if (field_default_value != NULL && field_default_value->get_list().size() > 0) {
+                    out <<
+                        indent() << "return p." << field_name << " != nil" << endl;
+                } else {
+                    out <<
+                        indent() << "return p." << field_name << " != nil && len(p." << field_name << ") > 0" << endl;
+                }
+            } else if (type->is_map()) {
+                if (field_default_value != NULL && field_default_value->get_map().size() > 0) {
+                    out <<
+                        indent() << "return p." << field_name << " != nil" << endl;
+                } else {
+                    out <<
+                        indent() << "return p." << field_name << " != nil && len(p." << field_name << ") > 0" << endl;
+                }
+            } else {
+                throw "CANNOT GENERATE ISSET HELPERS FOR TYPE: " + type->get_name();
+            }
+
+            indent_down();
+            out <<
+                indent() << "}" << endl << endl;
+        }
+    }
 }
 
 /**
  * Generates the read method for a struct
  */
 void t_go_generator::generate_go_struct_reader(ofstream& out,
-                                                t_struct* tstruct,
-                                                const string& tstruct_name,
-                                                bool is_result) {
-  (void) is_result;
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  string escaped_tstruct_name(escape_string(tstruct->get_name()));
-
-  out <<
-    indent() << "func (p *" << tstruct_name << ") Read(iprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
-  indent_up();
-
-  out <<
-    indent() << "_, err = iprot.ReadStructBegin()" << endl <<
-    indent() << "if err != nil { return thrift.NewTProtocolExceptionReadStruct(p.ThriftName(), err); }" << endl;
-
-  // Loop over reading in fields
-  indent(out) << "for {" << endl;
-  indent_up();
-
-  // Read beginning field marker
-  out <<
-    indent() << "fieldName, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()" << endl <<
-    indent() << "if fieldId < 0 {" << endl <<
-    indent() << "  fieldId = int16(p.FieldIdFromFieldName(fieldName))" << endl <<
-    indent() << "} else if fieldName == \"\" {" << endl <<
-    indent() << "  fieldName = p.FieldNameFromFieldId(int(fieldId))" << endl <<
-    indent() << "}" << endl <<
-    indent() << "if fieldTypeId == thrift.GENERIC {" << endl <<
-    indent() << "  fieldTypeId = p.FieldFromFieldId(int(fieldId)).TypeId()" << endl <<
-    indent() << "}" << endl <<
-    indent() << "if err != nil {" << endl <<
-    indent() << "  return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)" << endl <<
-    indent() << "}" << endl;
-
-  // Check for field STOP marker and break
-  out <<
-    indent() << "if fieldTypeId == thrift.STOP { break; }" << endl;
-
-  // Switch statement on the field we are reading
-  bool first = true;
-
-  // Generate deserialization code for known cases
-  int32_t field_id = -1;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    field_id = (*f_iter)->get_key();
-    if (first) {
-      first = false;
-      indent(out);
-    } else {
-      indent(out) << "} else ";
-    }
-    out << "if fieldId == " << field_id << " || fieldName == \"" << escape_string((*f_iter)->get_name()) << "\" {" << endl;
+        t_struct* tstruct,
+        const string& tstruct_name,
+        bool is_result)
+{
+    const vector<t_field*>& fields = tstruct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    string escaped_tstruct_name(escape_string(tstruct->get_name()));
+    out <<
+        indent() << "func (p *" << tstruct_name << ") Read(iprot thrift.TProtocol) error {" << endl;
     indent_up();
     out <<
-      indent() << "if fieldTypeId == " << type_to_enum((*f_iter)->get_type()) << " {" << endl <<
-      indent() << "  err = p.ReadField" << field_id << "(iprot)" << endl <<
-      indent() << "  if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
-      indent() << "} else if fieldTypeId == thrift.VOID {" << endl <<
-      indent() << "  err = iprot.Skip(fieldTypeId)" << endl <<
-      indent() << "  if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
-      indent() << "} else {" << endl <<
-      indent() << "  err = p.ReadField" << field_id << "(iprot)" << endl <<
-      indent() << "  if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
-      indent() << "}" << endl;
-    indent_down();
-  }
-
-  // In the default case we skip the field
-  if (first) {
+        indent() << "if _, err := iprot.ReadStructBegin(); err != nil {" << endl <<
+        indent() << "  return fmt.Errorf(\"%T read error\", p)" << endl <<
+        indent() << "}" << endl;
+    // Loop over reading in fields
+    indent(out) << "for {" << endl;
+    indent_up();
+    // Read beginning field marker
     out <<
-      indent() << "err = iprot.Skip(fieldTypeId)" << endl <<
-      indent() << "if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl;
-  } else {
+        indent() << "_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()" << endl <<
+        indent() << "if err != nil {" << endl <<
+        indent() << "  return fmt.Errorf(\"%T field %d read error: %s\", p, fieldId, err)" << endl <<
+        indent() << "}" << endl;
+    // Check for field STOP marker and break
     out <<
-      indent() << "} else {" << endl <<
-      indent() << "  err = iprot.Skip(fieldTypeId)" << endl <<
-      indent() << "  if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
-      indent() << "}" << endl;
-  }
-  // Read field end marker
-  out <<
-    indent() << "err = iprot.ReadFieldEnd()" << endl <<
-    indent() << "if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    indent() << "err = iprot.ReadStructEnd()" << endl <<
-    indent() << "if err != nil { return thrift.NewTProtocolExceptionReadStruct(p.ThriftName(), err); }" << endl <<
-    indent() << "return err" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl << endl;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    string field_type_name(publicize((*f_iter)->get_type()->get_name()));
-    string field_name(publicize((*f_iter)->get_name()));
-    int32_t field_id = (*f_iter)->get_key();
+        indent() << "if fieldTypeId == thrift.STOP { break; }" << endl;
+    // Switch statement on the field we are reading
+    bool first = true;
+    string thriftFieldTypeId;
+    // Generate deserialization code for known cases
+    int32_t field_id = -1;
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        field_id = (*f_iter)->get_key();
+
+        if (first) {
+            first = false;
+            indent(out) << "switch fieldId {" << endl;
+        }
+
+        // if negative id, ensure we generate a valid method name
+        string field_method_prefix("readField");
+
+        if (field_id < 0) {
+            field_method_prefix += "_";
+            field_id *= -1;
+        }
+
+        indent_up();
+        out << "case " << field_id << ":" << endl;
+        thriftFieldTypeId = type_to_enum((*f_iter)->get_type());
+
+        if (thriftFieldTypeId == "thrift.BINARY") {
+            thriftFieldTypeId = "thrift.STRING";
+        }
+
+        out <<
+            indent() << "if err := p." << field_method_prefix << field_id << "(iprot); err != nil {" << endl <<
+            indent() << "  return err" << endl <<
+            indent() << "}" << endl;
+        indent_down();
+    }
+
+    // In the default case we skip the field
+    if (!first) {
+        out <<
+            indent() << "default:" << endl <<
+            indent() << "  if err := iprot.Skip(fieldTypeId); err != nil {" << endl <<
+            indent() << "    return err" << endl <<
+            indent() << "  }" << endl <<
+            indent() << "}" << endl;
+    }
+
+    // Read field end marker
     out <<
-      indent() << "func (p *" << tstruct_name << ") ReadField" << field_id << "(iprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
-    indent_up();
-    generate_deserialize_field(out, *f_iter, false, "p.");
+        indent() << "if err := iprot.ReadFieldEnd(); err != nil {" << endl <<
+        indent() << "  return err" << endl <<
+        indent() << "}" << endl;
     indent_down();
     out <<
-      indent() << "  return err" << endl <<
-      indent() << "}" << endl << endl <<
-      indent() << "func (p *" << tstruct_name << ") ReadField" << field_name << "(iprot thrift.TProtocol) (thrift.TProtocolException) {" << endl <<
-      indent() << "  return p.ReadField" << field_id << "(iprot)" << endl <<
-      indent() << "}" << endl << endl;
-  }
+        indent() << "}" << endl <<
+        indent() << "if err := iprot.ReadStructEnd(); err != nil {" << endl <<
+        indent() << "  return fmt.Errorf(\"%T read struct end error: %s\", p, err)" << endl <<
+        indent() << "}" << endl <<
+        indent() << "return nil" << endl;
+    indent_down();
+    out <<
+        indent() << "}" << endl << endl;
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        string field_type_name(publicize((*f_iter)->get_type()->get_name()));
+        string field_name(publicize((*f_iter)->get_name()));
+        string field_method_prefix("readField");
+        int32_t field_id = (*f_iter)->get_key();
+
+        if (field_id < 0) {
+            field_method_prefix += "_";
+            field_id *= -1;
+        }
+
+        out <<
+            indent() << "func (p *" << tstruct_name << ")  " << field_method_prefix << field_id << "(iprot thrift.TProtocol) error {" << endl;
+        indent_up();
+        generate_deserialize_field(out, *f_iter, false, "p.");
+        indent_down();
+        out <<
+            indent() << "  return nil" << endl <<
+            indent() << "}" << endl << endl;
+    }
 }
 
 void t_go_generator::generate_go_struct_writer(ofstream& out,
-                                               t_struct* tstruct,
-                                               const string& tstruct_name,
-                                               bool is_result) {
-  string name(tstruct->get_name());
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  indent(out) <<
-    "func (p *" << tstruct_name << ") Write(oprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
-  indent_up();
-
-  out << 
-    indent() << "err = oprot.WriteStructBegin(\"" << name << "\")" << endl <<
-    indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteStruct(" <<
-                          "p.ThriftName(), err); }" << endl;
-  
-  string field_name;
-  string escape_field_name;
-  int32_t fieldId = -1;
-  if (is_result && fields.size()) {
+        t_struct* tstruct,
+        const string& tstruct_name,
+        bool is_result)
+{
+    string name(tstruct->get_name());
+    const vector<t_field*>& fields = tstruct->get_sorted_members();
+    vector<t_field*>::const_iterator f_iter;
+    indent(out) <<
+                "func (p *" << tstruct_name << ") Write(oprot thrift.TProtocol) error {" << endl;
+    indent_up();
     out <<
-      indent() << "switch {" << endl;
-    vector<t_field*>::const_reverse_iterator fr_iter;
-    for (fr_iter = fields.rbegin(); fr_iter != fields.rend(); ++fr_iter) {
-      field_name = (*fr_iter)->get_name();
-      fieldId = (*fr_iter)->get_key();
-      if(can_be_nil((*fr_iter)->get_type()) && fieldId != 0) {
+        indent() << "if err := oprot.WriteStructBegin(\"" << name << "\"); err != nil {" << endl <<
+        indent() << "  return fmt.Errorf(\"%T write struct begin error: %s\", p, err) }" << endl;
+
+    string field_name;
+    string escape_field_name;
+    t_const_value* field_default_value;
+    t_field::e_req field_required;
+    bool field_can_be_nil = false;
+    int32_t field_id = -1;
+
+    if (is_result && fields.size()) {
         out <<
-          indent() << "case p." << publicize(variable_name_to_go_name(field_name)) << " != nil:" << endl <<
-          indent() << "  if err = p.WriteField" << fieldId << "(oprot); err != nil {" << endl <<
-          indent() << "    return err" << endl <<
-          indent() << "  }" << endl;
-      } else {
+            indent() << "switch {" << endl;
+        vector<t_field*>::const_reverse_iterator fr_iter;
+
+        for (fr_iter = fields.rbegin(); fr_iter != fields.rend(); ++fr_iter) {
+            string field_method_prefix("writeField");
+            field_name = (*fr_iter)->get_name();
+            field_id = (*fr_iter)->get_key();
+
+            if (field_id < 0) {
+                field_method_prefix += "_";
+                field_id *= -1;
+            }
+
+            if (can_be_nil((*fr_iter)->get_type()) && field_id != 0) {
+                out <<
+                    indent() << "case p." << publicize(variable_name_to_go_name(field_name)) << " != nil:" << endl <<
+                    indent() << "  if err := p." << field_method_prefix << field_id << "(oprot); err != nil { return err }" << endl;
+            } else {
+                out <<
+                    indent() << "default:" << endl <<
+                    indent() << "  if err := p." << field_method_prefix << field_id << "(oprot); err != nil { return err }" << endl;
+            }
+        }
+
         out <<
-          indent() << "default:" << endl <<
-          indent() << "  if err = p.WriteField" << fieldId << "(oprot); err != nil {" << endl <<
-          indent() << "    return err" << endl <<
-          indent() << "  }" << endl;
-      }
-    }
-    out <<
-      indent() << "}" << endl;
-  } else {
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      field_name = (*f_iter)->get_name();
-      escape_field_name = escape_string(field_name);
-      fieldId = (*f_iter)->get_key();
-      out <<
-        indent() << "err = p.WriteField" << fieldId << "(oprot)" << endl <<
-        indent() << "if err != nil { return err }" << endl;
-    }
-  }
-
-  // Write the struct map
-  out <<
-    indent() << "err = oprot.WriteFieldStop()" << endl <<
-    indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteField(-1, \"STOP\", p.ThriftName(), err); }" << endl <<
-    indent() << "err = oprot.WriteStructEnd()" << endl <<
-    indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteStruct(" <<
-                          "p.ThriftName(), err); }" << endl <<
-    indent() << "return err" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl << endl;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    fieldId = (*f_iter)->get_key();
-    field_name = (*f_iter)->get_name();
-    escape_field_name = escape_string(field_name);
-    out <<
-      indent() << "func (p *" << tstruct_name << ") WriteField" << fieldId << "(oprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
-    indent_up();
-    // Write field header
-    if (can_be_nil((*f_iter)->get_type())) {
-      out <<
-        indent() << "if p." << publicize(variable_name_to_go_name(field_name)) << " != nil {" << endl;
-      indent_up();
+            indent() << "}" << endl;
+    } else {
+        for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+            string field_method_prefix("writeField");
+            field_name = (*f_iter)->get_name();
+            escape_field_name = escape_string(field_name);
+            field_id = (*f_iter)->get_key();
+
+            if (field_id < 0) {
+                field_method_prefix += "_";
+                field_id *= -1;
+            }
+
+            out <<
+                indent() << "if err := p." << field_method_prefix << field_id << "(oprot); err != nil { return err }" << endl;
+
+        }
     }
+
+    // Write the struct map
     out <<
-      indent() << "err = oprot.WriteFieldBegin(\"" <<
-                            escape_field_name << "\", " <<
-                            type_to_enum((*f_iter)->get_type()) << ", " <<
-                            fieldId << ")" << endl <<
-      indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteField(" <<
-                            fieldId << ", \"" <<
-                            escape_field_name << "\", " <<
-                            "p.ThriftName(), err); }" << endl;
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "p.");
-    
-    // Write field closer
+        indent() << "if err := oprot.WriteFieldStop(); err != nil {" << endl <<
+        indent() << "  return fmt.Errorf(\"%T write field stop error: %s\", err) }" << endl <<
+        indent() << "if err := oprot.WriteStructEnd(); err != nil {" << endl <<
+        indent() << "  return fmt.Errorf(\"%T write struct stop error: %s\", err) }" << endl <<
+        indent() << "return nil" << endl;
+    indent_down();
     out <<
-      indent() << "err = oprot.WriteFieldEnd()" << endl <<
-      indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteField(" <<
-                            fieldId << ", \"" <<
-                            escape_field_name << "\", " <<
-                            "p.ThriftName(), err); }" << endl;
+        indent() << "}" << endl << endl;
 
-    if (can_be_nil((*f_iter)->get_type())) {
-      indent_down();
-      out <<
-        indent() << "}" << endl;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        string field_method_prefix("writeField");
+        field_id = (*f_iter)->get_key();
+        field_name = (*f_iter)->get_name();
+        escape_field_name = escape_string(field_name);
+        field_default_value = (*f_iter)->get_value();
+        field_required = (*f_iter)->get_req();
+        field_can_be_nil = can_be_nil((*f_iter)->get_type());
+
+        if (field_id < 0) {
+            field_method_prefix += "_";
+            field_id *= -1;
+        }
+
+        out <<
+            indent() << "func (p *" << tstruct_name << ") " << field_method_prefix << field_id << "(oprot thrift.TProtocol) (err error) {" << endl;
+        indent_up();
+
+        // Write field header
+        if (field_can_be_nil) {
+            out <<
+                indent() << "if p." << publicize(variable_name_to_go_name(field_name)) << " != nil {" << endl;
+            indent_up();
+        }
+
+        if (field_required == t_field::T_OPTIONAL || (*f_iter)->get_type()->is_enum()) {
+            out <<
+                indent() << "if p.IsSet" << publicize(variable_name_to_go_name(field_name)) << "() {" << endl;
+            indent_up();
+        }
+
+        out <<
+            indent() << "if err := oprot.WriteFieldBegin(\"" <<
+            escape_field_name << "\", " <<
+            type_to_enum((*f_iter)->get_type()) << ", " <<
+            field_id << "); err != nil {" << endl <<
+            indent() << "  return fmt.Errorf(\"%T write field begin error " << field_id << ":" << escape_field_name << ": %s\", p, err); }" << endl;
+
+        // Write field contents
+        generate_serialize_field(out, *f_iter, "p.");
+
+
+        // Write field closer
+        out <<
+            indent() << "if err := oprot.WriteFieldEnd(); err != nil {" << endl <<
+            indent() << "  return fmt.Errorf(\"%T write field end error " << field_id << ":" << escape_field_name << ": %s\", p, err); }" << endl;
+
+        if (field_required == t_field::T_OPTIONAL || (*f_iter)->get_type()->is_enum()) {
+            indent_down();
+            out <<
+                indent() << "}" << endl;
+        }
+
+        if (field_can_be_nil) {
+            indent_down();
+            out <<
+                indent() << "}" << endl;
+        }
+
+        indent_down();
+        out <<
+            indent() << "  return err" << endl <<
+            indent() << "}" << endl << endl;
     }
-    indent_down();
-    out <<
-      indent() << "  return err" << endl <<
-      indent() << "}" << endl << endl <<
-      indent() << "func (p *" << tstruct_name << ") WriteField" << publicize(field_name) << "(oprot thrift.TProtocol) (thrift.TProtocolException) {" << endl <<
-      indent() << "  return p.WriteField" << fieldId << "(oprot)" << endl <<
-      indent() << "}" << endl << endl;
-  }
 }
 
 /**
@@ -1235,38 +1343,31 @@ void t_go_generator::generate_go_struct_writer(ofstream& out,
  *
  * @param tservice The service definition
  */
-void t_go_generator::generate_service(t_service* tservice) {
-  string f_service_name = package_dir_+"/"+service_name_+".go";
-  f_service_.open(f_service_name.c_str());
+void t_go_generator::generate_service(t_service* tservice)
+{
+    string f_service_name = package_dir_ + "/" + underscore(service_name_) + ".go";
+    f_service_.open(f_service_name.c_str());
+    f_service_ <<
+               go_autogen_comment() <<
+               go_package() <<
+               go_imports_begin();
 
-  f_service_ <<
-    go_autogen_comment() <<
-    go_package() <<
-    go_imports();
+    if (tservice->get_extends() != NULL) {
+        f_service_ << "\t\"" << gen_package_prefix_ + get_real_go_module(tservice->get_extends()->get_program()) << "\"\n";
+    }
 
-  if (tservice->get_extends() != NULL) {
-    f_service_ <<
-      "import \"thriftlib/" << get_real_go_module(tservice->get_extends()->get_program()) << "\"" << endl;
-  }
-
-  f_service_ <<
-                "import (" << endl <<
-    indent() << "        \"os\"" << endl <<
-    indent() << ")" << endl << endl <<
-    render_fastbinary_includes();
-
-  f_service_ << endl;
-
-  // Generate the three main parts of the service (well, two for now in PHP)
-  generate_service_interface(tservice);
-  generate_service_client(tservice);
-  generate_service_server(tservice);
-  generate_service_helpers(tservice);
-  generate_

<TRUNCATED>