general cleanup of the codebase

- new pybind11::base<> attribute to indicate a subclass relationship
- unified infrastructure for parsing variadic arguments in class_ and cpp_function
- use 'handle' and 'object' more consistently everywhere
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ebb4ea6..4160719 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -80,6 +80,7 @@
 include_directories(include)
 
 set(PYBIND11_HEADERS
+  include/pybind11/attr.h
   include/pybind11/cast.h
   include/pybind11/common.h
   include/pybind11/complex.h
@@ -167,7 +168,7 @@
   # Strip unnecessary sections of the binary on Linux/Mac OS
   if(APPLE)
     set_target_properties(example PROPERTIES MACOSX_RPATH ".")
-    set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup -dead_strip")
+    set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup ")
     if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
       add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_SOURCE_DIR}/example/example.so)
     endif()
diff --git a/docs/advanced.rst b/docs/advanced.rst
index 4c2b23b..4683c70 100644
--- a/docs/advanced.rst
+++ b/docs/advanced.rst
@@ -925,7 +925,7 @@
     FUNCTIONS
     ...
     |  myFunction(...)
-    |      Signature : (MyClass, arg : SomeType = <SomeType object at 0x101b7b080>) -> None
+    |      Signature : (MyClass, arg : SomeType = <SomeType object at 0x101b7b080>) -> NoneType
     ...
 
 The first way of addressing this is by defining ``SomeType.__repr__``.
diff --git a/docs/changelog.rst b/docs/changelog.rst
index b992303..d497e26 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -5,15 +5,19 @@
 
 1.2 (not yet released)
 --------------------------
+
 * Optional: efficient generation of function signatures at compile time using C++14
-* Switched to a simpler and more general way of dealing with function default arguments
-  Unused keyword arguments in function calls are now detected and cause errors as expected
+* Switched to a simpler and more general way of dealing with function default
+  arguments. Unused keyword arguments in function calls are now detected and
+  cause errors as expected
 * New ``keep_alive`` call policy analogous to Boost.Python's ``with_custodian_and_ward``
+* New ``pybind11::base<>`` attribute to indicate a subclass relationship
 * Improved interface for RAII type wrappers in ``pytypes.h``
 * Use RAII type wrappers consistently within pybind11 itself. This
   fixes various potential refcount leaks when exceptions occur
 * Added new ``bytes`` RAII type wrapper (maps to ``string`` in Python 2.7).
-* Made handle and related RAII classes const correct
+* Made handle and related RAII classes const correct, using them more
+  consistently everywhere now
 * Got rid of the ugly ``__pybind11__`` attributes on the Python side---they are
   now stored in a C++ hash table that is not visible in Python
 * Fixed refcount leaks involving NumPy arrays and bound functions
@@ -21,7 +25,9 @@
 * Removed an unnecessary copy operation in ``pybind11::vectorize``
 * Fixed naming clashes when both pybind11 and NumPy headers are included
 * Added conversions for additional exception types
-* Documentation improvements (using multiple extension modules, smart pointers, other minor clarifications)
+* Documentation improvements (using multiple extension modules, smart pointers,
+  other minor clarifications)
+* unified infrastructure for parsing variadic arguments in class_ and cpp_function
 * Fixed license text (was: ZLIB, should have been: 3-clause BSD)
 * Python 3.2 compatibility
 
diff --git a/docs/classes.rst b/docs/classes.rst
index 5aad4d1..cfe349f 100644
--- a/docs/classes.rst
+++ b/docs/classes.rst
@@ -177,9 +177,22 @@
         std::string bark() const { return "woof!"; }
     };
 
-To capture the hierarchical relationship in pybind11, we must assign a name to
-the ``Pet`` :class:`class_` instance and reference it when binding the ``Dog``
-class.
+There are two different ways of indicating a hierarchical relationship to
+pybind11: the first is by specifying the C++ base class explicitly during
+construction using the ``base`` attribute:
+
+.. code-block:: cpp
+
+    py::class_<Pet>(m, "Pet")
+       .def(py::init<const std::string &>())
+       .def_readwrite("name", &Pet::name);
+
+    py::class_<Dog>(m, "Dog", py::base<Pet>() /* <- specify C++ parent type */)
+        .def(py::init<const std::string &>())
+        .def("bark", &Dog::bark);
+
+Alternatively, we can also assign a name to the previously bound ``Pet``
+:class:`class_` object and reference it when binding the ``Dog`` class:
 
 .. code-block:: cpp
 
@@ -187,11 +200,12 @@
     pet.def(py::init<const std::string &>())
        .def_readwrite("name", &Pet::name);
 
-    py::class_<Dog>(m, "Dog", pet /* <- specify parent */)
+    py::class_<Dog>(m, "Dog", pet /* <- specify Python parent type */)
         .def(py::init<const std::string &>())
         .def("bark", &Dog::bark);
 
-Instances then expose fields and methods of both types:
+Functionality-wise, both approaches are completely equivalent. Afterwards,
+instances will expose fields and methods of both types:
 
 .. code-block:: python
 
@@ -242,14 +256,14 @@
      |  Methods defined here:
      |
      |  __init__(...)
-     |      Signature : (Pet, str, int) -> None
+     |      Signature : (Pet, str, int) -> NoneType
      |
      |  set(...)
-     |      1. Signature : (Pet, int) -> None
+     |      1. Signature : (Pet, int) -> NoneType
      |
      |      Set the pet's age
      |
-     |      2. Signature : (Pet, str) -> None
+     |      2. Signature : (Pet, str) -> NoneType
      |
      |      Set the pet's name
 
diff --git a/docs/cmake.rst b/docs/cmake.rst
index 50d50b5..6172859 100644
--- a/docs/cmake.rst
+++ b/docs/cmake.rst
@@ -30,10 +30,14 @@
     # Try to autodetect Python (can be overridden manually if needed)
     set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7)
     if (NOT ${PYBIND11_PYTHON_VERSION} STREQUAL "")
-      find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} EXACT REQUIRED)
+      find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} EXACT)
+      if (NOT PythonLibs_FOUND)
+        find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} REQUIRED)
+      endif()
     else()
       find_package(PythonLibs REQUIRED)
     endif()
+    find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} EXACT REQUIRED)
 
     # Uncomment the following line if you will also require a matching Python interpreter
     # find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} EXACT REQUIRED)
@@ -115,7 +119,7 @@
       # Strip unnecessary sections of the binary on Linux/Mac OS
       if(APPLE)
         set_target_properties(example PROPERTIES MACOSX_RPATH ".")
-        set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup -dead_strip")
+        set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup ")
         if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
           add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_BINARY_DIR}/example.so)
         endif()
diff --git a/docs/reference.rst b/docs/reference.rst
index ab5c11b..4df4344 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -63,17 +63,19 @@
 
     Return the ``PyObject *`` underlying a :class:`handle`.
 
-.. function:: void handle::inc_ref() const
+.. function:: const handle& handle::inc_ref() const
 
     Manually increase the reference count of the Python object. Usually, it is
     preferable to use the :class:`object` class which derives from
-    :class:`handle` and calls this function automatically.
+    :class:`handle` and calls this function automatically. Returns a reference
+    to itself.
 
-.. function:: void handle::dec_ref() const
+.. function:: const handle& handle::dec_ref() const
 
     Manually decrease the reference count of the Python object. Usually, it is
     preferable to use the :class:`object` class which derives from
-    :class:`handle` and calls this function automatically.
+    :class:`handle` and calls this function automatically. Returns a reference
+    to itself.
 
 .. function:: void handle::ref_count() const
 
@@ -167,11 +169,11 @@
     Move constructor; steals the object from ``other`` and preserves its
     reference count.
 
-.. function:: PyObject* object::release()
+.. function:: handle object::release()
 
-    Release ownership of underlying ``PyObject *``. Returns raw Python object
-    pointer without decreasing its reference count and resets handle to
-    ``nullptr``-valued pointer.
+    Resets the internal pointer to ``nullptr`` without without decreasing the
+    object's reference count. The function returns a raw handle to the original
+    Python object.
 
 .. function:: object::~object()
 
diff --git a/example/example5.cpp b/example/example5.cpp
index cabd847..ad24ef0 100644
--- a/example/example5.cpp
+++ b/example/example5.cpp
@@ -29,6 +29,11 @@
     void bark() const { std::cout << "Woof!" << std::endl; }
 };
 
+class Rabbit : public Pet {
+public:
+    Rabbit(const std::string &name) : Pet(name, "parrot") {}
+};
+
 void pet_print(const Pet &pet) {
     std::cout << pet.name() + " is a " + pet.species() << std::endl;
 }
@@ -62,9 +67,14 @@
         .def("name", &Pet::name)
         .def("species", &Pet::species);
 
+    /* One way of declaring a subclass relationship: reference parent's class_ object */
     py::class_<Dog>(m, "Dog", pet_class)
         .def(py::init<std::string>());
 
+    /* Another way of declaring a subclass relationship: reference parent's C++ type */
+    py::class_<Rabbit>(m, "Rabbit", py::base<Pet>())
+        .def(py::init<std::string>());
+
     m.def("pet_print", pet_print);
     m.def("dog_bark", dog_bark);
 
diff --git a/example/example5.py b/example/example5.py
index b7e3cd3..0699978 100755
--- a/example/example5.py
+++ b/example/example5.py
@@ -5,11 +5,15 @@
 
 from example import Pet
 from example import Dog
+from example import Rabbit
 from example import dog_bark
 from example import pet_print
 
 polly = Pet('Polly', 'parrot')
 molly = Dog('Molly')
+roger = Rabbit('Rabbit')
+print(roger.name() + " is a " + roger.species())
+pet_print(roger)
 print(polly.name() + " is a " + polly.species())
 pet_print(polly)
 print(molly.name() + " is a " + molly.species())
diff --git a/example/example5.ref b/example/example5.ref
index 41544c8..d1da883 100644
--- a/example/example5.ref
+++ b/example/example5.ref
@@ -1,16 +1,7 @@
+Rabbit is a parrot
 Polly is a parrot
-Polly is a parrot
-Molly is a dog
 Molly is a dog
 Woof!
-The following error is expected: Incompatible function arguments. The following argument types are supported:
-    1. (Dog) -> NoneType
-
-Callback function 1 called!
-False
-Callback function 2 called : Hello, x, True, 5
-5
-func(43) = 44
 func(43) = 44
 Payload constructor
 Payload copy constructor
@@ -18,3 +9,14 @@
 Payload destructor
 Payload destructor
 Payload destructor
+Rabbit is a parrot
+Polly is a parrot
+Molly is a dog
+The following error is expected: Incompatible function arguments. The following argument types are supported:
+    1. (example.Dog) -> NoneType
+
+Callback function 1 called!
+False
+Callback function 2 called : Hello, x, True, 5
+5
+func(43) = 44
diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h
new file mode 100644
index 0000000..9a646cb
--- /dev/null
+++ b/include/pybind11/attr.h
@@ -0,0 +1,275 @@
+/*
+    pybind11/pybind11.h: Infrastructure for processing custom
+    type and function attributes
+
+    Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "cast.h"
+
+NAMESPACE_BEGIN(pybind11)
+
+template <typename T> struct arg_t;
+
+/// Annotation for keyword arguments
+struct arg {
+    arg(const char *name) : name(name) { }
+    template <typename T> arg_t<T> operator=(const T &value);
+    const char *name;
+};
+
+/// Annotation for keyword arguments with default values
+template <typename T> struct arg_t : public arg {
+    arg_t(const char *name, const T &value, const char *descr = nullptr)
+        : arg(name), value(value), descr(descr) { }
+    T value;
+    const char *descr;
+};
+
+template <typename T> arg_t<T> arg::operator=(const T &value) { return arg_t<T>(name, value); }
+
+/// Annotation for methods
+struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
+
+/// Annotation for documentation
+struct doc { const char *value; doc(const char *value) : value(value) { } };
+
+/// Annotation for function names
+struct name { const char *value; name(const char *value) : value(value) { } };
+
+/// Annotation indicating that a function is an overload associated with a given "sibling"
+struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } };
+
+/// Annotation indicating that a class derives from another given type
+template <typename T> struct base { };
+
+/// Keep patient alive while nurse lives
+template <int Nurse, int Patient> struct keep_alive { };
+
+NAMESPACE_BEGIN(detail)
+/* Forward declarations */
+enum op_id : int;
+enum op_type : int;
+struct undefined_t;
+template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t> struct op_;
+template <typename... Args> struct init;
+inline void keep_alive_impl(int Nurse, int Patient, handle args, handle ret);
+
+/// Internal data structure which holds metadata about a keyword argument
+struct argument_record {
+    const char *name;  ///< Argument name
+    const char *descr; ///< Human-readable version of the argument value
+    handle value;      ///< Associated Python object
+
+    argument_record(const char *name, const char *descr, handle value)
+        : name(name), descr(descr), value(value) { }
+};
+
+/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.)
+struct function_record {
+    /// Function name
+    char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
+
+    // User-specified documentation string
+    char *doc = nullptr;
+
+    /// Human-readable version of the function signature
+    char *signature = nullptr;
+
+    /// List of registered keyword arguments
+    std::vector<argument_record> args;
+
+    /// Pointer to lambda function which converts arguments and performs the actual call
+    handle (*impl) (function_record *, handle, handle) = nullptr;
+
+    /// Storage for the wrapped function pointer and captured data, if any
+    void *data = nullptr;
+
+    /// Pointer to custom destructor for 'data' (if needed)
+    void (*free_data) (void *ptr) = nullptr;
+
+    /// Return value policy associated with this function
+    return_value_policy policy = return_value_policy::automatic;
+
+    /// True if name == '__init__'
+    bool is_constructor = false;
+
+    /// Python method object
+    PyMethodDef *def = nullptr;
+
+    /// Python handle to the associated class (if this is method)
+    handle class_;
+
+    /// Python handle to the sibling function representing an overload chain
+    handle sibling;
+
+    /// Pointer to next overload
+    function_record *next = nullptr;
+};
+
+/// Special data structure which (temporarily) holds metadata about a bound class
+struct type_record {
+    /// Handle to the parent scope
+    handle scope;
+
+    /// Name of the class
+    const char *name = nullptr;
+
+    // Pointer to RTTI type_info data structure
+    const std::type_info *type = nullptr;
+
+    /// How large is the underlying C++ type?
+    size_t type_size = 0;
+
+    /// How large is pybind11::instance<type>?
+    size_t instance_size = 0;
+
+    /// Function pointer to class_<..>::init_holder
+    void (*init_holder)(PyObject *, const void *) = nullptr;
+
+    /// Function pointer to class_<..>::dealloc
+    void (*dealloc)(PyObject *) = nullptr;
+
+    // Pointer to RTTI type_info data structure of base class
+    const std::type_info *base_type = nullptr;
+
+    /// OR: Python handle to base class
+    handle base_handle;
+
+    /// Optional docstring
+    const char *doc = nullptr;
+};
+
+/**
+ * Partial template specializations to process custom attributes provided to
+ * cpp_function_ and class_. These are either used to initialize the respective
+ * fields in the type_record and function_record data structures or executed
+ * at runtime to deal with custom call policies (e.g. keep_alive).
+ */
+template <typename T, typename SFINAE = void> struct process_attribute;
+
+template <typename T> struct process_attribute_default {
+    /// Default implementation: do nothing
+    static void init(const T &, function_record *) { }
+    static void init(const T &, type_record *) { }
+    static void precall(handle) { }
+    static void postcall(handle, handle) { }
+};
+
+/// Process an attribute specifying the function's name
+template <> struct process_attribute<name> : process_attribute_default<name> {
+    static void init(const name &n, function_record *r) { r->name = const_cast<char *>(n.value); }
+};
+
+/// Process an attribute specifying the function's docstring
+template <> struct process_attribute<doc> : process_attribute_default<doc> {
+    static void init(const doc &n, function_record *r) { r->doc = const_cast<char *>(n.value); }
+};
+
+/// Process an attribute specifying the function's docstring (provided as a C-style string)
+template <> struct process_attribute<const char *> : process_attribute_default<const char *> {
+    static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); }
+    static void init(const char *d, type_record *r) { r->doc = const_cast<char *>(d); }
+};
+template <> struct process_attribute<char *> : process_attribute<const char *> { };
+
+/// Process an attribute indicating the function's return value policy
+template <> struct process_attribute<return_value_policy> : process_attribute_default<return_value_policy> {
+    static void init(const return_value_policy &p, function_record *r) { r->policy = p; }
+};
+
+/// Process an attribute which indicates that this is an overloaded function associated with a given sibling
+template <> struct process_attribute<sibling> : process_attribute_default<sibling> {
+    static void init(const sibling &s, function_record *r) { r->sibling = s.value; }
+};
+
+/// Process an attribute which indicates that this function is a method
+template <> struct process_attribute<is_method> : process_attribute_default<is_method> {
+    static void init(const is_method &s, function_record *r) { r->class_ = s.class_; }
+};
+
+/// Process a keyword argument attribute (*without* a default value)
+template <> struct process_attribute<arg> : process_attribute_default<arg> {
+    static void init(const arg &a, function_record *r) {
+        if (r->class_ && r->args.empty())
+            r->args.emplace_back("self", nullptr, handle());
+        r->args.emplace_back(a.name, nullptr, handle());
+    }
+};
+
+/// Process a keyword argument attribute (*with* a default value)
+template <typename T>
+struct process_attribute<arg_t<T>> : process_attribute_default<arg_t<T>> {
+    static void init(const arg_t<T> &a, function_record *r) {
+        if (r->class_ && r->args.empty())
+            r->args.emplace_back("self", nullptr, handle());
+
+        /* Convert keyword value into a Python object */
+        object o = object(detail::type_caster<typename detail::intrinsic_type<T>::type>::cast(
+                a.value, return_value_policy::automatic, handle()), false);
+
+        if (!o)
+            pybind11_fail("arg(): could not convert default keyword "
+                          "argument into a Python object (type not "
+                          "registered yet?)");
+
+        r->args.emplace_back(a.name, a.descr, o.release());
+    }
+};
+
+/// Process a parent class attribute
+template <typename T>
+struct process_attribute<T, typename std::enable_if<std::is_base_of<handle, T>::value>::type> : process_attribute_default<handle> {
+    static void init(const handle &h, type_record *r) { r->base_handle = h; }
+};
+
+/// Process a parent class attribute
+template <typename T>
+struct process_attribute<base<T>> : process_attribute_default<base<T>> {
+    static void init(const base<T> &, type_record *r) { r->base_type = &typeid(T); }
+};
+
+/***
+ * Process a keep_alive call policy -- invokes keep_alive_impl during the
+ * pre-call handler if both Nurse, Patient != 0 and use the post-call handler
+ * otherwise
+ */
+template <int Nurse, int Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> {
+    template <int N = Nurse, int P = Patient, typename std::enable_if<N != 0 && P != 0, int>::type = 0>
+    static void precall(handle args) { keep_alive_impl(Nurse, Patient, args, handle()); }
+    template <int N = Nurse, int P = Patient, typename std::enable_if<N != 0 && P != 0, int>::type = 0>
+    static void postcall(handle, handle) { }
+    template <int N = Nurse, int P = Patient, typename std::enable_if<N == 0 || P == 0, int>::type = 0>
+    static void precall(handle) { }
+    template <int N = Nurse, int P = Patient, typename std::enable_if<N == 0 || P == 0, int>::type = 0>
+    static void postcall(handle args, handle ret) { keep_alive_impl(Nurse, Patient, args, ret); }
+};
+
+
+/// Recursively iterate over variadic template arguments
+template <typename... Args> struct process_attributes {
+    static void init(const Args&... args, function_record *r) {
+        int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
+        (void) unused;
+    }
+    static void init(const Args&... args, type_record *r) {
+        int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
+        (void) unused;
+    }
+    static void precall(handle fn_args) {
+        int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(fn_args), 0) ... };
+        (void) unused;
+    }
+    static void postcall(handle fn_args, handle fn_ret) {
+        int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(fn_args, fn_ret), 0) ... };
+        (void) unused;
+    }
+};
+
+NAMESPACE_END(detail)
+NAMESPACE_END(pybind11)
diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index 8fab99d..bc26e47 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -19,95 +19,168 @@
 NAMESPACE_BEGIN(pybind11)
 NAMESPACE_BEGIN(detail)
 
-class type_caster_generic {
-public:
-    PYBIND11_NOINLINE type_caster_generic(const std::type_info *type_info) {
-        auto &types = get_internals().registered_types_cpp;
+/// Additional type information which does not fit into the PyTypeObject
+struct type_info {
+    PyTypeObject *type;
+    size_t type_size;
+    void (*init_holder)(PyObject *, const void *);
+    std::vector<PyObject *(*)(PyObject *, PyTypeObject *) > implicit_conversions;
+    buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
+    void *get_buffer_data = nullptr;
+};
 
-        auto it = types.find(type_info);
-        if (it != types.end()) {
-            typeinfo = (detail::type_info *) it->second;
-        } else {
-            /* Unknown type?! Since std::type_info* often varies across
-               module boundaries, the following does an explicit check */
-            for (auto const &type : types) {
-                auto *first = (const std::type_info *) type.first;
-                if (strcmp(first->name(), type_info->name()) == 0) {
-                    types[type_info] = type.second;
-                    typeinfo = (detail::type_info *) type.second;
-                    break;
-                }
+PYBIND11_NOINLINE inline internals &get_internals() {
+    static internals *internals_ptr = nullptr;
+    if (internals_ptr)
+        return *internals_ptr;
+    handle builtins(PyEval_GetBuiltins());
+    capsule caps(builtins["__pybind11__"]);
+    if (caps.check()) {
+        internals_ptr = caps;
+    } else {
+        internals_ptr = new internals();
+        builtins["__pybind11__"] = capsule(internals_ptr);
+    }
+    return *internals_ptr;
+}
+
+PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) {
+    auto const &type_dict = get_internals().registered_types_py;
+    do {
+        auto it = type_dict.find(type);
+        if (it != type_dict.end())
+            return (detail::type_info *) it->second;
+        type = type->tp_base;
+        if (!type)
+            pybind11_fail("pybind11::detail::get_type_info: unable to find type object!");
+    } while (true);
+}
+
+PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_info &tp) {
+    auto &types = get_internals().registered_types_cpp;
+
+    auto it = types.find(&tp);
+    if (it != types.end()) {
+        return (detail::type_info *) it->second;
+    } else {
+        /* Unknown type?! Since std::type_info* often varies across
+           module boundaries, the following does an explicit check */
+        for (auto const &type : types) {
+            auto *first = (const std::type_info *) type.first;
+            if (strcmp(first->name(), tp.name()) == 0) {
+                types[&tp] = type.second;
+                return (detail::type_info *) type.second;
             }
         }
     }
+    return nullptr;
+}
 
-    PYBIND11_NOINLINE bool load(PyObject *src, bool convert) {
-        if (src == nullptr || typeinfo == nullptr)
+PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp) {
+    detail::type_info *type_info = get_type_info(tp);
+    return handle(type_info ? ((PyObject *) type_info->type) : nullptr);
+}
+
+PYBIND11_NOINLINE inline std::string error_string() {
+    std::string errorString;
+    PyThreadState *tstate = PyThreadState_GET();
+    if (tstate == nullptr)
+        return "";
+
+    if (tstate->curexc_type) {
+        errorString += (std::string) handle(tstate->curexc_type).str();
+        errorString += ": ";
+    }
+    if (tstate->curexc_value)
+        errorString += (std::string) handle(tstate->curexc_value).str();
+
+    return errorString;
+}
+
+PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr) {
+    auto instances = get_internals().registered_instances;
+    auto it = instances.find(ptr);
+    if (it == instances.end())
+        return handle();
+    return handle((PyObject *) it->second);
+}
+
+class type_caster_generic {
+public:
+    PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info)
+     : typeinfo(get_type_info(type_info)) { }
+
+    PYBIND11_NOINLINE bool load(handle src, bool convert) {
+        if (!src || !typeinfo)
             return false;
-        if (PyType_IsSubtype(Py_TYPE(src), typeinfo->type)) {
-            value = ((instance<void> *) src)->value;
+        if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) {
+            value = ((instance<void> *) src.ptr())->value;
             return true;
         }
         if (convert) {
             for (auto &converter : typeinfo->implicit_conversions) {
-                temp = object(converter(src, typeinfo->type), false);
-                if (load(temp.ptr(), false))
+                temp = object(converter(src.ptr(), typeinfo->type), false);
+                if (load(temp, false))
                     return true;
             }
         }
         return false;
     }
 
-    PYBIND11_NOINLINE static PyObject *cast(const void *_src, return_value_policy policy, PyObject *parent,
-                                            const std::type_info *type_info,
-                                            void *(*copy_constructor)(const void *),
-                                            const void *existing_holder = nullptr) {
+    PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent,
+                                         const std::type_info *type_info,
+                                         void *(*copy_constructor)(const void *),
+                                         const void *existing_holder = nullptr) {
         void *src = const_cast<void *>(_src);
-        if (src == nullptr) {
-            Py_INCREF(Py_None);
-            return Py_None;
-        }
+        if (src == nullptr)
+            return handle(Py_None).inc_ref();
+
         // avoid an issue with internal references matching their parent's address
         bool dont_cache = policy == return_value_policy::reference_internal &&
-                          parent && ((instance<void> *) parent)->value == (void *) src;
+                          parent && ((instance<void> *) parent.ptr())->value == (void *) src;
+
         auto& internals = get_internals();
         auto it_instance = internals.registered_instances.find(src);
-        if (it_instance != internals.registered_instances.end() && !dont_cache) {
-            PyObject *inst = (PyObject *) it_instance->second;
-            Py_INCREF(inst);
-            return inst;
-        }
+        if (it_instance != internals.registered_instances.end() && !dont_cache)
+            return handle((PyObject *) it_instance->second).inc_ref();
+
         auto it = internals.registered_types_cpp.find(type_info);
         if (it == internals.registered_types_cpp.end()) {
             std::string tname = type_info->name();
             detail::clean_type_id(tname);
             std::string msg = "Unregistered type : " + tname;
             PyErr_SetString(PyExc_TypeError, msg.c_str());
-            return nullptr;
+            return handle();
         }
+
         auto tinfo = (const detail::type_info *) it->second;
-        instance<void> *inst = (instance<void> *) PyType_GenericAlloc(tinfo->type, 0);
-        inst->value = src;
-        inst->owned = true;
-        inst->parent = nullptr;
+        object inst(PyType_GenericAlloc(tinfo->type, 0), false);
+
+        auto wrapper = (instance<void> *) inst.ptr();
+
+        wrapper->value = src;
+        wrapper->owned = true;
+        wrapper->parent = nullptr;
+
         if (policy == return_value_policy::automatic)
             policy = return_value_policy::take_ownership;
+
         if (policy == return_value_policy::copy) {
-            inst->value = copy_constructor(inst->value);
-            if (inst->value == nullptr)
+            wrapper->value = copy_constructor(wrapper->value);
+            if (wrapper->value == nullptr)
                 throw cast_error("return_value_policy = copy, but the object is non-copyable!");
         } else if (policy == return_value_policy::reference) {
-            inst->owned = false;
+            wrapper->owned = false;
         } else if (policy == return_value_policy::reference_internal) {
-            inst->owned = false;
-            inst->parent = parent;
-            Py_XINCREF(parent);
+            wrapper->owned = false;
+            wrapper->parent = parent.inc_ref().ptr();
         }
-        PyObject *inst_pyobj = (PyObject *) inst;
-        tinfo->init_holder(inst_pyobj, existing_holder);
+
+        tinfo->init_holder(inst.ptr(), existing_holder);
         if (!dont_cache)
-            internals.registered_instances[inst->value] = inst_pyobj;
-        return inst_pyobj;
+            internals.registered_instances[wrapper->value] = inst.ptr();
+
+        return inst.release();
     }
 
 protected:
@@ -121,15 +194,15 @@
 public:
     static PYBIND11_DESCR name() { return type_descr(_<type>()); }
 
-    type_caster() : type_caster_generic(&typeid(type)) { }
+    type_caster() : type_caster_generic(typeid(type)) { }
 
-    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
+    static handle cast(const type &src, return_value_policy policy, handle parent) {
         if (policy == return_value_policy::automatic)
             policy = return_value_policy::copy;
         return type_caster_generic::cast(&src, policy, parent, &typeid(type), &copy_constructor);
     }
 
-    static PyObject *cast(const type *src, return_value_policy policy, PyObject *parent) {
+    static handle cast(const type *src, return_value_policy policy, handle parent) {
         return type_caster_generic::cast(src, policy, parent, &typeid(type), &copy_constructor);
     }
 
@@ -149,7 +222,7 @@
         type value; \
     public: \
         static PYBIND11_DESCR name() { return type_descr(py_name); } \
-        static PyObject *cast(const type *src, return_value_policy policy, PyObject *parent) { \
+        static handle cast(const type *src, return_value_policy policy, handle parent) { \
             return cast(*src, policy, parent); \
         } \
         operator type*() { return &value; } \
@@ -171,21 +244,21 @@
     typedef typename std::conditional<std::is_floating_point<T>::value, double, _py_type_1>::type py_type;
 public:
 
-    bool load(PyObject *src, bool) {
+    bool load(handle src, bool) {
         py_type py_value;
 
         if (std::is_floating_point<T>::value) {
-            py_value = (py_type) PyFloat_AsDouble(src);
+            py_value = (py_type) PyFloat_AsDouble(src.ptr());
         } else if (sizeof(T) <= sizeof(long)) {
             if (std::is_signed<T>::value)
-                py_value = (py_type) PyLong_AsLong(src);
+                py_value = (py_type) PyLong_AsLong(src.ptr());
             else
-                py_value = (py_type) PyLong_AsUnsignedLong(src);
+                py_value = (py_type) PyLong_AsUnsignedLong(src.ptr());
         } else {
             if (std::is_signed<T>::value)
-                py_value = (py_type) PYBIND11_LONG_AS_LONGLONG(src);
+                py_value = (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr());
             else
-                py_value = (py_type) PYBIND11_LONG_AS_UNSIGNED_LONGLONG(src);
+                py_value = (py_type) PYBIND11_LONG_AS_UNSIGNED_LONGLONG(src.ptr());
         }
 
         if ((py_value == (py_type) -1 && PyErr_Occurred()) ||
@@ -200,7 +273,7 @@
         return true;
     }
 
-    static PyObject *cast(T src, return_value_policy /* policy */, PyObject * /* parent */) {
+    static handle cast(T src, return_value_policy /* policy */, handle /* parent */) {
         if (std::is_floating_point<T>::value) {
             return PyFloat_FromDouble((double) src);
         } else if (sizeof(T) <= sizeof(long)) {
@@ -216,12 +289,13 @@
         }
     }
 
-    static PyObject *cast(const T *src, return_value_policy policy, PyObject *parent) {
+    static handle cast(const T *src, return_value_policy policy, handle parent) {
         return cast(*src, policy, parent);
     }
 
     template <typename T2 = T, typename std::enable_if<std::is_integral<T2>::value, int>::type = 0>
     static PYBIND11_DESCR name() { return type_descr(_("int")); }
+
     template <typename T2 = T, typename std::enable_if<!std::is_integral<T2>::value, int>::type = 0>
     static PYBIND11_DESCR name() { return type_descr(_("float")); }
 
@@ -234,10 +308,9 @@
 
 template <> class type_caster<void_type> {
 public:
-    bool load(PyObject *, bool) { return false; }
-    static PyObject *cast(void_type, return_value_policy /* policy */, PyObject * /* parent */) {
-        Py_INCREF(Py_None);
-        return Py_None;
+    bool load(handle, bool) { return false; }
+    static handle cast(void_type, return_value_policy /* policy */, handle /* parent */) {
+        return handle(Py_None).inc_ref();
     }
     PYBIND11_TYPE_CASTER(void_type, _("NoneType"));
 };
@@ -247,38 +320,36 @@
 
 template <> class type_caster<bool> {
 public:
-    bool load(PyObject *src, bool) {
-        if (src == Py_True) { value = true; return true; }
-        else if (src == Py_False) { value = false; return true; }
+    bool load(handle src, bool) {
+        if (src.ptr() == Py_True) { value = true; return true; }
+        else if (src.ptr() == Py_False) { value = false; return true; }
         else return false;
     }
-    static PyObject *cast(bool src, return_value_policy /* policy */, PyObject * /* parent */) {
-        PyObject *result = src ? Py_True : Py_False;
-        Py_INCREF(result);
-        return result;
+    static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) {
+        return handle(src ? Py_True : Py_False).inc_ref();
     }
     PYBIND11_TYPE_CASTER(bool, _("bool"));
 };
 
 template <> class type_caster<std::string> {
 public:
-    bool load(PyObject *src, bool) {
+    bool load(handle src, bool) {
         object temp;
-        PyObject *load_src = src;
-        if (PyUnicode_Check(src)) {
-            temp = object(PyUnicode_AsUTF8String(src), false);
+        handle load_src = src;
+        if (PyUnicode_Check(load_src.ptr())) {
+            temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false);
             if (!temp) { PyErr_Clear(); return false; }  // UnicodeEncodeError
-            load_src = temp.ptr();
+            load_src = temp;
         }
         char *buffer;
         ssize_t length;
-        int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src, &buffer, &length);
+        int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src.ptr(), &buffer, &length);
         if (err == -1) { PyErr_Clear(); return false; }  // TypeError
         value = std::string(buffer, length);
         return true;
     }
 
-    static PyObject *cast(const std::string &src, return_value_policy /* policy */, PyObject * /* parent */) {
+    static handle cast(const std::string &src, return_value_policy /* policy */, handle /* parent */) {
         return PyUnicode_FromStringAndSize(src.c_str(), src.length());
     }
 
@@ -287,25 +358,25 @@
 
 template <> class type_caster<char> {
 public:
-    bool load(PyObject *src, bool) {
+    bool load(handle src, bool) {
         object temp;
-        PyObject *load_src = src;
-        if (PyUnicode_Check(src)) {
-            temp = object(PyUnicode_AsUTF8String(src), false);
+        handle load_src = src;
+        if (PyUnicode_Check(load_src.ptr())) {
+            temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false);
             if (!temp) { PyErr_Clear(); return false; }  // UnicodeEncodeError
-            load_src = temp.ptr();
+            load_src = temp;
         }
-        const char *ptr = PYBIND11_BYTES_AS_STRING(load_src);
+        const char *ptr = PYBIND11_BYTES_AS_STRING(load_src.ptr());
         if (!ptr) { PyErr_Clear(); return false; }  // TypeError
         value = std::string(ptr);
         return true;
     }
 
-    static PyObject *cast(const char *src, return_value_policy /* policy */, PyObject * /* parent */) {
+    static handle cast(const char *src, return_value_policy /* policy */, handle /* parent */) {
         return PyUnicode_FromString(src);
     }
 
-    static PyObject *cast(char src, return_value_policy /* policy */, PyObject * /* parent */) {
+    static handle cast(char src, return_value_policy /* policy */, handle /* parent */) {
         char str[2] = { src, '\0' };
         return PyUnicode_DecodeLatin1(str, 1, nullptr);
     }
@@ -321,25 +392,22 @@
 template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
     typedef std::pair<T1, T2> type;
 public:
-    bool load(PyObject *src, bool convert) {
-        if (!PyTuple_Check(src) || PyTuple_Size(src) != 2)
+    bool load(handle src, bool convert) {
+        if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != 2)
             return false;
-        if (!first.load(PyTuple_GET_ITEM(src, 0), convert))
-            return false;
-        return second.load(PyTuple_GET_ITEM(src, 1), convert);
+        return  first.load(PyTuple_GET_ITEM(src.ptr(), 0), convert) &&
+               second.load(PyTuple_GET_ITEM(src.ptr(), 1), convert);
     }
 
-    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
-        object o1(type_caster<typename intrinsic_type<T1>::type>::cast(src.first, policy, parent), false);
-        object o2(type_caster<typename intrinsic_type<T2>::type>::cast(src.second, policy, parent), false);
+    static handle cast(const type &src, return_value_policy policy, handle parent) {
+        object o1 = object(type_caster<typename intrinsic_type<T1>::type>::cast(src.first, policy, parent), false);
+        object o2 = object(type_caster<typename intrinsic_type<T2>::type>::cast(src.second, policy, parent), false);
         if (!o1 || !o2)
-            return nullptr;
-        PyObject *tuple = PyTuple_New(2);
-        if (!tuple)
-            return nullptr;
-        PyTuple_SET_ITEM(tuple, 0, o1.release());
-        PyTuple_SET_ITEM(tuple, 1, o2.release());
-        return tuple;
+            return handle();
+        tuple result(2);
+        PyTuple_SET_ITEM(result.ptr(), 0, o1.release().ptr());
+        PyTuple_SET_ITEM(result.ptr(), 1, o2.release().ptr());
+        return result.release();
     }
 
     static PYBIND11_DESCR name() {
@@ -361,11 +429,11 @@
 public:
     enum { size = sizeof...(Tuple) };
 
-    bool load(PyObject *src, bool convert) {
+    bool load(handle src, bool convert) {
         return load(src, convert, typename make_index_sequence<sizeof...(Tuple)>::type());
     }
 
-    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
+    static handle cast(const type &src, return_value_policy policy, handle parent) {
         return cast(src, policy, parent, typename make_index_sequence<size>::type());
     }
 
@@ -398,36 +466,32 @@
         return type((Tuple) std::get<Index>(value)...);
     }
 
-    template <size_t ... Indices> bool load(PyObject *src, bool convert, index_sequence<Indices...>) {
-        if (!PyTuple_Check(src))
+    template <size_t ... Indices> bool load(handle src, bool convert, index_sequence<Indices...>) {
+        if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != size)
             return false;
-        if (PyTuple_Size(src) != size)
-            return false;
-        std::array<bool, size> results {{
-            (PyTuple_GET_ITEM(src, Indices) != nullptr ? std::get<Indices>(value).load(PyTuple_GET_ITEM(src, Indices), convert) : false)...
+        std::array<bool, size> success {{
+            (PyTuple_GET_ITEM(src.ptr(), Indices) != nullptr ? std::get<Indices>(value).load(PyTuple_GET_ITEM(src.ptr(), Indices), convert) : false)...
         }};
         (void) convert; /* avoid a warning when the tuple is empty */
-        for (bool r : results)
+        for (bool r : success)
             if (!r)
                 return false;
         return true;
     }
 
     /* Implementation: Convert a C++ tuple into a Python tuple */
-    template <size_t ... Indices> static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent, index_sequence<Indices...>) {
-        std::array<object, size> results {{
+    template <size_t ... Indices> static handle cast(const type &src, return_value_policy policy, handle parent, index_sequence<Indices...>) {
+        std::array<object, size> entries {{
             object(type_caster<typename intrinsic_type<Tuple>::type>::cast(std::get<Indices>(src), policy, parent), false)...
         }};
-        for (const auto & result : results)
-            if (!result)
-                return nullptr;
-        PyObject *tuple = PyTuple_New(size);
-        if (!tuple)
-            return nullptr;
+        for (const auto &entry: entries)
+            if (!entry)
+                return handle();
+        tuple result(size);
         int counter = 0;
-        for (auto & result : results)
-            PyTuple_SET_ITEM(tuple, counter++, result.release());
-        return tuple;
+        for (auto & entry: entries)
+            PyTuple_SET_ITEM(result.ptr(), counter++, entry.release().ptr());
+        return result.release();
     }
 
 protected:
@@ -443,19 +507,21 @@
     using type_caster<type>::temp;
     using type_caster<type>::copy_constructor;
 
-    bool load(PyObject *src, bool convert) {
-        if (src == nullptr || typeinfo == nullptr)
+    bool load(handle src, bool convert) {
+        if (!src || !typeinfo)
             return false;
-        if (PyType_IsSubtype(Py_TYPE(src), typeinfo->type)) {
-            auto inst = (instance<type, holder_type> *) src;
+
+        if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) {
+            auto inst = (instance<type, holder_type> *) src.ptr();
             value = inst->value;
             holder = inst->holder;
             return true;
         }
+
         if (convert) {
             for (auto &converter : typeinfo->implicit_conversions) {
-                temp = object(converter(src, typeinfo->type), false);
-                if (load(temp.ptr(), false))
+                temp = object(converter(src.ptr(), typeinfo->type), false);
+                if (load(temp, false))
                     return true;
             }
         }
@@ -467,7 +533,7 @@
     explicit operator holder_type&() { return holder; }
     explicit operator holder_type*() { return &holder; }
 
-    static PyObject *cast(const holder_type &src, return_value_policy policy, PyObject *parent) {
+    static handle cast(const holder_type &src, return_value_policy policy, handle parent) {
         return type_caster_generic::cast(
             src.get(), policy, parent, &typeid(type), &copy_constructor, &src);
     }
@@ -483,27 +549,27 @@
 struct type_caster<type, typename std::enable_if<std::is_base_of<handle, type>::value>::type> {
 public:
     template <typename T = type, typename std::enable_if<std::is_same<T, handle>::value, int>::type = 0>
-    bool load(PyObject *src, bool /* convert */) { value = handle(src); return value.check(); }
+    bool load(handle src, bool /* convert */) { value = src; return value.check(); }
 
     template <typename T = type, typename std::enable_if<!std::is_same<T, handle>::value, int>::type = 0>
-    bool load(PyObject *src, bool /* convert */) { value = type(src, true); return value.check(); }
+    bool load(handle src, bool /* convert */) { value = type(src, true); return value.check(); }
 
-    static PyObject *cast(const handle &src, return_value_policy /* policy */, PyObject * /* parent */) {
-        src.inc_ref(); return (PyObject *) src.ptr();
+    static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
+        return src.inc_ref();
     }
     PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name());
 };
 
 NAMESPACE_END(detail)
 
-template <typename T> inline T cast(PyObject *object) {
+template <typename T> inline T cast(handle handle) {
     detail::type_caster<typename detail::intrinsic_type<T>::type> conv;
-    if (!conv.load(object, true))
+    if (!conv.load(handle, true))
         throw cast_error("Unable to cast Python object to C++ type");
     return conv;
 }
 
-template <typename T> inline object cast(const T &value, return_value_policy policy = return_value_policy::automatic, PyObject *parent = nullptr) {
+template <typename T> inline object cast(const T &value, return_value_policy policy = return_value_policy::automatic, handle parent = handle()) {
     if (policy == return_value_policy::automatic)
         policy = std::is_pointer<T>::value ? return_value_policy::take_ownership : return_value_policy::copy;
     return object(detail::type_caster<typename detail::intrinsic_type<T>::type>::cast(value, policy, parent), false);
@@ -514,23 +580,22 @@
 
 template <typename... Args> inline object handle::call(Args&&... args_) const {
     const size_t size = sizeof...(Args);
-    std::array<object, size> args{
+    std::array<object, size> args {
         { object(detail::type_caster<typename detail::intrinsic_type<Args>::type>::cast(
             std::forward<Args>(args_), return_value_policy::reference, nullptr), false)... }
     };
-    for (const auto & result : args)
-        if (!result)
-            throw cast_error("handle::call(): unable to convert input arguments to Python objects");
-    object tuple(PyTuple_New(size), false);
-    if (!tuple)
-        throw cast_error("handle::call(): unable to allocate tuple");
+    for (auto &arg_value : args)
+        if (!arg_value)
+            throw cast_error("handle::call(): unable to convert input "
+                             "arguments to Python objects");
+    tuple args_tuple(size);
     int counter = 0;
-    for (auto & result : args)
-        PyTuple_SET_ITEM(tuple.ptr(), counter++, result.release());
-    PyObject *result = PyObject_CallObject(m_ptr, tuple.ptr());
-    if (result == nullptr && PyErr_Occurred())
+    for (auto &arg_value : args)
+        PyTuple_SET_ITEM(args_tuple.ptr(), counter++, arg_value.release().ptr());
+    object result(PyObject_CallObject(m_ptr, args_tuple.ptr()), false);
+    if (!result)
         throw error_already_set();
-    return object(result, false);
+    return result;
 }
 
 NAMESPACE_END(pybind11)
diff --git a/include/pybind11/common.h b/include/pybind11/common.h
index ff84661..a0af678 100644
--- a/include/pybind11/common.h
+++ b/include/pybind11/common.h
@@ -73,6 +73,7 @@
 #include <memory>
 
 #if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
+#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
 #define PYBIND11_BYTES_CHECK PyBytes_Check
 #define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
 #define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
@@ -89,6 +90,7 @@
 #define PYBIND11_PLUGIN_IMPL(name) \
     extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
 #else
+#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_)
 #define PYBIND11_BYTES_CHECK PyString_Check
 #define PYBIND11_BYTES_FROM_STRING PyString_FromString
 #define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
@@ -200,16 +202,6 @@
     holder_type holder;
 };
 
-/// Additional type information which does not fit into the PyTypeObject
-struct type_info {
-    PyTypeObject *type;
-    size_t type_size;
-    void (*init_holder)(PyObject *, const void *);
-    std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
-    buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
-    void *get_buffer_data = nullptr;
-};
-
 struct overload_hash {
     inline std::size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
         size_t value = std::hash<const void *>()(v.first);
@@ -218,16 +210,6 @@
     }
 };
 
-/// Stores information about a keyword argument
-struct argument_entry {
-    const char *name;  ///< Argument name
-    const char *descr; ///< Human-readable version of the argument value
-    PyObject *value;   ///< Associated Python object
-
-    argument_entry(const char *name, const char *descr, PyObject *value)
-        : name(name), descr(descr), value(value) { }
-};
-
 /// Internal data struture used to track registered instances and types
 struct internals {
     std::unordered_map<const void *, void*> registered_types_cpp; // std::type_info* -> type_info
diff --git a/include/pybind11/complex.h b/include/pybind11/complex.h
index be0614c..10da21d 100644
--- a/include/pybind11/complex.h
+++ b/include/pybind11/complex.h
@@ -20,8 +20,8 @@
 NAMESPACE_BEGIN(detail)
 template <typename T> class type_caster<std::complex<T>> {
 public:
-    bool load(PyObject *src, bool) {
-        Py_complex result = PyComplex_AsCComplex(src);
+    bool load(handle src, bool) {
+        Py_complex result = PyComplex_AsCComplex(src.ptr());
         if (result.real == -1.0 && PyErr_Occurred()) {
             PyErr_Clear();
             return false;
@@ -30,7 +30,7 @@
         return true;
     }
 
-    static PyObject *cast(const std::complex<T> &src, return_value_policy /* policy */, PyObject * /* parent */) {
+    static handle cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
         return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
     }
 
diff --git a/include/pybind11/functional.h b/include/pybind11/functional.h
index 5bc8988..95ac7c9 100644
--- a/include/pybind11/functional.h
+++ b/include/pybind11/functional.h
@@ -18,14 +18,13 @@
 template <typename Return, typename... Args> struct type_caster<std::function<Return(Args...)>> {
     typedef std::function<Return(Args...)> type;
 public:
-
-    bool load(PyObject *src_, bool) {
+    bool load(handle src_, bool) {
         src_ = detail::get_function(src_);
-        if (!src_ || !(PyFunction_Check(src_) || PyCFunction_Check(src_)))
+        if (!src_ || !(PyFunction_Check(src_.ptr()) || PyCFunction_Check(src_.ptr())))
             return false;
         object src(src_, true);
         value = [src](Args... args) -> Return {
-            object retval(pybind11::handle(src).call(std::move(args)...));
+            object retval(src.call(std::move(args)...));
             /* Visual studio 2015 parser issue: need parentheses around this expression */
             return (retval.template cast<Return>());
         };
@@ -33,10 +32,8 @@
     }
 
     template <typename Func>
-    static PyObject *cast(Func &&f_, return_value_policy policy, PyObject *) {
-        cpp_function f(std::forward<Func>(f_), policy);
-        f.inc_ref();
-        return f.ptr();
+    static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
+        return cpp_function(std::forward<Func>(f_), policy).release();
     }
 
     PYBIND11_TYPE_CASTER(type, _("function<") +
diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h
index 2365a60..0aaac96 100644
--- a/include/pybind11/numpy.h
+++ b/include/pybind11/numpy.h
@@ -79,36 +79,36 @@
         API& api = lookup_api();
         PyObject *descr = api.PyArray_DescrFromType_(npy_format_descriptor<Type>::value);
         if (descr == nullptr)
-            throw std::runtime_error("NumPy: unsupported buffer format!");
+            pybind11_fail("NumPy: unsupported buffer format!");
         Py_intptr_t shape = (Py_intptr_t) size;
         object tmp = object(api.PyArray_NewFromDescr_(
             api.PyArray_Type_, descr, 1, &shape, nullptr, (void *) ptr, 0, nullptr), false);
         if (ptr && tmp)
             tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
         if (!tmp)
-            throw std::runtime_error("NumPy: unable to create array!");
-        m_ptr = tmp.release();
+            pybind11_fail("NumPy: unable to create array!");
+        m_ptr = tmp.release().ptr();
     }
 
     array(const buffer_info &info) {
         API& api = lookup_api();
         if ((info.format.size() < 1) || (info.format.size() > 2))
-            throw std::runtime_error("Unsupported buffer format!");
+            pybind11_fail("Unsupported buffer format!");
         int fmt = (int) info.format[0];
         if (info.format == "Zd")      fmt = API::NPY_CDOUBLE_;
         else if (info.format == "Zf") fmt = API::NPY_CFLOAT_;
 
         PyObject *descr = api.PyArray_DescrFromType_(fmt);
         if (descr == nullptr)
-            throw std::runtime_error("NumPy: unsupported buffer format '" + info.format + "'!");
+            pybind11_fail("NumPy: unsupported buffer format '" + info.format + "'!");
         object tmp(api.PyArray_NewFromDescr_(
             api.PyArray_Type_, descr, info.ndim, (Py_intptr_t *) &info.shape[0],
             (Py_intptr_t *) &info.strides[0], info.ptr, 0, nullptr), false);
         if (info.ptr && tmp)
             tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
         if (!tmp)
-            throw std::runtime_error("NumPy: unable to create array!");
-        m_ptr = tmp.release();
+            pybind11_fail("NumPy: unable to create array!");
+        m_ptr = tmp.release().ptr();
     }
 
 protected:
@@ -186,7 +186,7 @@
         /* Check if the parameters are actually compatible */
         for (size_t i=0; i<N; ++i)
             if (buffers[i].size != 1 && (buffers[i].ndim != ndim || buffers[i].shape != shape))
-                throw std::runtime_error("pybind11::vectorize: incompatible size/dimension of inputs!");
+                pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!");
 
         if (size == 1)
             return cast(f(*((Args *) buffers[Index].ptr)...));
diff --git a/include/pybind11/operators.h b/include/pybind11/operators.h
index 4c97c36..9865d44 100644
--- a/include/pybind11/operators.h
+++ b/include/pybind11/operators.h
@@ -45,17 +45,17 @@
 
 /// Operator implementation generator
 template <op_id id, op_type ot, typename L, typename R> struct op_ {
-    template <typename Base, typename Holder, typename... Extra> void execute(pybind11::class_<Base, Holder> &class_, Extra&&... extra) const {
+    template <typename Base, typename Holder, typename... Extra> void execute(pybind11::class_<Base, Holder> &class_, const Extra&... extra) const {
         typedef typename std::conditional<std::is_same<L, self_t>::value, Base, L>::type L_type;
         typedef typename std::conditional<std::is_same<R, self_t>::value, Base, R>::type R_type;
         typedef op_impl<id, ot, Base, L_type, R_type> op;
-        class_.def(op::name(), &op::execute, std::forward<Extra>(extra)...);
+        class_.def(op::name(), &op::execute, extra...);
     }
-    template <typename Base, typename Holder, typename... Extra> void execute_cast(pybind11::class_<Base, Holder> &class_, Extra&&... extra) const {
+    template <typename Base, typename Holder, typename... Extra> void execute_cast(pybind11::class_<Base, Holder> &class_, const Extra&... extra) const {
         typedef typename std::conditional<std::is_same<L, self_t>::value, Base, L>::type L_type;
         typedef typename std::conditional<std::is_same<R, self_t>::value, Base, R>::type R_type;
         typedef op_impl<id, ot, Base, L_type, R_type> op;
-        class_.def(op::name(), &op::execute_cast, std::forward<Extra>(extra)...);
+        class_.def(op::name(), &op::execute_cast, extra...);
     }
 };
 
diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index df43217..9fecaa9 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -1,5 +1,6 @@
 /*
-    pybind11/pybind11.h: Main header file of the C++11 python binding generator library
+    pybind11/pybind11.h: Main header file of the C++11 python
+    binding generator library
 
     Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
 
@@ -10,131 +11,26 @@
 #pragma once
 
 #if defined(_MSC_VER)
-#pragma warning(push)
-#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
-#pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning)
-#pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
-#pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter
-#pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted
+#  pragma warning(push)
+#  pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
+#  pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning)
+#  pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
+#  pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter
+#  pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted
 #elif defined(__GNUG__) and !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
+#  pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#  pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 #endif
 
-#include "cast.h"
+#include "attr.h"
 
 NAMESPACE_BEGIN(pybind11)
 
-template <typename T> struct arg_t;
-
-/// Annotation for keyword arguments
-struct arg {
-    arg(const char *name) : name(name) { }
-    template <typename T> arg_t<T> operator=(const T &value);
-    const char *name;
-};
-
-/// Annotation for keyword arguments with default values
-template <typename T> struct arg_t : public arg {
-    arg_t(const char *name, const T &value, const char *descr = nullptr)
-        : arg(name), value(value), descr(descr) { }
-    T value;
-    const char *descr;
-};
-
-template <typename T> arg_t<T> arg::operator=(const T &value) { return arg_t<T>(name, value); }
-
-/// Annotation for methods
-struct is_method { PyObject *class_; is_method(object *o) : class_(o->ptr()) { } };
-
-/// Annotation for documentation
-struct doc { const char *value; doc(const char *value) : value(value) { } };
-
-/// Annotation for function names
-struct name { const char *value; name(const char *value) : value(value) { } };
-
-/// Annotation indicating that a function is an overload associated with a given "sibling"
-struct sibling { PyObject *value; sibling(handle value) : value(value.ptr()) { } };
-
-/// Keep patient alive while nurse lives
-template <int Nurse, int Patient> struct keep_alive { };
-
-NAMESPACE_BEGIN(detail)
-
-/// Partial template helper to invoke function call policies (e.g. keep_alive) when a function is called
-template <typename... Args> struct process_dynamic;
-
-/// Default implementation: do nothing
-template <typename T> struct process_dynamic<T> {
-    static void precall(PyObject *) { }
-    static void postcall(PyObject *, PyObject *) { }
-};
-
-/// Recursively iterate over variadic template arguments
-template <typename T, typename... Args> struct process_dynamic<T, Args...> {
-    static void precall(PyObject *arg) {
-        process_dynamic<T>::precall(arg);
-        process_dynamic<Args...>::precall(arg);
-    }
-    static void postcall(PyObject *arg, PyObject *ret) {
-        process_dynamic<T>::postcall(arg, ret);
-        process_dynamic<Args...>::postcall(arg, ret);
-    }
-};
-
-template <> struct process_dynamic<> : public process_dynamic<void> { };
-
-NAMESPACE_END(detail)
-
 /// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
 class cpp_function : public function {
 protected:
-    /// Special data structure which holds metadata about a bound function (signature, overloads, etc.)
-    struct function_entry {
-        /// Function name
-        char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
-
-        // User-specified documentation string
-        char *doc = nullptr;
-
-        /// Human-readable version of the function signature
-        char *signature = nullptr;
-
-        /// List of registered keyword arguments
-        std::vector<detail::argument_entry> args;
-
-        /// Pointer to lambda function which converts arguments and performs the actual call
-        PyObject * (*impl) (function_entry *, PyObject *, PyObject *) = nullptr;
-
-        /// Storage for the wrapped function pointer and captured data, if any
-        void *data = nullptr;
-
-        /// Pointer to custom destructor for 'data' (if needed)
-        void (*free_data) (void *ptr) = nullptr;
-
-        /// Return value policy associated with this function
-        return_value_policy policy = return_value_policy::automatic;
-
-        /// True if name == '__init__'
-        bool is_constructor = false;
-
-        /// Python method object
-        PyMethodDef *def = nullptr;
-
-        /// Pointer to class (if this is method)
-        PyObject *class_ = nullptr;
-
-        /// Pointer to first registered function in overload chain
-        PyObject *sibling = nullptr;
-
-        /// Pointer to next overload
-        function_entry *next = nullptr;
-    };
-
-    function_entry *m_entry;
-
     /// Picks a suitable return value converter from cast.h
     template <typename T> using return_value_caster =
         detail::type_caster<typename std::conditional<
@@ -143,317 +39,135 @@
     /// Picks a suitable argument value converter from cast.h
     template <typename... T> using arg_value_caster =
         detail::type_caster<typename std::tuple<T...>>;
-
-    /// Deal with annotations that can be processed at function registration time
-    template <typename... T> static void process_static(const std::tuple<T...> &args, function_entry *entry) {
-        process_static(args, entry, typename detail::make_index_sequence<sizeof...(T)>::type());
-    }
-
-    /// contd.
-    template <typename... T, size_t ... Index> static void process_static(const std::tuple<T...> &args,
-            function_entry *entry, detail::index_sequence<Index...>) {
-        int unused[] = { 0, (process_static(std::get<Index>(args), entry), 0)... };
-        (void) unused;
-    }
-
-    /* The following overloads are used to process any annotations passed to
-       cpp_function. They update the corresponding fields in m_entry */
-
-    /// Process an annotation specifying the function's name
-    static void process_static(const pybind11::name &n, function_entry *entry) { entry->name = (char *) n.value; }
-
-    /// Process an annotation specifying function's docstring (provided as a C-style string)
-    static void process_static(const char *doc, function_entry *entry) { entry->doc = (char *) doc; }
-
-    /// Process an annotation specifying function's docstring
-    static void process_static(const pybind11::doc &d, function_entry *entry) { entry->doc = (char *) d.value; }
-
-    /// Process an annotation indicating the function's return value policy
-    static void process_static(const pybind11::return_value_policy p, function_entry *entry) { entry->policy = p; }
-
-    /// Process an annotation which indicates that this is an overloaded function associated with a given sibling
-    static void process_static(const pybind11::sibling s, function_entry *entry) { entry->sibling = s.value; }
-
-    /// Process an annotation which indicates that this function is a method
-    static void process_static(const pybind11::is_method &m, function_entry *entry) { entry->class_ = m.class_; }
-
-    /// Process a keyword argument annotation (*without* a default value)
-    static void process_static(const pybind11::arg &a, function_entry *entry) {
-        if (entry->class_ && entry->args.empty())
-            entry->args.emplace_back("self", nullptr, nullptr);
-        entry->args.emplace_back(a.name, nullptr, nullptr);
-    }
-
-    /// Process a keyword argument annotation (with a default value)
-    template <typename T>
-    static void process_static(const pybind11::arg_t<T> &a, function_entry *entry) {
-        if (entry->class_ && entry->args.empty())
-            entry->args.emplace_back("self", nullptr, nullptr);
-
-        /* Convert keyword value into a Python object */
-        PyObject *obj = detail::type_caster<typename detail::intrinsic_type<T>::type>::cast(
-                a.value, return_value_policy::automatic, nullptr);
-
-        if (obj == nullptr)
-            pybind11_fail("arg(): could not convert default keyword "
-                          "argument into a Python object (type not "
-                          "registered yet?)");
-
-        entry->args.emplace_back(a.name, a.descr, obj);
-    }
-
-    /// Process an annotation indicating a keep_alive call policy
-    template <int Nurse, int Patient>
-    static void process_static(const keep_alive<Nurse, Patient> &, function_entry *) { /* handled at call time */ }
 public:
     cpp_function() { }
 
     /// Vanilla function pointers
     template <typename Return, typename... Args, typename... Extra>
-    cpp_function(Return (*f)(Args...), Extra&&... extra) {
-        using detail::descr;
-        m_entry = new function_entry();
-        m_entry->data = (void *) f;
+    cpp_function(Return (*f)(Args...), const Extra&... extra) {
+        auto rec = new detail::function_record();
+        rec->data = (void *) f;
 
         typedef arg_value_caster<Args...> cast_in;
         typedef return_value_caster<Return> cast_out;
 
         /* Dispatch code which converts function arguments and performs the actual function call */
-        m_entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *parent) -> PyObject * {
+        rec->impl = [](detail::function_record *rec, handle pyArgs, handle parent) -> handle {
             cast_in args;
 
             /* Try to cast the function arguments into the C++ domain */
             if (!args.load(pyArgs, true))
                 return PYBIND11_TRY_NEXT_OVERLOAD;
 
-            detail::process_dynamic<Extra...>::precall(pyArgs); // call policy precall
+            /* Invoke call policy pre-call hook */
+            detail::process_attributes<Extra...>::precall(pyArgs);
 
             /* Do the call and convert the return value back into the Python domain */
-            PyObject *result = cast_out::cast(
-                args.template call<Return>((Return (*) (Args...)) entry->data),
-                entry->policy, parent);
+            handle result = cast_out::cast(
+                args.template call<Return>((Return (*) (Args...)) rec->data),
+                rec->policy, parent);
 
-            detail::process_dynamic<Extra...>::postcall(pyArgs, result); // call policy postcall
+            /* Invoke call policy post-call hook */
+            detail::process_attributes<Extra...>::postcall(pyArgs, result);
+
             return result;
         };
 
-        /* Process any user-provided function annotations */
-        process_static(std::make_tuple(std::forward<Extra>(extra)...), m_entry);
+        /* Process any user-provided function attributes */
+        detail::process_attributes<Extra...>::init(extra..., rec);
 
         /* Generate a readable signature describing the function's arguments and return value types */
+        using detail::descr;
         PYBIND11_DESCR signature = cast_in::name() + detail::_(" -> ") + cast_out::name();
 
         /* Register the function with Python from generic (non-templated) code */
-        initialize(signature.text(), signature.types(), sizeof...(Args));
+        initialize(rec, signature.text(), signature.types(), sizeof...(Args));
     }
 
     /// Delegating helper constructor to deal with lambda functions
-    template <typename Func, typename... Extra> cpp_function(Func &&f, Extra&&... extra) {
+    template <typename Func, typename... Extra> cpp_function(Func &&f, const Extra&... extra) {
         initialize(std::forward<Func>(f),
                    (typename detail::remove_class<decltype(
-                       &std::remove_reference<Func>::type::operator())>::type *) nullptr,
-                   std::forward<Extra>(extra)...);
+                       &std::remove_reference<Func>::type::operator())>::type *) nullptr, extra...);
     }
 
     /// Delegating helper constructor to deal with class methods (non-const)
     template <typename Return, typename Class, typename... Arg, typename... Extra> cpp_function(
-            Return (Class::*f)(Arg...), Extra&&... extra) {
+            Return (Class::*f)(Arg...), const Extra&... extra) {
         initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); },
-                   (Return (*) (Class *, Arg...)) nullptr, std::forward<Extra>(extra)...);
+                   (Return (*) (Class *, Arg...)) nullptr, extra...);
     }
 
     /// Delegating helper constructor to deal with class methods (const)
     template <typename Return, typename Class, typename... Arg, typename... Extra> cpp_function(
-            Return (Class::*f)(Arg...) const, Extra&&... extra) {
+            Return (Class::*f)(Arg...) const, const Extra&... extra) {
         initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); },
-                   (Return (*)(const Class *, Arg ...)) nullptr, std::forward<Extra>(extra)...);
+                   (Return (*)(const Class *, Arg ...)) nullptr, extra...);
     }
 
     /// Return the function name
-    const char *name() const { return m_entry->name; }
+    object name() const { return attr("__name__"); }
 
 protected:
     /// Special internal constructor for functors, lambda functions, etc.
     template <typename Func, typename Return, typename... Args, typename... Extra>
-    void initialize(Func &&f, Return (*)(Args...), Extra&&... extra) {
-        using detail::descr;
+    void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) {
         struct capture { typename std::remove_reference<Func>::type f; };
 
         /* Store the function including any extra state it might have (e.g. a lambda capture object) */
-        m_entry = new function_entry();
-        m_entry->data = new capture { std::forward<Func>(f) };
+        auto rec = new detail::function_record();
+        rec->data = new capture { std::forward<Func>(f) };
 
         /* Create a cleanup handler, but only if we have to (less generated code) */
         if (!std::is_trivially_destructible<Func>::value)
-            m_entry->free_data = [](void *ptr) { delete (capture *) ptr; };
+            rec->free_data = [](void *ptr) { delete (capture *) ptr; };
         else
-            m_entry->free_data = operator delete;
+            rec->free_data = operator delete;
 
         typedef arg_value_caster<Args...> cast_in;
         typedef return_value_caster<Return> cast_out;
 
         /* Dispatch code which converts function arguments and performs the actual function call */
-        m_entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *parent) -> PyObject *{
+        rec->impl = [](detail::function_record *rec, handle pyArgs, handle parent) -> handle {
             cast_in args;
 
             /* Try to cast the function arguments into the C++ domain */
             if (!args.load(pyArgs, true))
                 return PYBIND11_TRY_NEXT_OVERLOAD;
 
-            detail::process_dynamic<Extra...>::precall(pyArgs); // call policy precall
+            /* Invoke call policy pre-call hook */
+            detail::process_attributes<Extra...>::precall(pyArgs);
 
             /* Do the call and convert the return value back into the Python domain */
-            PyObject *result = cast_out::cast(
-                args.template call<Return>(((capture *) entry->data)->f),
-                entry->policy, parent);
+            handle result = cast_out::cast(
+                args.template call<Return>(((capture *) rec->data)->f),
+                rec->policy, parent);
 
-            detail::process_dynamic<Extra...>::postcall(pyArgs, result); // call policy postcall
+            /* Invoke call policy post-call hook */
+            detail::process_attributes<Extra...>::postcall(pyArgs, result);
+
             return result;
         };
 
-        /* Process any user-provided function annotations */
-        process_static(std::make_tuple(std::forward<Extra>(extra)...), m_entry);
+        /* Process any user-provided function attributes */
+        detail::process_attributes<Extra...>::init(extra..., rec);
 
         /* Generate a readable signature describing the function's arguments and return value types */
+        using detail::descr;
         PYBIND11_DESCR signature = cast_in::name() + detail::_(" -> ") + cast_out::name();
 
         /* Register the function with Python from generic (non-templated) code */
-        initialize(signature.text(), signature.types(), sizeof...(Args));
-    }
-
-    /// Main dispatch logic for calls to functions bound using pybind11
-    static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs) {
-        /* Iterator over the list of potentially admissible overloads */
-        function_entry *overloads = (function_entry *) PyCapsule_GetPointer(self, nullptr),
-                       *it = overloads;
-
-        /* Need to know how many arguments + keyword arguments there are to pick the right overload */
-        int nargs = (int) PyTuple_Size(args),
-            nkwargs = kwargs ? (int) PyDict_Size(kwargs) : 0;
-
-        PyObject *parent = nargs > 0 ? PyTuple_GetItem(args, 0) : nullptr,
-                 *result = PYBIND11_TRY_NEXT_OVERLOAD;
-        try {
-            for (; it != nullptr; it = it->next) {
-                object args_(args, true);
-                int kwargs_consumed = 0;
-
-                /* For each overload:
-                   1. If the required list of arguments is longer than the
-                      actually provided amount, create a copy of the argument
-                      list and fill in any available keyword/default arguments.
-                   2. Ensure that all keyword arguments were "consumed"
-                   3. Call the function call dispatcher (function_entry::impl)
-                 */
-
-                if (nargs < (int) it->args.size()) {
-                    args_ = object(PyTuple_New(it->args.size()), false);
-                    for (int i = 0; i < nargs; ++i) {
-                        PyObject *item = PyTuple_GET_ITEM(args, i);
-                        Py_INCREF(item);
-                        PyTuple_SET_ITEM(args_.ptr(), i, item);
-                    }
-                    int arg_ctr = 0;
-                    for (auto const &it2 : it->args) {
-                        int index = arg_ctr++;
-                        if (PyTuple_GET_ITEM(args_.ptr(), index))
-                            continue;
-                        PyObject *value = nullptr;
-                        if (kwargs)
-                            value = PyDict_GetItemString(kwargs, it2.name);
-                        if (value)
-                            kwargs_consumed++;
-                        else if (it2.value)
-                            value = it2.value;
-                        if (value) {
-                            Py_INCREF(value);
-                            PyTuple_SET_ITEM(args_.ptr(), index, value);
-                        } else {
-                            kwargs_consumed = -1; /* definite failure */
-                            break;
-                        }
-                    }
-                }
-
-                if (kwargs_consumed == nkwargs)
-                    result = it->impl(it, args_.ptr(), parent);
-
-                if (result != PYBIND11_TRY_NEXT_OVERLOAD)
-                    break;
-            }
-        } catch (const error_already_set &)      {                                                 return nullptr;
-        } catch (const index_error &e)           { PyErr_SetString(PyExc_IndexError,    e.what()); return nullptr;
-        } catch (const stop_iteration &e)        { PyErr_SetString(PyExc_StopIteration, e.what()); return nullptr;
-        } catch (const std::bad_alloc &e)        { PyErr_SetString(PyExc_MemoryError,   e.what()); return nullptr;
-        } catch (const std::domain_error &e)     { PyErr_SetString(PyExc_ValueError,    e.what()); return nullptr;
-        } catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError,    e.what()); return nullptr;
-        } catch (const std::length_error &e)     { PyErr_SetString(PyExc_ValueError,    e.what()); return nullptr;
-        } catch (const std::out_of_range &e)     { PyErr_SetString(PyExc_IndexError,    e.what()); return nullptr;
-        } catch (const std::range_error &e)      { PyErr_SetString(PyExc_ValueError,    e.what()); return nullptr;
-        } catch (const std::exception &e)        { PyErr_SetString(PyExc_RuntimeError,  e.what()); return nullptr;
-        } catch (...) {
-            PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!");
-            return nullptr;
-        }
-
-        if (result == PYBIND11_TRY_NEXT_OVERLOAD) {
-            std::string msg = "Incompatible function arguments. The "
-                              "following argument types are supported:\n";
-            int ctr = 0;
-            for (function_entry *it2 = overloads; it2 != nullptr; it2 = it2->next) {
-                msg += "    "+ std::to_string(++ctr) + ". ";
-                msg += it2->signature;
-                msg += "\n";
-            }
-            PyErr_SetString(PyExc_TypeError, msg.c_str());
-            return nullptr;
-        } else if (result == nullptr) {
-            std::string msg = "Unable to convert function return value to a "
-                              "Python type! The signature was\n\t";
-            msg += it->signature;
-            PyErr_SetString(PyExc_TypeError, msg.c_str());
-            return nullptr;
-        } else {
-            if (overloads->is_constructor) {
-                /* When a construtor ran successfully, the corresponding
-                   holder type (e.g. std::unique_ptr) must still be initialized. */
-                PyObject *inst = PyTuple_GetItem(args, 0);
-                auto tinfo = detail::get_type_info(Py_TYPE(inst));
-                tinfo->init_holder(inst, nullptr);
-            }
-            return result;
-        }
-    }
-
-    /// When a cpp_function is GCed, release any memory allocated by pybind11
-    static void destruct(function_entry *entry) {
-        while (entry) {
-            function_entry *next = entry->next;
-            if (entry->free_data)
-                entry->free_data(entry->data);
-            std::free((char *) entry->name);
-            std::free((char *) entry->doc);
-            std::free((char *) entry->signature);
-            for (auto &arg: entry->args) {
-                std::free((char *) arg.name);
-                std::free((char *) arg.descr);
-                Py_XDECREF(arg.value);
-            }
-            if (entry->def) {
-                std::free((char *) entry->def->ml_doc);
-                delete entry->def;
-            }
-            delete entry;
-            entry = next;
-        }
+        initialize(rec, signature.text(), signature.types(), sizeof...(Args));
     }
 
     /// Register a function call with Python (generic non-templated code goes here)
-    void initialize(const char *text, const std::type_info * const * types, int args) {
+    void initialize(detail::function_record *rec, const char *text,
+                    const std::type_info *const *types, int args) {
+
         /* Create copies of all referenced C-style strings */
-        m_entry->name = strdup(m_entry->name ? m_entry->name : "");
-        if (m_entry->doc) m_entry->doc = strdup(m_entry->doc);
-        for (auto &a: m_entry->args) {
+        rec->name = strdup(rec->name ? rec->name : "");
+        if (rec->doc) rec->doc = strdup(rec->doc);
+        for (auto &a: rec->args) {
             if (a.name)
                 a.name = strdup(a.name);
             if (a.descr)
@@ -472,17 +186,17 @@
                 break;
 
             if (c == '{') {
-                if (type_depth == 1 && arg_index < m_entry->args.size()) {
-                    signature += m_entry->args[arg_index].name;
+                if (type_depth == 1 && arg_index < rec->args.size()) {
+                    signature += rec->args[arg_index].name;
                     signature += " : ";
                 }
                 ++type_depth;
             } else if (c == '}') {
                 --type_depth;
-                if (type_depth == 1 && arg_index < m_entry->args.size()) {
-                    if (m_entry->args[arg_index].descr) {
+                if (type_depth == 1 && arg_index < rec->args.size()) {
+                    if (rec->args[arg_index].descr) {
                         signature += " = ";
-                        signature += m_entry->args[arg_index].descr;
+                        signature += rec->args[arg_index].descr;
                     }
                     arg_index++;
                 }
@@ -511,67 +225,66 @@
         #endif
 
 #if PY_MAJOR_VERSION < 3
-        if (strcmp(m_entry->name, "__next__") == 0) {
-            std::free(m_entry->name);
-            m_entry->name = strdup("next");
+        if (strcmp(rec->name, "__next__") == 0) {
+            std::free(rec->name);
+            rec->name = strdup("next");
         }
 #endif
 
-        if (!m_entry->args.empty() && (int) m_entry->args.size() != args)
+        if (!rec->args.empty() && (int) rec->args.size() != args)
             pybind11_fail(
-                "cpp_function(): function \"" + std::string(m_entry->name) + "\" takes " +
-                std::to_string(args) + " arguments, but " + std::to_string(m_entry->args.size()) +
+                "cpp_function(): function \"" + std::string(rec->name) + "\" takes " +
+                std::to_string(args) + " arguments, but " + std::to_string(rec->args.size()) +
                 " pybind11::arg entries were specified!");
 
-        m_entry->is_constructor = !strcmp(m_entry->name, "__init__");
-        m_entry->signature = strdup(signature.c_str());
-        m_entry->args.shrink_to_fit();
+        rec->is_constructor = !strcmp(rec->name, "__init__");
+        rec->signature = strdup(signature.c_str());
+        rec->args.shrink_to_fit();
 
 #if PY_MAJOR_VERSION < 3
-        if (m_entry->sibling && PyMethod_Check(m_entry->sibling))
-            m_entry->sibling = PyMethod_GET_FUNCTION(m_entry->sibling);
+        if (rec->sibling && PyMethod_Check(rec->sibling.ptr()))
+            rec->sibling = PyMethod_GET_FUNCTION(rec->sibling.ptr());
 #endif
 
-        function_entry *s_entry = nullptr, *entry = m_entry;
-        if (m_entry->sibling && PyCFunction_Check(m_entry->sibling)) {
-            capsule entry_capsule(PyCFunction_GetSelf(m_entry->sibling), true);
-            s_entry = (function_entry *) entry_capsule;
+        detail::function_record *chain = nullptr, *chain_start = rec;
+        if (rec->sibling && PyCFunction_Check(rec->sibling.ptr())) {
+            capsule rec_capsule(PyCFunction_GetSelf(rec->sibling.ptr()), true);
+            chain = (detail::function_record *) rec_capsule;
             /* Never append a method to an overload chain of a parent class;
                instead, hide the parent's overloads in this case */
-            if (s_entry->class_ != m_entry->class_)
-                s_entry = nullptr;
+            if (chain->class_ != rec->class_)
+                chain = nullptr;
         }
 
-        if (!s_entry) {
+        if (!chain) {
             /* No existing overload was found, create a new function object */
-            m_entry->def = new PyMethodDef();
-            memset(m_entry->def, 0, sizeof(PyMethodDef));
-            m_entry->def->ml_name = m_entry->name;
-            m_entry->def->ml_meth = reinterpret_cast<PyCFunction>(*dispatcher);
-            m_entry->def->ml_flags = METH_VARARGS | METH_KEYWORDS;
-            capsule entry_capsule(m_entry, [](PyObject *o) {
-                destruct((function_entry *) PyCapsule_GetPointer(o, nullptr));
+            rec->def = new PyMethodDef();
+            memset(rec->def, 0, sizeof(PyMethodDef));
+            rec->def->ml_name = rec->name;
+            rec->def->ml_meth = reinterpret_cast<PyCFunction>(*dispatcher);
+            rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS;
+            capsule rec_capsule(rec, [](PyObject *o) {
+                destruct((detail::function_record *) PyCapsule_GetPointer(o, nullptr));
             });
-            m_ptr = PyCFunction_New(m_entry->def, entry_capsule.ptr());
+            m_ptr = PyCFunction_New(rec->def, rec_capsule.ptr());
             if (!m_ptr)
                 pybind11_fail("cpp_function::cpp_function(): Could not allocate function object");
         } else {
             /* Append at the end of the overload chain */
-            m_ptr = m_entry->sibling;
+            m_ptr = rec->sibling.ptr();
             inc_ref();
-            entry = s_entry;
-            while (s_entry->next)
-                s_entry = s_entry->next;
-            s_entry->next = m_entry;
+            chain_start = chain;
+            while (chain->next)
+                chain = chain->next;
+            chain->next = rec;
         }
 
         std::string signatures;
         int index = 0;
-        function_entry *it = entry;
-        /* Create a nice pydoc entry including all signatures and
+        /* Create a nice pydoc rec including all signatures and
            docstrings of the functions in the overload chain */
-        while (it) {
-            if (s_entry)
+        for (auto it = chain_start; it != nullptr; it = it->next) {
+            if (chain)
                 signatures += std::to_string(++index) + ". ";
             signatures += "Signature : ";
             signatures += it->signature;
@@ -583,23 +296,150 @@
             }
             if (it->next)
                 signatures += "\n";
-            it = it->next;
         }
+
+        /* Install docstring */
         PyCFunctionObject *func = (PyCFunctionObject *) m_ptr;
         if (func->m_ml->ml_doc)
             std::free((char *) func->m_ml->ml_doc);
         func->m_ml->ml_doc = strdup(signatures.c_str());
-        if (entry->class_) {
-#if PY_MAJOR_VERSION >= 3
-            m_ptr = PyInstanceMethod_New(m_ptr);
-#else
-            m_ptr = PyMethod_New(m_ptr, nullptr, entry->class_);
-#endif
+
+        if (rec->class_) {
+            m_ptr = PYBIND11_INSTANCE_METHOD_NEW(m_ptr, rec->class_.ptr());
             if (!m_ptr)
                 pybind11_fail("cpp_function::cpp_function(): Could not allocate instance method object");
             Py_DECREF(func);
         }
     }
+
+    /// When a cpp_function is GCed, release any memory allocated by pybind11
+    static void destruct(detail::function_record *rec) {
+        while (rec) {
+            detail::function_record *next = rec->next;
+            if (rec->free_data)
+                rec->free_data(rec->data);
+            std::free((char *) rec->name);
+            std::free((char *) rec->doc);
+            std::free((char *) rec->signature);
+            for (auto &arg: rec->args) {
+                std::free((char *) arg.name);
+                std::free((char *) arg.descr);
+                arg.value.dec_ref();
+            }
+            if (rec->def) {
+                std::free((char *) rec->def->ml_doc);
+                delete rec->def;
+            }
+            delete rec;
+            rec = next;
+        }
+    }
+
+    /// Main dispatch logic for calls to functions bound using pybind11
+    static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs) {
+        /* Iterator over the list of potentially admissible overloads */
+        detail::function_record *overloads = (detail::function_record *) PyCapsule_GetPointer(self, nullptr),
+                                *it = overloads;
+
+        /* Need to know how many arguments + keyword arguments there are to pick the right overload */
+        int nargs = (int) PyTuple_Size(args),
+            nkwargs = kwargs ? (int) PyDict_Size(kwargs) : 0;
+
+        handle parent = nargs > 0 ? PyTuple_GetItem(args, 0) : nullptr,
+               result = PYBIND11_TRY_NEXT_OVERLOAD;
+        try {
+            for (; it != nullptr; it = it->next) {
+                tuple args_(args, true);
+                int kwargs_consumed = 0;
+
+                /* For each overload:
+                   1. If the required list of arguments is longer than the
+                      actually provided amount, create a copy of the argument
+                      list and fill in any available keyword/default arguments.
+                   2. Ensure that all keyword arguments were "consumed"
+                   3. Call the function call dispatcher (function_record::impl)
+                 */
+
+                if (nargs < (int) it->args.size()) {
+                    args_ = tuple(it->args.size());
+                    for (int i = 0; i < nargs; ++i) {
+                        handle item = PyTuple_GET_ITEM(args, i);
+                        PyTuple_SET_ITEM(args_.ptr(), i, item.inc_ref().ptr());
+                    }
+
+                    int arg_ctr = 0;
+                    for (auto const &it2 : it->args) {
+                        int index = arg_ctr++;
+                        if (PyTuple_GET_ITEM(args_.ptr(), index))
+                            continue;
+
+                        handle value;
+                        if (kwargs)
+                            value = PyDict_GetItemString(kwargs, it2.name);
+
+                        if (value)
+                            kwargs_consumed++;
+                        else if (it2.value)
+                            value = it2.value;
+
+                        if (value) {
+                            PyTuple_SET_ITEM(args_.ptr(), index, value.inc_ref().ptr());
+                        } else {
+                            kwargs_consumed = -1; /* definite failure */
+                            break;
+                        }
+                    }
+                }
+
+                if (kwargs_consumed == nkwargs)
+                    result = it->impl(it, args_, parent);
+
+                if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD)
+                    break;
+            }
+        } catch (const error_already_set &)      {                                                 return nullptr;
+        } catch (const index_error &e)           { PyErr_SetString(PyExc_IndexError,    e.what()); return nullptr;
+        } catch (const stop_iteration &e)        { PyErr_SetString(PyExc_StopIteration, e.what()); return nullptr;
+        } catch (const std::bad_alloc &e)        { PyErr_SetString(PyExc_MemoryError,   e.what()); return nullptr;
+        } catch (const std::domain_error &e)     { PyErr_SetString(PyExc_ValueError,    e.what()); return nullptr;
+        } catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError,    e.what()); return nullptr;
+        } catch (const std::length_error &e)     { PyErr_SetString(PyExc_ValueError,    e.what()); return nullptr;
+        } catch (const std::out_of_range &e)     { PyErr_SetString(PyExc_IndexError,    e.what()); return nullptr;
+        } catch (const std::range_error &e)      { PyErr_SetString(PyExc_ValueError,    e.what()); return nullptr;
+        } catch (const std::exception &e)        { PyErr_SetString(PyExc_RuntimeError,  e.what()); return nullptr;
+        } catch (...) {
+            PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!");
+            return nullptr;
+        }
+
+        if (result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) {
+            std::string msg = "Incompatible function arguments. The "
+                              "following argument types are supported:\n";
+            int ctr = 0;
+            for (detail::function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) {
+                msg += "    "+ std::to_string(++ctr) + ". ";
+                msg += it2->signature;
+                msg += "\n";
+            }
+            PyErr_SetString(PyExc_TypeError, msg.c_str());
+            return nullptr;
+        } else if (!result) {
+            std::string msg = "Unable to convert function return value to a "
+                              "Python type! The signature was\n\t";
+            msg += it->signature;
+            PyErr_SetString(PyExc_TypeError, msg.c_str());
+            return nullptr;
+        } else {
+            if (overloads->is_constructor) {
+                /* When a construtor ran successfully, the corresponding
+                   holder type (e.g. std::unique_ptr) must still be initialized. */
+                PyObject *inst = PyTuple_GetItem(args, 0);
+                auto tinfo = detail::get_type_info(Py_TYPE(inst));
+                tinfo->init_holder(inst, nullptr);
+            }
+            return result.ptr();
+        }
+    }
 };
 
 /// Wrapper for Python extension modules
@@ -625,11 +465,11 @@
     }
 
     template <typename Func, typename... Extra>
-    module &def(const char *name_, Func &&f, Extra&& ... extra) {
+    module &def(const char *name_, Func &&f, const Extra& ... extra) {
         cpp_function func(std::forward<Func>(f), name(name_),
-                          sibling((handle) attr(name_)), std::forward<Extra>(extra)...);
-        func.inc_ref(); /* The following line steals a reference to 'func' */
-        PyModule_AddObject(ptr(), name_, func.ptr());
+                          sibling((handle) attr(name_)), extra...);
+        /* PyModule_AddObject steals a reference to 'func' */
+        PyModule_AddObject(ptr(), name_, func.inc_ref().ptr());
         return *this;
     }
 
@@ -652,18 +492,27 @@
 };
 
 NAMESPACE_BEGIN(detail)
-/// Basic support for creating new Python heap types
+/// Generic support for creating new Python heap types
 class generic_type : public object {
+    template <typename type, typename holder_type> friend class class_;
 public:
     PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check)
-
-    generic_type(const object &scope, const char *name_, const std::type_info *type_cpp,
-                size_t type_size, size_t instance_size,
-                void (*init_holder)(PyObject *, const void *),
-                const destructor &dealloc, object parent, const char *doc) {
+protected:
+    void initialize(type_record *rec) {
+        if (rec->base_type) {
+            if (rec->base_handle)
+                pybind11_fail("generic_type: specified base type multiple times!");
+            rec->base_handle = detail::get_type_handle(*(rec->base_type));
+            if (!rec->base_handle) {
+                std::string tname(rec->base_type->name());
+                detail::clean_type_id(tname);
+                pybind11_fail("generic_type: type \"" + std::string(rec->name) +
+                              "\" referenced unknown base type \"" + tname + "\"");
+            }
+        }
 
         object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false);
-        object name(PYBIND11_FROM_STRING(name_), false);
+        object name(PYBIND11_FROM_STRING(rec->name), false);
         auto type = (PyHeapTypeObject*) type_holder.ptr();
 
         if (!type_holder || !name)
@@ -673,25 +522,26 @@
         auto &internals = get_internals();
         detail::type_info *tinfo = new detail::type_info();
         tinfo->type = (PyTypeObject *) type;
-        tinfo->type_size = type_size;
-        tinfo->init_holder = init_holder;
-        internals.registered_types_cpp[type_cpp] = tinfo;
+        tinfo->type_size = rec->type_size;
+        tinfo->init_holder = rec->init_holder;
+        internals.registered_types_cpp[rec->type] = tinfo;
         internals.registered_types_py[type] = tinfo;
 
-        auto scope_module = (object) scope.attr("__module__");
+        auto scope_module = (object) rec->scope.attr("__module__");
         if (!scope_module)
-            scope_module = (object) scope.attr("__name__");
+            scope_module = (object) rec->scope.attr("__name__");
 
-        std::string full_name = (scope_module ? ((std::string) scope_module.str() + "." + name_)
-                                              : std::string(name_));
+        std::string full_name = (scope_module ? ((std::string) scope_module.str() + "." + rec->name)
+                                              : std::string(rec->name));
         /* Basic type attributes */
         type->ht_type.tp_name = strdup(full_name.c_str());
-        type->ht_type.tp_basicsize = instance_size;
-        type->ht_type.tp_base = (PyTypeObject *) parent.release();
+        type->ht_type.tp_basicsize = rec->instance_size;
+        type->ht_type.tp_base = (PyTypeObject *) rec->base_handle.ptr();
+        rec->base_handle.inc_ref();
 
 #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
         /* Qualified names for Python >= 3.3 */
-        auto scope_qualname = (object) scope.attr("__qualname__");
+        auto scope_qualname = (object) rec->scope.attr("__qualname__");
         if (scope_qualname) {
             type->ht_qualname = PyUnicode_FromFormat(
                 "%U.%U", scope_qualname.ptr(), name.ptr());
@@ -700,7 +550,7 @@
             name.inc_ref();
         }
 #endif
-        type->ht_name = name.release();
+        type->ht_name = name.release().ptr();
 
         /* Supported protocols */
         type->ht_type.tp_as_number = &type->as_number;
@@ -710,7 +560,7 @@
         /* Supported elementary operations */
         type->ht_type.tp_init = (initproc) init;
         type->ht_type.tp_new = (newfunc) new_instance;
-        type->ht_type.tp_dealloc = dealloc;
+        type->ht_type.tp_dealloc = rec->dealloc;
 
         /* Support weak references (needed for the keep_alive feature) */
         type->ht_type.tp_weaklistoffset = offsetof(instance<void>, weakrefs);
@@ -722,12 +572,12 @@
 #endif
         type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC;
 
-        if (doc) {
+        if (rec->doc) {
             /* Allocate memory for docstring (using PyObject_MALLOC, since
                Python will free this later on) */
-            size_t size = strlen(doc) + 1;
+            size_t size = strlen(rec->doc) + 1;
             type->ht_type.tp_doc = (char *) PyObject_MALLOC(size);
-            memcpy((void *) type->ht_type.tp_doc, doc, size);
+            memcpy((void *) type->ht_type.tp_doc, rec->doc, size);
         }
 
         if (PyType_Ready(&type->ht_type) < 0)
@@ -736,15 +586,14 @@
         m_ptr = type_holder.ptr();
 
         if (scope_module) // Needed by pydoc
-            type_holder.attr("__module__") = scope_module;
+            attr("__module__") = scope_module;
 
         /* Register type with the parent scope */
-        scope.attr(name_) = *this;
+        rec->scope.attr(handle(type->ht_name)) = *this;
 
         type_holder.release();
     }
 
-protected:
     /// Allocate a metaclass on demand (for static properties)
     handle metaclass() {
         auto &ht_type = ((PyHeapTypeObject *) m_ptr)->ht_type;
@@ -758,17 +607,21 @@
                 pybind11_fail("generic_type::metaclass(): unable to create type object!");
 
             auto type = (PyHeapTypeObject*) type_holder.ptr();
-            type->ht_name = name.release();
-
+            type->ht_name = name.release().ptr();
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
+            /* Qualified names for Python >= 3.3 */
+            type->ht_qualname = PyUnicode_FromFormat(
+                "%U__Meta", ((object) attr("__qualname__")).ptr());
+#endif
             type->ht_type.tp_name = strdup(name_.c_str());
-            type->ht_type.tp_base = &PyType_Type;
+            type->ht_type.tp_base = ob_type;
             type->ht_type.tp_flags |= (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE) &
                                       ~Py_TPFLAGS_HAVE_GC;
 
             if (PyType_Ready(&type->ht_type) < 0)
                 pybind11_fail("generic_type::metaclass(): PyType_Ready failed!");
 
-            ob_type = (PyTypeObject *) type_holder.release();
+            ob_type = (PyTypeObject *) type_holder.release().ptr();
         }
         return handle((PyObject *) ob_type);
     }
@@ -851,65 +704,64 @@
 
     static void releasebuffer(PyObject *, Py_buffer *view) { delete (buffer_info *) view->internal; }
 };
-
-/* Forward declarations */
-enum op_id : int;
-enum op_type : int;
-struct undefined_t;
-template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t> struct op_;
-template <typename... Args> struct init;
 NAMESPACE_END(detail)
 
-template <typename type, typename holder_type = std::unique_ptr<type>> class class_ : public detail::generic_type {
+template <typename type, typename holder_type = std::unique_ptr<type>>
+class class_ : public detail::generic_type {
 public:
     typedef detail::instance<type, holder_type> instance_type;
 
     PYBIND11_OBJECT(class_, detail::generic_type, PyType_Check)
 
-    class_(object &scope, const char *name, const char *doc = nullptr)
-        : detail::generic_type(scope, name, &typeid(type), sizeof(type),
-                              sizeof(instance_type), init_holder, dealloc,
-                              object(), doc) { }
+    template <typename... Extra>
+    class_(handle scope, const char *name, const Extra &... extra) {
+        detail::type_record record;
+        record.scope = scope;
+        record.name = name;
+        record.type = &typeid(type);
+        record.type_size = sizeof(type);
+        record.instance_size = sizeof(instance_type);
+        record.init_holder = init_holder;
+        record.dealloc = dealloc;
 
-    class_(object &scope, const char *name, object &parent,
-           const char *doc = nullptr)
-        : detail::generic_type(scope, name, &typeid(type), sizeof(type),
-                              sizeof(instance_type), init_holder, dealloc,
-                              parent, doc) { }
+        /* Process optional arguments, if any */
+        detail::process_attributes<Extra...>::init(extra..., &record);
+
+        detail::generic_type::initialize(&record);
+    }
 
     template <typename Func, typename... Extra>
-    class_ &def(const char *name_, Func&& f, Extra&&... extra) {
+    class_ &def(const char *name_, Func&& f, const Extra&... extra) {
         cpp_function cf(std::forward<Func>(f), name(name_),
-                        sibling(attr(name_)), is_method(this),
-                        std::forward<Extra>(extra)...);
+                        sibling(attr(name_)), is_method(*this),
+                        extra...);
         attr(cf.name()) = cf;
         return *this;
     }
 
     template <typename Func, typename... Extra> class_ &
-    def_static(const char *name_, Func f, Extra&&... extra) {
+    def_static(const char *name_, Func f, const Extra&... extra) {
         cpp_function cf(std::forward<Func>(f), name(name_),
-                        sibling(attr(name_)),
-                        std::forward<Extra>(extra)...);
+                        sibling(attr(name_)), extra...);
         attr(cf.name()) = cf;
         return *this;
     }
 
     template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
-    class_ &def(const detail::op_<id, ot, L, R> &op, Extra&&... extra) {
-        op.template execute<type>(*this, std::forward<Extra>(extra)...);
+    class_ &def(const detail::op_<id, ot, L, R> &op, const Extra&... extra) {
+        op.template execute<type>(*this, extra...);
         return *this;
     }
 
     template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
-    class_ & def_cast(const detail::op_<id, ot, L, R> &op, Extra&&... extra) {
-        op.template execute_cast<type>(*this, std::forward<Extra>(extra)...);
+    class_ & def_cast(const detail::op_<id, ot, L, R> &op, const Extra&... extra) {
+        op.template execute_cast<type>(*this, extra...);
         return *this;
     }
 
     template <typename... Args, typename... Extra>
-    class_ &def(const detail::init<Args...> &init, Extra&&... extra) {
-        init.template execute<type>(*this, std::forward<Extra>(extra)...);
+    class_ &def(const detail::init<Args...> &init, const Extra&... extra) {
+        init.template execute<type>(*this, extra...);
         return *this;
     }
 
@@ -926,28 +778,28 @@
     }
 
     template <typename C, typename D, typename... Extra>
-    class_ &def_readwrite(const char *name, D C::*pm, Extra&&... extra) {
+    class_ &def_readwrite(const char *name, D C::*pm, const Extra&... extra) {
         cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; },
                           return_value_policy::reference_internal,
-                          is_method(this), extra...),
+                          is_method(*this), extra...),
                      fset([pm](C &c, const D &value) { c.*pm = value; },
-                          is_method(this), extra...);
+                          is_method(*this), extra...);
         def_property(name, fget, fset);
         return *this;
     }
 
     template <typename C, typename D, typename... Extra>
-    class_ &def_readonly(const char *name, const D C::*pm, Extra&& ...extra) {
+    class_ &def_readonly(const char *name, const D C::*pm, const Extra& ...extra) {
         cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; },
                           return_value_policy::reference_internal,
-                          is_method(this), std::forward<Extra>(extra)...);
+                          is_method(*this), extra...);
         def_property_readonly(name, fget);
         return *this;
     }
 
     template <typename D, typename... Extra>
-    class_ &def_readwrite_static(const char *name, D *pm, Extra&& ...extra) {
-        cpp_function fget([pm](object) -> const D &{ return *pm; }, nullptr,
+    class_ &def_readwrite_static(const char *name, D *pm, const Extra& ...extra) {
+        cpp_function fget([pm](object) -> const D &{ return *pm; },
                           return_value_policy::reference_internal, extra...),
                      fset([pm](object, const D &value) { *pm = value; }, extra...);
         def_property_static(name, fget, fset);
@@ -955,9 +807,9 @@
     }
 
     template <typename D, typename... Extra>
-    class_ &def_readonly_static(const char *name, const D *pm, Extra&& ...extra) {
-        cpp_function fget([pm](object) -> const D &{ return *pm; }, nullptr,
-                          return_value_policy::reference_internal, std::forward<Extra>(extra)...);
+    class_ &def_readonly_static(const char *name, const D *pm, const Extra& ...extra) {
+        cpp_function fget([pm](object) -> const D &{ return *pm; },
+                          return_value_policy::reference_internal, extra...);
         def_property_readonly_static(name, fget);
         return *this;
     }
@@ -973,21 +825,19 @@
     }
 
     class_ &def_property(const char *name, const cpp_function &fget, const cpp_function &fset, const char *doc = nullptr) {
-        object doc_obj = doc ? pybind11::str(doc) : (object) const_cast<cpp_function&>(fget).attr("__doc__");
+        object doc_obj = doc ? pybind11::str(doc) : (object) fget.attr("__doc__");
         object property(
-            PyObject_CallFunctionObjArgs((PyObject *) &PyProperty_Type,
-                                  fget.ptr() ? fget.ptr() : Py_None,
-                                  fset.ptr() ? fset.ptr() : Py_None, Py_None, doc_obj.ptr(), nullptr), false);
+            PyObject_CallFunctionObjArgs((PyObject *) &PyProperty_Type, fget.ptr() ? fget.ptr() : Py_None,
+                                         fset.ptr() ? fset.ptr() : Py_None, Py_None, doc_obj.ptr(), nullptr), false);
         attr(name) = property;
         return *this;
     }
 
     class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset, const char *doc = nullptr) {
-        object doc_obj = doc ? pybind11::str(doc) : (object) const_cast<cpp_function&>(fget).attr("__doc__");
+        object doc_obj = doc ? pybind11::str(doc) : (object) fget.attr("__doc__");
         object property(
-            PyObject_CallFunctionObjArgs((PyObject *) &PyProperty_Type,
-                                  fget.ptr() ? fget.ptr() : Py_None,
-                                  fset.ptr() ? fset.ptr() : Py_None, Py_None, doc_obj.ptr(), nullptr), false);
+            PyObject_CallFunctionObjArgs((PyObject *) &PyProperty_Type, fget.ptr() ? fget.ptr() : Py_None,
+                                         fset.ptr() ? fset.ptr() : Py_None, Py_None, doc_obj.ptr(), nullptr), false);
         metaclass().attr(name) = property;
         return *this;
     }
@@ -1047,8 +897,9 @@
 /// Binds C++ enumerations and enumeration classes to Python
 template <typename Type> class enum_ : public class_<Type> {
 public:
-    enum_(object &scope, const char *name, const char *doc = nullptr)
-      : class_<Type>(scope, name, doc), m_parent(scope) {
+    template <typename... Extra>
+    enum_(const handle &scope, const char *name, const Extra&... extra)
+      : class_<Type>(scope, name, extra...), m_parent(scope) {
         auto entries = new std::unordered_map<int, const char *>();
         this->def("__repr__", [name, entries](Type value) -> std::string {
             auto it = entries->find((int) value);
@@ -1078,21 +929,21 @@
     }
 private:
     std::unordered_map<int, const char *> *m_entries;
-    object &m_parent;
+    handle m_parent;
 };
 
 NAMESPACE_BEGIN(detail)
 template <typename... Args> struct init {
-    template <typename Base, typename Holder, typename... Extra> void execute(pybind11::class_<Base, Holder> &class_, Extra&&... extra) const {
+    template <typename Base, typename Holder, typename... Extra> void execute(pybind11::class_<Base, Holder> &class_, const Extra&... extra) const {
         /// Function which calls a specific C++ in-place constructor
-        class_.def("__init__", [](Base *instance, Args... args) { new (instance) Base(args...); }, std::forward<Extra>(extra)...);
+        class_.def("__init__", [](Base *instance, Args... args) { new (instance) Base(args...); }, extra...);
     }
 };
 
-PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, PyObject *arg, PyObject *ret) {
+PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, handle args, handle ret) {
     /* Clever approach based on weak references taken from Boost.Python */
-    handle nurse  (Nurse   > 0 ? PyTuple_GetItem(arg, Nurse   - 1) : ret);
-    handle patient(Patient > 0 ? PyTuple_GetItem(arg, Patient - 1) : ret);
+    handle nurse  (Nurse   > 0 ? PyTuple_GetItem(args.ptr(), Nurse   - 1) : ret.ptr());
+    handle patient(Patient > 0 ? PyTuple_GetItem(args.ptr(), Patient - 1) : ret.ptr());
 
     if (!nurse || !patient)
         pybind11_fail("Could not activate keep_alive!");
@@ -1106,17 +957,6 @@
     (void) wr.release();
 }
 
-template <int Nurse, int Patient> struct process_dynamic<keep_alive<Nurse, Patient>> : public process_dynamic<void> {
-    template <int N = Nurse, int P = Patient, typename std::enable_if<N != 0 && P != 0, int>::type = 0>
-    static void precall(PyObject *arg) { keep_alive_impl(Nurse, Patient, arg, nullptr); }
-    template <int N = Nurse, int P = Patient, typename std::enable_if<N != 0 && P != 0, int>::type = 0>
-    static void postcall(PyObject *, PyObject *) { }
-    template <int N = Nurse, int P = Patient, typename std::enable_if<N == 0 || P == 0, int>::type = 0>
-    static void precall(PyObject *) { }
-    template <int N = Nurse, int P = Patient, typename std::enable_if<N == 0 || P == 0, int>::type = 0>
-    static void postcall(PyObject *arg, PyObject *ret) { keep_alive_impl(Nurse, Patient, arg, ret); }
-};
-
 NAMESPACE_END(detail)
 
 template <typename... Args> detail::init<Args...> init() { return detail::init<Args...>(); };
@@ -1198,8 +1038,7 @@
 NAMESPACE_END(pybind11)
 
 #if defined(_MSC_VER)
-#pragma warning(pop)
+#  pragma warning(pop)
 #elif defined(__GNUG__) and !defined(__clang__)
-#pragma GCC diagnostic pop
+#  pragma GCC diagnostic pop
 #endif
-
diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h
index 10488c3..2ce6ed2 100644
--- a/include/pybind11/pytypes.h
+++ b/include/pybind11/pytypes.h
@@ -30,10 +30,11 @@
     handle(const handle &other) : m_ptr(other.m_ptr) { }
     handle(PyObject *ptr) : m_ptr(ptr) { }
     PyObject *ptr() const { return m_ptr; }
-    void inc_ref() const { Py_XINCREF(m_ptr); }
-    void dec_ref() const { Py_XDECREF(m_ptr); }
+    PyObject *&ptr() { return m_ptr; }
+    const handle& inc_ref() const { Py_XINCREF(m_ptr); return *this; }
+    const handle& dec_ref() const { Py_XDECREF(m_ptr); return *this; }
     int ref_count() const { return (int) Py_REFCNT(m_ptr); }
-    handle get_type() const { return (PyObject *) Py_TYPE(m_ptr); }
+    handle get_type() const { return handle((PyObject *) Py_TYPE(m_ptr)); }
     inline iterator begin() const;
     inline iterator end() const;
     inline detail::accessor operator[](handle key) const;
@@ -44,6 +45,8 @@
     template <typename T> T cast() const;
     template <typename ... Args> object call(Args&&... args_) const;
     operator bool() const { return m_ptr != nullptr; }
+    bool operator==(const handle &h) const { return m_ptr == h.m_ptr; }
+    bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }
     bool check() const { return m_ptr != nullptr; }
 protected:
     PyObject *m_ptr;
@@ -59,25 +62,25 @@
     object(object &&other) { m_ptr = other.m_ptr; other.m_ptr = nullptr; }
     ~object() { dec_ref(); }
 
-    PyObject * release() {
+    handle release() {
       PyObject *tmp = m_ptr;
       m_ptr = nullptr;
-      return tmp;
+      return handle(tmp);
     }
 
     object& operator=(object &other) {
-        Py_XINCREF(other.m_ptr);
-        Py_XDECREF(m_ptr);
+        other.inc_ref();
+        dec_ref();
         m_ptr = other.m_ptr;
         return *this;
     }
 
     object& operator=(object &&other) {
         if (this != &other) {
-            PyObject *temp = m_ptr;
+            handle temp(m_ptr);
             m_ptr = other.m_ptr;
             other.m_ptr = nullptr;
-            Py_XDECREF(temp);
+            temp.dec_ref();
         }
         return *this;
     }
@@ -85,7 +88,7 @@
 
 class iterator : public object {
 public:
-    iterator(PyObject *obj, bool borrowed = false) : object(obj, borrowed) { ++*this; }
+    iterator(handle obj, bool borrowed = false) : object(obj, borrowed) { ++*this; }
     iterator& operator++() {
         if (ptr())
             value = object(PyIter_Next(m_ptr), false);
@@ -100,108 +103,106 @@
 };
 
 NAMESPACE_BEGIN(detail)
-inline PyObject *get_function(PyObject *value) {
-    if (value == nullptr)
-        return nullptr;
+inline handle get_function(handle value) {
+    if (value) {
 #if PY_MAJOR_VERSION >= 3
-    if (PyInstanceMethod_Check(value))
-        value = PyInstanceMethod_GET_FUNCTION(value);
+        if (PyInstanceMethod_Check(value.ptr()))
+            value = PyInstanceMethod_GET_FUNCTION(value.ptr());
 #endif
-    if (PyMethod_Check(value))
-        value = PyMethod_GET_FUNCTION(value);
+        if (PyMethod_Check(value.ptr()))
+            value = PyMethod_GET_FUNCTION(value.ptr());
+    }
     return value;
 }
 
 class accessor {
 public:
-    accessor(PyObject *obj, PyObject *key, bool attr)
-        : obj(obj), key(key), attr(attr) { Py_INCREF(key);  }
-    accessor(PyObject *obj, const char *key, bool attr)
-        : obj(obj), key(PyUnicode_FromString(key)), attr(attr) { }
-    accessor(const accessor &a) : obj(a.obj), key(a.key), attr(a.attr)
-        { Py_INCREF(key); }
-    ~accessor() { Py_DECREF(key); }
+    accessor(handle obj, handle key, bool attr)
+        : obj(obj), key(key, true), attr(attr) { }
+    accessor(handle obj, const char *key, bool attr)
+        : obj(obj), key(PyUnicode_FromString(key), false), attr(attr) { }
+    accessor(const accessor &a) : obj(a.obj), key(a.key), attr(a.attr) { }
 
     void operator=(accessor o) { operator=(object(o)); }
 
-    void operator=(const handle &h) {
+    void operator=(const handle &value) {
         if (attr) {
-            if (PyObject_SetAttr(obj, key, (PyObject *) h.ptr()) < 0)
+            if (PyObject_SetAttr(obj.ptr(), key.ptr(), value.ptr()) == -1)
                 pybind11_fail("Unable to set object attribute");
         } else {
-            if (PyObject_SetItem(obj, key, (PyObject *) h.ptr()) < 0)
+            if (PyObject_SetItem(obj.ptr(), key.ptr(), value.ptr()) == -1)
                 pybind11_fail("Unable to set object item");
         }
     }
 
     operator object() const {
-        object result(attr ? PyObject_GetAttr(obj, key)
-                           : PyObject_GetItem(obj, key), false);
-        if (!result) PyErr_Clear();
+        object result(attr ? PyObject_GetAttr(obj.ptr(), key.ptr())
+                           : PyObject_GetItem(obj.ptr(), key.ptr()), false);
+        if (!result) {PyErr_Clear(); }
         return result;
     }
 
     operator bool() const {
         if (attr) {
-            return (bool) PyObject_HasAttr(obj, key);
+            return (bool) PyObject_HasAttr(obj.ptr(), key.ptr());
         } else {
-            object result(PyObject_GetItem(obj, key), false);
+            object result(PyObject_GetItem(obj.ptr(), key.ptr()), false);
             if (!result) PyErr_Clear();
             return (bool) result;
         }
     };
 
 private:
-    PyObject *obj;
-    PyObject *key;
+    handle obj;
+    object key;
     bool attr;
 };
 
 struct list_accessor {
 public:
-    list_accessor(PyObject *list, size_t index) : list(list), index(index) { }
+    list_accessor(handle list, size_t index) : list(list), index(index) { }
     void operator=(list_accessor o) { return operator=(object(o)); }
     void operator=(const handle &o) {
-        o.inc_ref(); // PyList_SetItem steals a reference
-        if (PyList_SetItem(list, (ssize_t) index, (PyObject *) o.ptr()) < 0)
+        // PyList_SetItem steals a reference to 'o'
+        if (PyList_SetItem(list.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0)
             pybind11_fail("Unable to assign value in Python list!");
     }
     operator object() const {
-        PyObject *result = PyList_GetItem(list, (ssize_t) index);
+        PyObject *result = PyList_GetItem(list.ptr(), (ssize_t) index);
         if (!result)
             pybind11_fail("Unable to retrieve value from Python list!");
         return object(result, true);
     }
 private:
-    PyObject *list;
+    handle list;
     size_t index;
 };
 
 struct tuple_accessor {
 public:
-    tuple_accessor(PyObject *tuple, size_t index) : tuple(tuple), index(index) { }
+    tuple_accessor(handle tuple, size_t index) : tuple(tuple), index(index) { }
     void operator=(tuple_accessor o) { return operator=(object(o)); }
     void operator=(const handle &o) {
-        o.inc_ref(); // PyTuple_SetItem steals a reference
-        if (PyTuple_SetItem(tuple, (ssize_t) index, (PyObject *) o.ptr()) < 0)
+        // PyTuple_SetItem steals a referenceto 'o'
+        if (PyTuple_SetItem(tuple.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0)
             pybind11_fail("Unable to assign value in Python tuple!");
     }
     operator object() const {
-        PyObject *result = PyTuple_GetItem(tuple, (ssize_t) index);
+        PyObject *result = PyTuple_GetItem(tuple.ptr(), (ssize_t) index);
         if (!result)
             pybind11_fail("Unable to retrieve value from Python tuple!");
         return object(result, true);
     }
 private:
-    PyObject *tuple;
+    handle tuple;
     size_t index;
 };
 
 struct dict_iterator {
 public:
-    dict_iterator(PyObject *dict = nullptr, ssize_t pos = -1) : dict(dict), pos(pos) { }
+    dict_iterator(handle dict = handle(), ssize_t pos = -1) : dict(dict), pos(pos) { }
     dict_iterator& operator++() {
-        if (!PyDict_Next(dict, &pos, &key, &value))
+        if (!PyDict_Next(dict.ptr(), &pos, &key.ptr(), &value.ptr()))
             pos = -1;
         return *this;
     }
@@ -211,7 +212,7 @@
     bool operator==(const dict_iterator &it) const { return it.pos == pos; }
     bool operator!=(const dict_iterator &it) const { return it.pos != pos; }
 private:
-    PyObject *dict, *key, *value;
+    handle dict, key, value;
     ssize_t pos = 0;
 };
 
@@ -410,8 +411,8 @@
         if (!m_ptr) pybind11_fail("Could not allocate list object!");
     }
     size_t size() const { return (size_t) PyList_Size(m_ptr); }
-    detail::list_accessor operator[](size_t index) const { return detail::list_accessor(ptr(), index); }
-    void append(const object &object) const { PyList_Append(m_ptr, (PyObject *) object.ptr()); }
+    detail::list_accessor operator[](size_t index) const { return detail::list_accessor(*this, index); }
+    void append(const object &object) const { PyList_Append(m_ptr, object.ptr()); }
 };
 
 class set : public object {
@@ -421,7 +422,7 @@
         if (!m_ptr) pybind11_fail("Could not allocate set object!");
     }
     size_t size() const { return (size_t) PySet_Size(m_ptr); }
-    bool add(const object &object) const { return PySet_Add(m_ptr, (PyObject *) object.ptr()) == 0; }
+    bool add(const object &object) const { return PySet_Add(m_ptr, object.ptr()) == 0; }
     void clear() const { PySet_Clear(m_ptr); }
 };
 
@@ -429,8 +430,8 @@
 public:
     PYBIND11_OBJECT_DEFAULT(function, object, PyFunction_Check)
     bool is_cpp_function() const {
-        PyObject *ptr = detail::get_function(m_ptr);
-        return ptr != nullptr && PyCFunction_Check(ptr);
+        handle fun = detail::get_function(m_ptr);
+        return fun && PyCFunction_Check(fun.ptr());
     }
 };
 
@@ -448,57 +449,4 @@
     }
 };
 
-NAMESPACE_BEGIN(detail)
-PYBIND11_NOINLINE inline internals &get_internals() {
-    static internals *internals_ptr = nullptr;
-    if (internals_ptr)
-        return *internals_ptr;
-    handle builtins(PyEval_GetBuiltins());
-    capsule caps(builtins["__pybind11__"]);
-    if (caps.check()) {
-        internals_ptr = caps;
-    } else {
-        internals_ptr = new internals();
-        builtins["__pybind11__"] = capsule(internals_ptr);
-    }
-    return *internals_ptr;
-}
-
-PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) {
-    auto const &type_dict = get_internals().registered_types_py;
-    do {
-        auto it = type_dict.find(type);
-        if (it != type_dict.end())
-            return (detail::type_info *) it->second;
-        type = type->tp_base;
-        if (type == nullptr)
-            pybind11_fail("pybind11::detail::get_type_info: unable to find type object!");
-    } while (true);
-}
-
-PYBIND11_NOINLINE inline std::string error_string() {
-    std::string errorString;
-    PyThreadState *tstate = PyThreadState_GET();
-    if (tstate == nullptr)
-        return "";
-
-    if (tstate->curexc_type) {
-        errorString += (std::string) handle(tstate->curexc_type).str();
-        errorString += ": ";
-    }
-    if (tstate->curexc_value)
-        errorString += (std::string) handle(tstate->curexc_value).str();
-
-    return errorString;
-}
-
-PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr) {
-    auto instances = get_internals().registered_instances;
-    auto it = instances.find(ptr);
-    if (it == instances.end())
-        return handle();
-    return handle((PyObject *) it->second);
-}
-
-NAMESPACE_END(detail)
 NAMESPACE_END(pybind11)
diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h
index c57befa..5153fec 100644
--- a/include/pybind11/stl.h
+++ b/include/pybind11/stl.h
@@ -26,7 +26,7 @@
     typedef std::vector<Value, Alloc> type;
     typedef type_caster<Value> value_conv;
 public:
-    bool load(PyObject *src, bool convert) {
+    bool load(handle src, bool convert) {
         list l(src, true);
         if (!l.check())
             return false;
@@ -34,21 +34,21 @@
         value.clear();
         value_conv conv;
         for (auto it : l) {
-            if (!conv.load(it.ptr(), convert))
+            if (!conv.load(it, convert))
                 return false;
             value.push_back((Value) conv);
         }
         return true;
     }
 
-    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
+    static handle cast(const type &src, return_value_policy policy, handle parent) {
         list l(src.size());
         size_t index = 0;
         for (auto const &value: src) {
-            object value_(value_conv::cast(value, policy, parent), false);
+            object value_ = object(value_conv::cast(value, policy, parent), false);
             if (!value_)
-                return nullptr;
-            PyList_SET_ITEM(l.ptr(), index++, value_.release()); // steals a reference
+                return handle();
+            PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
         }
         return l.release();
     }
@@ -59,26 +59,26 @@
     typedef std::set<Key, Compare, Alloc> type;
     typedef type_caster<Key> key_conv;
 public:
-    bool load(PyObject *src, bool convert) {
+    bool load(handle src, bool convert) {
         pybind11::set s(src, true);
         if (!s.check())
             return false;
         value.clear();
         key_conv conv;
         for (auto entry : s) {
-            if (!conv.load(entry.ptr(), convert))
+            if (!conv.load(entry, convert))
                 return false;
             value.insert((Key) conv);
         }
         return true;
     }
 
-    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
+    static handle cast(const type &src, return_value_policy policy, handle parent) {
         pybind11::set s;
         for (auto const &value: src) {
-            object value_(key_conv::cast(value, policy, parent), false);
+            object value_ = object(key_conv::cast(value, policy, parent), false);
             if (!value_ || !s.add(value))
-                return nullptr;
+                return handle();
         }
         return s.release();
     }
@@ -91,7 +91,7 @@
     typedef type_caster<Key>   key_conv;
     typedef type_caster<Value> value_conv;
 
-    bool load(PyObject *src, bool convert) {
+    bool load(handle src, bool convert) {
         dict d(src, true);
         if (!d.check())
             return false;
@@ -107,13 +107,13 @@
         return true;
     }
 
-    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
+    static handle cast(const type &src, return_value_policy policy, handle parent) {
         dict d;
         for (auto const &kv: src) {
-            object key(key_conv::cast(kv.first, policy, parent), false);
-            object value(value_conv::cast(kv.second, policy, parent), false);
+            object key = object(key_conv::cast(kv.first, policy, parent), false);
+            object value = object(value_conv::cast(kv.second, policy, parent), false);
             if (!key || !value)
-                return nullptr;
+                return handle();
             d[key] = value;
         }
         return d.release();
diff --git a/setup.py b/setup.py
index 691a51a..2f02e6a 100644
--- a/setup.py
+++ b/setup.py
@@ -15,6 +15,7 @@
     packages=[],
     license='BSD',
     headers=[
+        'include/pybind11/attr.h',
         'include/pybind11/cast.h',
         'include/pybind11/complex.h',
         'include/pybind11/descr.h',
@@ -58,10 +59,10 @@
 become an excessively large and unnecessary dependency.
 
 Think of this library as a tiny self-contained version of Boost.Python with
-everything stripped away that isn't relevant for binding generation. The core
-header files only require ~2.5K lines of code and depend on Python (2.7 or 3.x)
-and the C++ standard library. This compact implementation was possible thanks
-to some of the new C++11 language features (specifically: tuples, lambda
-functions and variadic templates). Since its creation, this library has grown
-beyond Boost.Python in many ways, leading to dramatically simpler binding code
-in many common situations.""")
+everything stripped away that isn't relevant for binding generation. Without
+comments, the core header files only require ~2.5K lines of code and depend on
+Python (2.7 or 3.x) and the C++ standard library. This compact implementation
+was possible thanks to some of the new C++11 language features (specifically:
+tuples, lambda functions and variadic templates). Since its creation, this
+library has grown beyond Boost.Python in many ways, leading to dramatically
+simpler binding code in many common situations.""")