     return (unpackAXValue(value!) as! T)
   }
 
+  /// Sets the value of `attribute` to `value`.
+  ///
+  /// - warning: Unlike read-only methods, this method throws if the attribute doesn't exist.
+  ///
+  /// - throws:
+  ///   - `Error.AttributeUnsupported`: `attribute` isn't supported.
+  ///   - `Error.IllegalArgument`: `value` is an illegal value.
+  ///   - `Error.Failure`: A temporary failure occurred.
+  public func setAttribute(attribute: Attribute, value: Any) throws {
+    try self.setAttribute(attribute.rawValue, value: value)
+  }
+
+  public func setAttribute(attribute: String, value: Any) throws {
+    let error = AXUIElementSetAttributeValue(element, attribute, packAXValue(value))
+
+    guard error == .Success else {
+      throw error
+    }
+  }
+
+  /// Gets multiple attributes of the element at once.
+  ///
+  /// - parameter attributes: An array of attribute names. Nonexistent attributes are ignored.
+  ///
+  /// - returns: A dictionary mapping provided parameter names to their values. Parameters which
+  ///            don't exist or have no value will be absent.
+  ///
+  /// - throws: If there are any errors other than .NoValue or .AttributeUnsupported, it will throw
+  ///           the first one it encounters.
+  ///
+  /// - note: Presumably you would use this API for performance, though it's not explicitly
+  ///         documented by Apple that there is actually a difference.
+  public func getMultipleAttributes(names: Attribute...) throws -> [Attribute: Any] {
+    return try getMultipleAttributes(names)
+  }
+
+  public func getMultipleAttributes(attributes: [Attribute]) throws -> [Attribute: Any] {
+    let values = try fetchMultiAttrValues(attributes.map({ $0.rawValue }))
+    return try packMultiAttrValues(attributes, values: values)
+  }
+
+  public func getMultipleAttributes(attributes: [String]) throws -> [String: Any] {
+    let values = try fetchMultiAttrValues(attributes)
+    return try packMultiAttrValues(attributes, values: values)
+  }
+
+  // Helper: Gets list of values
+  private func fetchMultiAttrValues(attributes: [String]) throws -> [AnyObject] {
+    var valuesCF: CFArray?
+    let error = AXUIElementCopyMultipleAttributeValues(
+      element,
+      attributes,
+      AXCopyMultipleAttributeOptions(rawValue: 0),  // keep going on errors (particularly NoValue)
+      &valuesCF)
+
+    guard error == .Success else {
+      throw error
+    }
+
+    return valuesCF! as [AnyObject]
+  }
+
+  // Helper: Packs names, values into dictionary
+  private func packMultiAttrValues<Attr>(attributes: [Attr], values: [AnyObject]) throws -> [Attr: Any] {
+    var result = [Attr: Any]()
+    for (index, attribute) in attributes.enumerate() {
+      if try checkMultiAttrValue(values[index]) {
+        result[attribute] = unpackAXValue(values[index])
+      }
+    }
+    return result
+  }
+
+  // Helper: Checks if value is present and not an error (throws on nontrivial errors).
+  private func checkMultiAttrValue(value: AnyObject) throws -> Bool {
+    // Check for null
+    if value is NSNull {
+      return false
+    }
+
+    // Check for error
+    if CFGetTypeID(value) == AXValueGetTypeID() &&
+       AXValueGetType(value as! AXValue).rawValue == kAXValueAXErrorType {
+      var error: AXError = AXError.Success;
+      AXValueGetValue(value as! AXValue, AXValueType(rawValue: kAXValueAXErrorType)!, &error)
+
+      assert(error != .Success)
+      if error == .NoValue || error == .AttributeUnsupported {
+        return false
+      } else {
+        throw error
+      }
+    }
+
+    return true
+  }
+
+  // MARK: Array attributes
+
+  /// Returns all the values of the attribute as an array of the given type.
+  ///
+  /// - parameter attribute: The name of the array attribute.
+  ///
+  /// - throws: `Error.IllegalArgument` if the attribute isn't an array.
+  public func arrayAttribute<T>(attribute: Attribute) throws -> [T]? {
+    return try self.arrayAttribute(attribute.rawValue)
+  }
+
   public func arrayAttribute<T>(attribute: String) throws -> [T]? {
-    guard let array: [AnyObject] = try self.attribute(attribute) else {
-      return nil
+    guard let value: Any = try self.attribute(attribute) else {
+      return nil
+    }
+    guard let array = value as? [AnyObject] else {
+      // For consistency with the other array attribute APIs, throw if it's not an array.
+      throw Error.IllegalArgument
     }
     return array.map({ unpackAXValue($0) as! T })
   }
+
+  /// Returns a subset of values from an array attribute.
+  ///
+  /// - parameter attribute: The name of the array attribute.
+  /// - parameter startAtIndex: The index of the array to start taking values from.
+  /// - parameter maxValues: The maximum number of values you want.
+  ///
+  /// - returns: An array of up to `maxValues` values starting at `startAtIndex`.
+  ///   - The array is empty if `startAtIndex` is out of range.
+  ///   - `nil` if the attribute doesn't exist or has no value.
+  ///
+  /// - throws: `Error.IllegalArgument` if the attribute isn't an array.
+  public func valuesForAttribute<T: AnyObject>
+      (attribute: Attribute, startAtIndex index: Int, maxValues: Int) throws -> [T]? {
+    return try valuesForAttribute(attribute.rawValue, startAtIndex: index, maxValues: maxValues)
+  }
+
+  public func valuesForAttribute<T: AnyObject>
+      (attribute: String, startAtIndex index: Int, maxValues: Int) throws -> [T]? {
+    var values: CFArray?
+    let error = AXUIElementCopyAttributeValues(element, attribute, index, maxValues, &values)
+
+    if error == .NoValue || error == .AttributeUnsupported {
+      return nil
+    }
+
+    guard error == .Success else {
+      throw error
+    }
+
+    let array = values! as [AnyObject]
+    return array.map({ unpackAXValue($0) as! T })
+  }
+
+  /// Returns the number of values an array attribute has.
+  /// - returns: The number of values, or `nil` if `attribute` isn't an array (or doesn't exist).
+  public func valueCountForAttribute(attribute: Attribute) throws -> Int? {
+    return try valueCountForAttribute(attribute.rawValue)
+  }
+
+  public func valueCountForAttribute(attribute: String) throws -> Int? {
+    var count: Int = 0
+    let error = AXUIElementGetAttributeValueCount(element, attribute, &count)
+
+    if error == .AttributeUnsupported || error == .IllegalArgument {
+      return nil
+    }
+
+    guard error == .Success else {
+      throw error
+    }
+
+    return count
+  }
+
+  // MARK: Parameterized attributes
+
+  /// Returns a list of all parameterized attributes of the element.
+  ///
+  /// Parameterized attributes are attributes that require parameters to retrieve. For example,
+  /// the cell contents of a spreadsheet might require the row and column of the cell you want.
+  public func parameterizedAttributes() throws -> [Attribute] {
+    return try parameterizedAttributesAsStrings().flatMap({ Attribute(rawValue: $0) })
+  }
+
+  public func parameterizedAttributesAsStrings() throws -> [String] {
+    var names: CFArray?
+    let error = AXUIElementCopyParameterizedAttributeNames(element, &names)
+
+    if error == .NoValue || error == .AttributeUnsupported {
+      return []
+    }
+
+    guard error == .Success else {
+      throw error
+    }
+
+    // We must first convert the CFArray to a native array, then downcast to an array of strings.
+    return names! as [AnyObject] as! [String]
+  }
+
+  /// Returns the value of the parameterized attribute `attribute` with parameter `param`.
+  ///
+  /// The expected type of `param` depends on the attribute. See the
+  /// [NSAccessibility Informal Protocol Reference](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Protocols/NSAccessibility_Protocol/)
+  /// for more info.
+  public func parameterizedAttribute<T, U>(attribute: Attribute, param: U) throws -> T? {
+    return try parameterizedAttribute(attribute.rawValue, param: param)
+  }
+
+  public func parameterizedAttribute<T, U>(attribute: String, param: U) throws -> T? {
+    var value: AnyObject?
+    let error = AXUIElementCopyParameterizedAttributeValue(element, attribute, param as! AnyObject, &value)
+
+    if error == .NoValue || error == .AttributeUnsupported {
+      return nil
+    }
+
+    guard error == .Success else {
+      throw error
+    }
+
+    return (unpackAXValue(value!) as! T)
+  }
+
+  // MARK: Attribute helpers
 
   // Checks if the value is an AXValue and if so, unwraps it.
   // If the value is an AXUIElement, wraps it in UIElement.

    return try self.attribute(attribute.rawValue)
  }

  public func arrayAttribute<T>(attribute: Attribute) throws -> [T]? {
    return try self.arrayAttribute(attribute.rawValue)
  }

  public func attribute<T>(attribute: String) throws -> T? {
    var value: AnyObject?
    let error = AXUIElementCopyAttributeValue(element, attribute, &value)

    }
  }

  // MARK: - Actions

  /// Returns a list of actions that can be performed on the element.
