docs: def concat(self, other_datatable, inplace=False):
          """
          Concatenates two DataTables together, as long as column names
          are identical (ignoring order). The resulting DataTable's columns
          are in the order of the table whose `concat` method was called.
          """
          if not isinstance(other_datatable, DataTable):
              raise TypeError("`concat` requires a DataTable, not a %s" %
                              type(other_datatable))
  
          # if the self table is empty, we can just return the other table
          # if we need to do it in place, we just copy over the columns
          if not self.fields:
              if inplace:
                  for field in other_datatable.fields:
                      self[field] = other_datatable[field]
                  return self
              else:
                  return other_datatable
          if not other_datatable.fields:
              return self
  
          if set(self.fields) != set(other_datatable.fields):
              raise Exception("Columns do not match:\nself: %s\nother: %s" %
                              (self.fields, other_datatable.fields))
  
          # TODO: this will fail if we're concatenating one table with `arrays`
          # TODO: to a table with lists, even if everything else is compatible
          # TODO: a TypeError is thrown
          # TODO: if we run through and just append, this may be faster and
          # TODO: more memory-efficient for large lists, as well as compatible
          # TODO: with arrays
          if inplace:
              for field in self.fields:
                  self.__data[field] = self[field] + other_datatable[field]
              return self
          else:
              new_table = DataTable()
              for field in self.fields:
                  new_table[field] = self[field] + other_datatable[field]
              return new_table