Skip to content

Commit

Permalink
API break: renamed some class_<..> members, added documentation
Browse files Browse the repository at this point in the history
While documenting the nanobind ``class_<>::def*`` methods, I realized
how poorly named they all are.

For example, there were function ``.def_readonly_static()`` and
``.def_readwrite_static()`` for read-only and mutable fields, but their
property variants were called ``.def_property_readonly_static()`` and
``.def_property_static()``.

This commit changes the interface to be more consistent and less
verbose. It now looks as follows:

- Methods & constructors: ``.def()``
- Fields: ``.def_ro()`` and ``.def_rw()``
- Properties: ``.def_prop_ro()`` and ``.def_prop_rw()``
- Static methods: ``.def_static()``
- Static fields: ``.def_ro_static()`` and ``.def_rw_static()``
- Static properties: ``.def_prop_ro_static()`` and ``.def_prop_rw_static()``

Apologies about the API break. nanobind is still in its experimental
phase (version number 0.x.y), which means that occasional API changes
can occur if they are considered a long-term improvement.
  • Loading branch information
wjakob committed Feb 13, 2023
1 parent 05a34a9 commit b5ed696
Show file tree
Hide file tree
Showing 22 changed files with 933 additions and 618 deletions.
363 changes: 306 additions & 57 deletions docs/api_core.rst

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions docs/api_extra.rst
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,41 @@ nanobind API and require an additional include directive:
* - ``items(self, arg: Map) -> Map.ItemView``
- Returns an iterable view of the map's items

Unique pointer deleter
----------------------

The following *deleter* should be used to gain maximal flexibility in combination with
``std::unique_ptr<..>``. It requires the following additional include directive:

.. code-block:: cpp
#include <nanobind/stl/unique_ptr.h>
See the two documentation sections on unique pointers for further detail
(:ref:`#1 <unique_ptr>`, :ref:`#2 <unique_ptr_adv>`).

.. cpp:struct:: template <typename T> deleter

.. cpp:function:: deleter() = default

Create a deleter that destroys the object using a ``delete`` expression.

.. cpp:function:: deleter(handle h)

Create a deleter that destroys the object by reducing the Python reference count.

.. cpp:function:: bool owned_by_python() const

Check if the object is owned by Python.

.. cpp:function:: bool owned_by_cpp() const

Check if the object is owned by C++.

.. cpp:function:: void operator()(void * p) noexcept

Destroy the object at address `p`.

.. _iterator_bindings:

Iterator bindings
Expand Down
65 changes: 45 additions & 20 deletions docs/basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ Docstrings
----------

Let's add one more bit of flourish by assigning a docstring to the extension
module itself. Add the following line anywhere in the body of the ``NB_MODULE()
{...}`` declaration:
module itself. Include the following line anywhere in the body of the
``NB_MODULE() {...}`` declaration:

.. code-block:: cpp
Expand Down Expand Up @@ -284,10 +284,10 @@ simple C++ type named ``Dog`` defined as follows:
#include <string>
struct Dog {
std::string m_name;
std::string name;
std::string bark() const {
return m_name + ": woof!";
return name + ": woof!";
}
};
Expand All @@ -305,7 +305,7 @@ The ``Dog`` bindings look as follows:
.def(nb::init<>())
.def(nb::init<const std::string &>())
.def("bark", &Dog::bark)
.def_readwrite("name", &Dog::name);
.def_rw("name", &Dog::name);
}
Let's look at selected lines of this example, starting with the added include directive:
Expand All @@ -317,8 +317,8 @@ Let's look at selected lines of this example, starting with the added include di
nanobind has a minimal core and initially doesn't know how to deal with STL
types like ``std::string``. This line imports a *type caster* that realizes a
bidirectional conversion (C++ ``std::string`` ↔ Python ``str``) to make the
example usable. An :ref:`upcoming documentation section <type_casters>`
contrasts type casters and other alternatives.
example usable. The next :ref:`documentation section <type_casters>` will
provide more detail on type casters and other alternatives.

The class binding declaration :class:`nb::class_\<T\>() <class_>` supports both
``class`` and ``struct``-style data structures.
Expand All @@ -333,15 +333,15 @@ and installs it in the :cpp:class:`nb::module_ <module_>` ``m``.
Initially, this type is completely empty---it has no members and cannot be
instantiated. The subsequent chain of binding declarations binds two
constructor overloads (via :cpp:class:`nb::init\<...\>() <init>`), a method,
and the ``name`` field (via :cpp:func:`.def_readwrite(..)
<class_::def_readwrite>`).
and the mutable ``name`` field (via :cpp:func:`.def_rw(..) <class_::def_rw>`,
where ``rw`` stands for read/write access).

.. code-block:: cpp
.def(nb::init<>())
.def(nb::init<const std::string &>())
.def("bark", &Dog::bark)
.def_readwrite("name", &Dog::name);
.def_rw("name", &Dog::name);
An interactive Python session demonstrating this example is shown below:

Expand All @@ -359,19 +359,43 @@ An interactive Python session demonstrating this example is shown below:
>>> d.bark()
'Charlie: woof!'
The example showed how to bind constructors, methods, and mutable fields. Many
other things can be bound using analogous :cpp:class:`nb::class_\<...\>
<class_>` methods:

.. list-table::
:widths: 40 60
:header-rows: 1

* - Type
- method
* - Methods & constructors
- :cpp:func:`.def() <class_::def>`
* - Fields
- :cpp:func:`.def_ro() <class_::def_ro>`,
:cpp:func:`.def_rw() <class_::def_rw>`
* - Properties
- :cpp:func:`.def_prop_ro() <class_::def_prop_ro>`,
:cpp:func:`.def_prop_rw() <class_::def_prop_rw>`
* - Static methods
- :cpp:func:`.def_static() <class_::def_static>`
* - Static fields
- :cpp:func:`.def_ro_static() <class_::def_ro_static>`,
:cpp:func:`.def_rw_static() <class_::def_rw_static>`
* - Static properties
- :cpp:func:`.def_prop_ro_static() <class_::def_prop_ro_static>`,
:cpp:func:`.def_prop_rw_static() <class_::def_prop_rw_static>`

.. note::

Constructors and methods support :ref:`docstrings <docstrings>`,
All of these binding declarations support :ref:`docstrings <docstrings>`,
:ref:`keyword, and default argument <keyword_and_default_args>` annotations
as before.

Binding fields
--------------

.. _binding_lambdas:

Lambda functions
----------------
Binding lambda functions
------------------------

Note how ``print(d)`` produced a rather useless summary in the example above:

Expand All @@ -380,10 +404,11 @@ Note how ``print(d)`` produced a rather useless summary in the example above:
>>> print(d)
<my_ext.Dog object at 0x1044540f0>
To address this, we must add a special method named ``__repr__`` that returns a
human-readable summary. Unfortunately, a function with such functionality does
not exist in the ``Dog`` type, and it would be nice if we did not have to
modify it. To accomplish this goal, we can instead bind a *lambda function*:
To address this, we can add a special Python method named ``__repr__`` that
returns a human-readable summary. Unfortunately, a corresponding function with
such functionality does not currently exist in the C++ type, and it would be
nice if we did not have to modify it. We can bind a *lambda function* to
achieve both goals:

.. code-block:: cpp
Expand Down
29 changes: 28 additions & 1 deletion docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,37 @@ current version is still in the prototype range (*0.x.y*), there are no (formal)
guarantees of API or ABI stability. That said, I will do my best to minimize
inconvenience whenever possible.

Version 0.1.1 (TBA)
Version 0.2.0 (TBA)
-------------------------------
* Nanobind now features documentation on `readthedocs
<https://nanobind.readthedocs.io>`_.
* While writing the documentation, I realized how lengthy and inconsistently some of
the :cpp:func:`class_\<T\>::def* <class_::def>` members are named. nanobind
will from now on use the following API:

.. list-table::
:widths: 40 60
:header-rows: 1

* - Type
- method
* - Methods & constructors
- :cpp:func:`.def() <class_::def>`
* - Fields
- :cpp:func:`.def_ro() <class_::def_ro>`,
:cpp:func:`.def_rw() <class_::def_rw>`
* - Properties
- :cpp:func:`.def_prop_ro() <class_::def_prop_ro>`,
:cpp:func:`.def_prop_rw() <class_::def_prop_rw>`
* - Static methods
- :cpp:func:`.def_static() <class_::def_static>`
* - Static fields
- :cpp:func:`.def_ro_static() <class_::def_ro_static>`,
:cpp:func:`.def_rw_static() <class_::def_rw_static>`
* - Static properties
- :cpp:func:`.def_prop_ro_static() <class_::def_prop_ro_static>`,
:cpp:func:`.def_prop_rw_static() <class_::def_prop_rw_static>`

* Added casters for dense matrix/array types from the `Eigen library
<https://eigen.tuxfamily.org/index.php?title=Main_Page>`_. (PR `#120
<https://github.com/wjakob/nanobind/pull/120>`_).
Expand Down
17 changes: 11 additions & 6 deletions docs/exchanging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Exchanging information

nanobind offers three fundamentally different ways of exchanging information
between Python and C++. Depending on the task at hand, one will usually be
preferable over the others, hence it is important to be aware of the pros and
cons of each approach.
preferable over the others, hence it is important to be aware of their
advantages and disadvantages.

.. _type_casters:

Expand Down Expand Up @@ -127,12 +127,16 @@ The following table lists the currently available type casters:
- ``#include <nanobind/eigen/dense.h>``


**Con**: Every transition between the Python and C++ side will require a
**Con**: Every transition between the Python and C++ side will generally require a
conversion step (in this case, to re-create all list elements). This can be
wasteful when the other side only needs to access a small part of the data.
Conversely, the overhead should not be a problem when the data is fully
"consumed" following conversion.

Note that some type casters (e.g., those for ``std::unique_ptr<..>``,
``std::shared_ptr<..>``, :cpp:class:`nb::tensor <tensor>`, and for ``Eigen::*``
can perform a type conversion without copying the underlying data.)

.. _type_caster_mutable:

Mutable reference issue
Expand Down Expand Up @@ -263,10 +267,11 @@ special cases (vectors, ordered/unordered maps, iterators):
- ``#include <nanobind/make_iterator.h>``
(:ref:`docs <iterator_bindings>`)
* - Other types
- See the :ref:`next section <bindings>`.
- See the previous example on :ref:`binding custom types <binding_types>`.

In general, you will need to write the binding code yourself. The :ref:`next
section <bindings>` explains how to do this for your own types.
In general, you will need to write the binding code yourself. The previous
section on :ref:`binding custom types <binding_types>` showed an example of
such a type binding.

.. _wrappers:

Expand Down
Loading

0 comments on commit b5ed696

Please sign in to comment.