docs: function RecordType(attrs, opts) {
    // Force creation of the options object in case we need to register this
    // record's name.
    opts = opts || {};
  
    // Save the namespace to restore it as we leave this record's scope.
    var namespace = opts.namespace;
    if (attrs.namespace !== undefined) {
      opts.namespace = attrs.namespace;
    } else if (attrs.name) {
      // Fully qualified names' namespaces are used when no explicit namespace
      // attribute was specified.
      var match = /^(.*)\.[^.]+$/.exec(attrs.name);
      if (match) {
        opts.namespace = match[1];
      }
    }
    Type.call(this, attrs, opts);
  
    if (!Array.isArray(attrs.fields)) {
      throw new Error(f('non-array record fields: %j', attrs.fields));
    }
    if (utils.hasDuplicates(attrs.fields, function (f) { return f.name; })) {
      throw new Error(f('duplicate field name: %j', attrs.fields));
    }
    this._fieldsMap = {};
    this._fields = attrs.fields.map(function (f) {
      var field = new Field(f, opts);
      this._fieldsMap[field.getName()] = field;
      return field;
    }, this);
  
    this._isError = attrs.type === 'error';
    this._constructor = this._createConstructor();
    this._read = this._createReader();
    this._skip = this._createSkipper();
    this._write = this._createWriter();
    this._check = this._createChecker();
  
    opts.namespace = namespace;
  }