---
icon: log
title: 'Upgrade to v2.0.0'
order: 25
---

We are applying a major API refactoring in this release. The main goal is to make the API more consistent and easier to use. We are also adding new features and improvements. This release is not backward compatible with the previous versions. Please read the following guide to upgrade your project.

## Alias for `PyObject*`

We are going to make a very big change in `v2.0` which may break everything!
In order to make this upgrade easier, we are introducing an alias for `PyObject*` in `v1.5.0`.

```cpp
using PyVar = PyObject*;
```

Please replace all `PyObject*` with `PyVar` in your code in order to be compatible with `v2.0` in the future.
We will try our best to keep the compatibility with `v1.x` series.

## Old style bindings

We introduced the new style bindings `vm->bind` in [`v1.1.3`](https://github.com/pocketpy/pocketpy/releases/tag/v1.1.3) and deprecated the old style bindings `vm->bind_func<>` and `vm->bind_method<>`.

In this release, we added an ARGC-based binding `vm->bind_func` (without template parameter)
to replace the old style bindings. If you are still using `vm->bind_func<>` and `vm->bind_method<>`,
please update your code to use `vm->bind_func` instead.

```cpp
// old style (removed)
vm->bind_func<N>(obj, "add", f_add);
vm->bind_method<M>(obj, "get", f_get);

// new ARGC-based binding
vm->bind_func(obj, "add", N, f_add);
vm->bind_func(obj, "get", M+1, f_get);  // +1 for `self`
```

## Class bindings

Previously, if we want to write bindings for a C++ class, we need to add `PY_CLASS` macro and implement a magic method `_register`. This way was known as an intrusive way. For example:

```cpp
struct Point{
    PY_CLASS(Point, test, Point)

    int x, y;

    static void _register(VM* vm, PyObject* mod, PyObject* type){
        // do bindings here
    }
};

int main(){
    VM* vm = new VM();
    PyObject* mod = vm->new_module("test");
    Point::register_class(vm, mod);
    return 0;
}
```

In `v1.5.0`, the `PY_CLASS` macro was deprecated. We introduced a non-intrusive way to write class bindings via `vm->register_user_class<>`. The example above can be rewritten as follows:

```cpp
struct Point{
    int x, y;
};

int main(){
    VM* vm = new VM();
    PyObject* mod = vm->new_module("test");
    vm->register_user_class<Point>(mod, "Point",
        [](VM* vm, PyVar mod, PyVar type){
            // do bindings here
        });
    return 0;
}
```

The magic method `_register` is kept for users who still wants to use the intrusive way.
This is achieved by an overloaded version of `vm->register_user_class<>`. For example:

```cpp
struct Point{
    int x, y;

    static void _register(VM* vm, PyObject* mod, PyObject* type){
        // do bindings here (if you like the intrusive way)
    }
};

int main(){
    VM* vm = new VM();
    PyObject* mod = vm->new_module("test");
    vm->register_user_class<Point>(mod, "Point");
    return 0;
}
```

## Signature of `_import_handler`

The signature of `_import_handler` was changed from:

```cpp
unsigned char* (*)(const char* name_p, int name_size, int* out_size);
```

to:
```cpp
unsigned char* (*)(const char* name, int* out_size);
```

This is because `str` object was ensured to be null-terminated after `v1.4.1`.

## Signature of `bind__next__`

`vm->bind__next__` is a special method that is used to implement the iterator protocol.
Previously, if you want to return multiple values, you need to pack them into a tuple.
For example:

```cpp
vm->bind__next__(type, [](VM* vm, PyVar _0){
    if(is_end) return vm->StopIteration;
    // ...
    PyVar a = VAR(1);
    PyVar b = VAR(2);
    return VAR(Tuple(a, b));
});
```

```python
for a, b in my_iter:
    # There is tuple creation and destruction for each iteration
    ...
```

It is not efficient because unnecessary tuple creation and destruction are involved.
In `v1.5.0`, you need to use stack-based style to reimplement the above code:

```cpp
vm->bind__next__(type, [](VM* vm, PyVar _0) -> unsigned{
    if(is_end) return 0;    // return 0 indicates StopIteration
    // ...
    PyVar a = VAR(1);
    PyVar b = VAR(2);
    vm->s_data.push(a);     // directly push to the stack
    vm->s_data.push(b);     // directly push to the stack
    return 2;  // return the number of values
});
```

In this way, the interpreter only creates a tuple when it is necessary.
It can improve ~25% performance when iterating over a large array.

```python
for a, b in my_iter:
    # No tuple creation and destruction
    ...

for t in my_iter:
    # Create a tuple lazily
    ...
```

## Builtin function `next()`

Previously, `next()` returns `StopIteration` when the iterator is exhausted.
In `v1.5.0`, it raises `StopIteration` exception instead, which is consistent with CPython.
If you like the old way, you can use the following snippet to import the old `next()` function:

```python
from __builtins import next
```

Related C++ APIs do not change. They still return `vm->StopIteration` to indicate the end of iteration.

## User config support

We used to read `user_config.h` file to override the default configurations.
In `v1.5.0`, this is no longer supported.
Please use config macros before `#include "pocketpy.h"` directly.

```cpp
#define PK_ENABLE_OS            1
#define PK_ENABLE_THREAD        1
#define PK_ENABLE_PROFILER      1
// for all config macros, please refer to `include/pocketpy/common/config.h`
#include "pocketpy.h"
```

## Debugger and profiler

We added a macro `PK_ENABLE_PROFILER` (default is 0) to control the availability of the builtin debugger and profiler.
If you want to use them, for example, you want to call `breakpoint()` or `import line_profiler`, you need to set `PK_ENABLE_PROFILER` to 1 before `#include "pocketpy.h"`.

```cpp
#define PK_ENABLE_PROFILER      1
#include "pocketpy.h"
```

!!!
Enabling the profiler has a performance overhead. Only enable it when you need it.
!!!

## Type checking functions

+ `vm->is_non_tagged_type` was removed. Use `vm->is_type` instead.
+ `vm->check_non_tagged_type` was removed. Use `vm->check_type` instead.

## Python stringify functions

The following functions now return `Str` object instead of `PyVar`:

+ `vm->py_str`
+ `vm->py_repr`
+ `vm->py_json`

Also, `vm->bind__str__` and `vm->bind__repr__` were changed to return `Str` object.

## Catching exceptions

Now you need to catch `TopLevelException` instead of `Exception`.