This is really the smallest problem of C++ since it introduced many more new problems than C had in the first place (e.g. popular memory corruption footguns like iterator invalidation or std::string_view), and this process of adding new problems seems to accelerate, C++ is now caught in a loop of trying to fix problems in new C++ versions which they had just introduced a couple of versions earlier
I would welcome the possibility of explicitly and semantically declaring ownership in data structures and API.
IMHO the concept of ownership is really only needed if you have a lot of external references dangling off your data structures (e.g. lots of pointers or slices). If you design your data as self-contained value types, most of the trouble with ownership and lifetimes simply doesnāt exist or at least become much easier to manage manually.
As soon as you have such references to external data, suddenly concepts like RAII or (deep-)copy-vs-move start to make sense, but IMHO itās better to avoid all this complexity in the first place by heavily preferring self-contained value types - and Zig does mostly a good job of encouraging this, except maybe the heavy usage of slices.
Of course Zigās philosophy of managing related lifetimes through arenas works well as an alternative to āgranular lifetime and ownership trackingā, but I see arenas as the next step when fully self-contained value items are not an option (e.g. for data where an upper bound cannot be estimated, or for bulk data thatās simply too big to copy around).
This is also in a nutshell why I think working with fixed-size nested arrays should be just as convenient as working with slices, since nested arrays are more important in my āworldā than slices - slices are pointers to external data which then suddenly requires thinking about ownership and lifetime - and once you run into this trap itās hard to get out again, e.g. once you start accepting data structures which are āreference spider websā instead of just a couple of arrays and indices, itās too late, no language will help you out of that mess
Overall, I believe that reality is complex, and this complexity ultimately reflects itself in programs. Strictly adhering to the design discipline of self-contained type values can yield good optimizations in some areas, but when it comes to concurrent programming, inter-thread communication, and shared resources, lifecycle issues must ultimately be confronted. These daunting concepts arise because reality is interconnected, concurrent, and unpredictable, and thereās no silver bullet that can resolve its inherent complexity.
zig uses the concept of parameter reference optimization to attempt to simultaneously embrace large, self-contained structures and copy performance, but I personally dislike this concept, as it can easily lead to unexpectedly corrupted usage of an intended pure function.
I prefer to express pointer ownership in function signatures, primarily because I dislike having to document these concepts: documentation tends to become outdated, while function signatures are always true. This reduces the effort API developers have to put into documentation, and API users also have to spend less effort understanding how to use them.
However, I must admit that Zig disagrees with my philosophy. Zig prefers that as long as the internal API logic prevents incorrect usage, then repeating this in the function signature is redundant, as evidenced by its stance on anytype.