Skip to content

No clear separation between "fast API" (unsafe) and "safe API" #61

@vstinner

Description

@vstinner

For historical reasons, the Python C API is a mixture of various kinds of functions:

  • Internal functions, exposed simply because it was the only way to be able to use it in CPython itself
  • Private functions, supposed to be not be used by 3rd party code, but sometimes added on purpose since we couldn't agree if it should be added or not
  • Clean and safe public API which is designed to be stable accross Python versions

In Python 3.7, a new Include/internal/ subdirectory was added: internal API which must not be used outside CPython have been moved slowly (one by one) there. Most of these functions are no longer exported: so technically it's no longer possible to use them outside Python. Moreover, the Py_BUILD_CORE macro must be defined to access it: it's an opt-in option (similar to issue #54 idea) to clearly point out that: hey, you're in the danger zone!

Recently, in Python 3.12, the concept of "Unstable API" was added: PEP 689 – Unstable C API tier. This one is a middleground for function that we want to expose as "public", but are known to be unstable between Python versions, like PyCore_New() which became: **PyUnstable_**Code_New().

There is still a gray area between "fast API" and "safe API".

Examples of unsafe fast APIs vs safe APIs:

  • PyTuple_GET_ITEM() vs PyTuple_GetItem() (runtime type check, check index bounds)
  • _PyThreadState_UncheckedGet() (can return NULL) vs PyThreadState_Get() (fatal error instead of returning NULL)

Differences between "fast API" and "safe API":

  • Fast API usually avoid runtime type check and avoid index bounds check, assertions may be used. Safe API implement runtime checks.
  • Fast API can sometimes implemented as macro or static inline function (ex: access structure members). Safe API is usually implemente as opaque function call.

It's more common for the "fast API" to rely on the compiler to produce efficient code (ex: inline code). Sadly, it may cause more portability issues (compiler not fully implementing a C standard or a specific function).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions