docs: function createInterface(params) {
          // Validate params as an object
          if (!isObject(params)) {
              throw new Error('Expected interface definition to be an object with the interface members.');
          }
          // Validate class name
          if (hasOwn(params, '$name')) {
              if (!isString(params.$name)) {
                  throw new Error('Interface name must be a string.');
              } else if (/\s+/.test(params.$name)) {
                  throw new Error('Interface name cannot have spaces.');
              }
          } else {
              params.$name = 'Unnamed';
          }
  
          checkKeywords(params);
  
          var parents,
              current,
              k,
              i,
              value,
              duplicate,
              opts = {},
              name,
              ambiguous,
              unallowed,
              interf = function () {
                  throw new Error('Interfaces cannot be instantiated.');
              };
  
          obfuscateProperty(interf, $interface, { parents: [], methods: {}, staticMethods: {}, constants: {}, check: bind(checkClass, interf) });
          interf.prototype.$name = params.$name;
  
          if (hasOwn(params, '$extends')) {
              parents = toArray(params.$extends);
              k = parents.length;
  
              // Verify argument type
              if (!k && !isArray(params.$extends)) {
                  throw new Error('$extends of "' + params.$name + '" seems to point to an nonexistent interface.');
              }
              // Verify duplicate entries
              if (k !== unique(parents).length && compact(parents).length === k) {
                  throw new Error('There are duplicate entries defined in $extends of "' + params.$name + '".');
              }
  
              for (k -= 1; k >= 0; k -= 1) {
                  current = parents[k];
  
                  // Check if it is a valid interface
                  if (!isFunction(current) || !current[$interface]) {
                      throw new Error('Specified interface in $extends at index ' +  k + ' of "' + params.$name + '" is not a valid interface.');
                  }
  
                  // Merge methods
                  duplicate = intersection(keys(interf[$interface].methods), keys(current[$interface].methods));
                  i = duplicate.length;
                  if (i) {
                      for (i -= 1; i >= 0; i -= 1) {
                          if (!isFunctionCompatible(interf[$interface].methods[duplicate[i]], current[$interface].methods[duplicate[i]]) &&
                                  !isFunctionCompatible(current[$interface].methods[duplicate[i]], interf[$interface].methods[duplicate[i]])) {
                              throw new Error('Interface "' + params.$name + '" is inheriting method "' + duplicate[i] + '" from different parents with incompatible signatures.');
                          }
                      }
                  }
                  mixIn(interf[$interface].methods, current[$interface].methods);
  
                  // Merge static methods
                  duplicate = intersection(keys(interf[$interface].staticMethods), keys(current[$interface].staticMethods));
                  i = duplicate.length;
                  if (i) {
                      for (i -= 1; i >= 0; i -= 1) {
                          if (!isFunctionCompatible(interf[$interface].staticMethods[duplicate[i]], current[$interface].staticMethods[duplicate[i]]) &&
                                  !isFunctionCompatible(current[$interface].staticMethods[duplicate[i]], interf[$interface].staticMethods[duplicate[i]])) {
                              throw new Error('Interface "' + params.$name + '" is inheriting static method "' + duplicate[i] + '" from different parents with incompatible signatures.');
                          }
                      }
                  }
                  mixIn(interf[$interface].staticMethods, current[$interface].staticMethods);
  
                  // Add interface constants
                  for (i in current[$interface].constants) {
                      if (interf[$interface].constants[i]) {
                          if (interf[i] !== current[i]) {
                              throw new Error('Interface "' + params.$name + '" is inheriting constant property "' + i + '" from different parents with different values.');
                          }
                      } else {
                          interf[$interface].constants[i] = current[$interface].constants[i];
                          assignConstant(i, current[i], interf);
                      }
                  }
  
                  // Add interface to the parents
                  interf[$interface].parents.push(current);
              }
  
              delete params.$extends;
          }
  
          // Check if the interface defines the initialize function
          if (hasOwn(params, 'initialize')) {
              throw new Error('Interface "' + params.$name + '" can\'t define the initialize method.');
          }
  
          // Parse constants
          if (hasOwn(params, '$constants')) {
              // Check argument
              if (!isObject(params.$constants)) {
                  throw new Error('$constants definition of interface "' + params.$name + '" must be an object.');
              }
  
              // Check reserved keywords
              checkKeywords(params.$constants, 'statics');
  
              // Check unallowed keywords
              unallowed = testKeywords(params.$constants);
              if (unallowed) {
                  throw new Error('$constants of interface "' + interf.prototype.$name + '" contains an unallowed keyword: "' + unallowed + '".');
              }
  
              // Check ambiguity
              if (hasOwn(params, '$statics')) {
                  ambiguous = intersection(keys(params.$constants), keys(params.$statics));
                  if (ambiguous.length) {
                      throw new Error('There are members defined in interface "' + params.$name + '" with the same name but with different modifiers: "' + ambiguous.join('", ') + '".');
                  }
              }
  
              for (k in params.$constants) {
                  addConstant(k, params.$constants[k], interf);
              }
  
              delete params.$constants;
          }
  
          // Parse statics
          if (hasOwn(params, '$statics')) {
              // Check argument
              if (!isObject(params.$statics)) {
                  throw new Error('$statics definition of interface "' + params.$name + '" must be an object.');
              }
  
              // Check reserved keywords
              checkKeywords(params.$statics, 'statics');
  
              // Check unallowed keywords
              unallowed = testKeywords(params.$statics);
              if (unallowed) {
                  throw new Error('$statics of interface "' + interf.prototype.$name + '" contains an unallowed keyword: "' + unallowed + '".');
              }
  
              opts.isStatic = true;
  
              for (k in params.$statics) {
                  value = params.$statics[k];
  
                  // Check if it is not a function
                  if (!isFunction(value) || value[$interface] || value[$class]) {
                      throw new Error('Static member "' + k + '" found in interface "' + params.$name + '" is not a function.');
                  }
  
                  addMethod(k, value, interf, opts);
              }
  
              delete opts.isStatic;
              delete params.$statics;
          }
  
          name = params.$name;
          delete params.$name;
  
          // Check unallowed keywords
          unallowed = testKeywords(params, ['$extends', '$statics', '$constants']);
          if (unallowed) {
              throw new Error('$statics of interface "' + interf.prototype.$name + '" contains an unallowed keyword: "' + unallowed + '".');
          }
  
          for (k in params) {
              addMethod(k, params[k], interf);
          }
  
          params.$name = name;
  
          // Supply .extend() to easily extend an interface
          interf.extend = extend;
  
          return interf;
      }