Lucifers,
Under the Python bindings, Clownfish objects *are* Python objects. Each
Clownfish object struct def starts with the Python object struct def:
typedef struct cfish_Obj {
Py_ssize_t ob_refcnt; // Python, shared by Clownfish
PyTypeObject *ob_type; // Used by Python exclusively
struct cfish_Class *klass; // Used by Clownfish exclusively
} cfish_Obj;
This means that we don't need host wrappers when sending Clownfish objects
into Python space -- they can be used directly by the host, unlike Clownfish
objects under our bindings for Perl and Go.
It also means that under Python, Clownfish objects must conform to Python's
refcounting conventions.
Unfortunately, the "stack string" optimization we use under Perl requires
overriding refcounting -- Clownfish stack strings are "copy on incref". This
won't work under Python because Python may incref a stack string without
knowing that it needs to make a copy instead.
If a Clownfish stack string ever winds up in Python space, and Python increfs
it without making a copy, the result will likely be a pointer to stack memory
in a (Python) heap data structure. Once the stack frame where the stack
string was allocated goes away, we'll be left with a dangling pointer and an
eventual memory error.
Therefore, the stack string optimization is not feasible under Python -- or
any other host where we can't implement copy-on-incref Strings.
It may still be possible to optimize Clownfish-Python string conversion,
though. We'll have to allocate all Clownfish strings on the heap, but they
can still wrap string content from a Python string.
Python strings are immutable, so as long as the Clownfish String holds a
refcount open on a Python string, it can wrap the UTF-8 string buffer obtained
via `PyUnicode_AsUTF8AndSize`:
https://docs.python.org/3/c-api/unicode.html?highlight=pyunicode_asutf8#c.PyUnicode_AsUTF8AndSize
This caches the UTF-8 representation of the string in the Unicode object,
and subsequent calls will return a pointer to the same buffer. The caller
is not responsible for deallocating the buffer.
Implementing this optimization would require changes to String's internals.
For the time being, I intend to just copy all string content and leave this
optimization as a TODO.
Marvin Humphrey