font = Font.open("MyFont.ufo")
glyphA = font.layers.defaultLayer["A"]
point = glyphA.contours[0].points[0]
point.x = 404;
assert point.x == glyphA.contours[0].points[0].x
The author apparently wants to be able to perform ad hoc modifications to an existing font.
Unfortunately, it's not clear from the article what the use case is. Most of the time I've worked with fonts, they're treated as immutable values.
If the idea is that a font needs to be built from a serialization format, then an alternative approach would be to eliminate the python mutable interface and replace it with a build function that calls the underlying Rust to build a Font. That way Python never needs to deal with mutating a font.
Rust lets you take unlimited numbers of references to an immutable value. That's not a problem, other than defining lifetimes if you pass those references around and/or hold them in structs.
The problem arises the instant you want to mutate the value behind a reference. Hold just one active immutable reference at the same time, and that won't be possible. Note that mutable and immutable references can in some situations exist in the same block thanks to non-lexical lifetimes.
There are a lot of existing python scripts that run on top of the existing python `ufoLib2` library, and the initial motivation for this work was seeing what would be involved in creating a wrapper API that would allow all of these existing scripts to work transparently on top of an existing rust crate.
Exactly. If I do glyphA.contours[0].points[0].x = 1
what happened to someone else holding a reference to the same glyph? To a python programmer it might not be a surprise to see such an API (a shared mutable value), but to most OO programmers I hope this API looks very strange.
The conclusion in the article that using a getter/setter would fix most of the issues seems much more straight forward. Maybe I don't write enough python, but I rarely think modifying properties on a library object is preferable over clearly named methods.
How the object is mutated isn't really relevant to the smell. It's that an object can be mutated while someone else has a reference to it (and that the API is designed that way),
Unfortunately, it's not clear from the article what the use case is. Most of the time I've worked with fonts, they're treated as immutable values.
If the idea is that a font needs to be built from a serialization format, then an alternative approach would be to eliminate the python mutable interface and replace it with a build function that calls the underlying Rust to build a Font. That way Python never needs to deal with mutating a font.
Rust lets you take unlimited numbers of references to an immutable value. That's not a problem, other than defining lifetimes if you pass those references around and/or hold them in structs.
The problem arises the instant you want to mutate the value behind a reference. Hold just one active immutable reference at the same time, and that won't be possible. Note that mutable and immutable references can in some situations exist in the same block thanks to non-lexical lifetimes.