8 ms·
The Fatal Flaw of Ownership Semantics
- gampleman 6y ago> Object orientated programming is a form of misinterpreted and misapplied Aristotelian Metaphysics applied to a domain it was never meant to model Ha! I always felt like OOP is a natural outgrowth of Scholasticism, which is basically saying the same thing.
- ncmncm 6y agoHow confused can one person be? (Also: what distinction is being made between "oriented" and "orientated", and why?) The author appears to believe that the analogies used to invent convenient names for language constructs are supposed to really be the construct, rather than a shorthand description. Language features, once they map to actual semantics, become pure mechanisms with their own ironclad logic, with only an analogical relationship to whatever concept motivated and, usually, named them. Thinking in terms of the concept, or (worse) the word chosen to refer to it, as the author does again and again, can only generate confusion. The author is also confused about the role of inheritance in C++. Unlike in Java, which offers practically nothing else to organize a program, in C++ inheritance is wholly optional, and is typically used only where it solves a specific problem. The author further confuses regular and virtual member functions, and their respective roles in design space. The sorts of confusion seen here are quite common in philosophy, which has great difficulty staying grounded to facts of experience, something I think Wittgenstein complained of. In programming most of us don't have that problem, because the facts of problems to be solved and, moreso, of the physical machines we use in solving them provide ground truth. Computer Science perennially tries to cut itself loose from that ground truth, but is always brought to heel by the demand of its graduates for employability.
- skinkestek 6y ago> How confused can one person be? IMO this sentence is completely unnecessary. > Unlike in Java, which offers practically nothing else to organize a program, in C++ inheritance is wholly optional, and is typically used only where it solves a specific problem. As someone with extensive experience in both Java and a number of other languages (before and after learning Java) this just isn't true. It detracts from your point for everyone who knows Java and it adds unnecessary anxiety for people who will learn Java in the future if they belive this. Java has flaws, but inheritance is not the only way to compose Java programs. Edit: As a general rule I'd suggest everyone stop pretending Java is generally bad until they have some actual experience from real world systems in Java and a couple of other languages under their belt.
- sideshowb 6y agoBeen a while since I used java but is it still the case that your main function has to be inside a class which has to inherit, ultimately, from Object? I think that's what gp meant in implying that inheritance is not optional. In practical terms of course a bit of boilerplate to declare a class where none was needed, doesn't matter a great deal.
- skinkestek 6y ago> but is it still the case that your main function has to be inside a class which has to inherit, ultimately, from Object? I think that's what gp meant in implying that inheritance is not optional. This is correct but not what GP wrote. What GP wrote is: > Unlike in Java, which offers practically nothing else [than inheritance] to organize a program, To point out why GP is wrong: - In Java you can organize files by packages - by purpose (different folders for test vs production code), - you can use composition to combine classes (in fact this is the recommended way these days) - etc I normally don't care about language wars but I think it is OK to point out when someone writes something that is clearly wrong.
- johnnycerberus 6y agoAlso, you can further organize your packages into Java modules (Java >=9). I don't know why people say that you can't use composition in Java or that it is unique to purely functional languages. You can achieve composition by using Streams, decorator, composite and chain of responsability patterns.
- Joker_vD 6y agoThe author also managed to use the same word, linear, in two different senses while pretending those are the same (or very similar) senses. Bonus points for having a somewhat long list of definitions that explains that the words are used in their usual meaning, yet does this by the way of introducing more undefined terms, sometimes tautological: an Agent is an actor with the capacity to act, marvellous. "A Doer is a doing entity that can do things"--agent and actor are both derived from the same Latin verb that means "to do". And that list misses the definition for "linear", which is definitely not used in any usual sense of the word: trees are linear, but graphs are not... huh?
- meheleventyone 6y agoYeah by the end of it I was dying for an explanation of what all the uses of linear and non-linear were meant to imply. One paragraph has the words mentioned six times in three sentences! The whole thing would be much more obvious if they ditched half the philosophising and gave a concrete example of the problem and their solution. Then by all means talk about the philosophy behind how it generalises.
- a1369209993 6y ago> "linear", which is definitely not used in any usual sense of the word: trees are linear, but graphs are not... huh? While I agree with your overall point, this is a usual definition of linear: each item (eg graph/tree node) is used (eg pointed to) at most[0] once (eg each tree node has at most one parent node, whereas a graph node can have multiple edges from other nodes). 0→2 0→2 ↓ ↓ ↓ ↓ 1 3 1→3 Left is a tree, and linear (each node has only one arrow pointing at it), while Right is nonlinear because there are two ways to get to 3 (via 1 or 2). In this context it also means that if (eg) you print out the graph in a naive S-expression-style traversal you'd encounter 3 twice (eg "(0 (1 (3)) (2 (3)))" when each node is a list). This sense comes from linear functions, which can be expressed with at most one use of their argument in the form λx(Ax+B) for A and B constant in x. (Under this scheme, x² would have to be expressed as x·x, which repeats x; linearity in programming languages generally allows numeric values to be duplicated freely, so this is only of etymological relevance.) 0: or possibly exactly once; I can never remember which of those is "linear" and which is "affine".
- Mordisquitos 6y ago>(Also: what distinction is being made between "oriented" and "orientated", and why?) My guess is that he's just explicitly acknowledging the Commonwealth English preference for using the verb "to orientate" to mean "to focus/to position", while on the other hand the verb "to orient" is traditionally understood as literally meaning to orientate something in an easterly (=oriental) direction. I'm a British English speaker, I use the verb "to orientate", but "object-orientated programming" still sounds unnatural to me. It's a bit like "program" and "programme"–we use "program" for software, "programme" for everything else.
- bregma 6y agoI have never heard of "orient" to mean "point something in an easterly direction." The difference between "orient" and "orientate" to my ear is "orient" is a verb and "orientation" is a noun. That means "object-oriented" is a gerunded adjective and "object-orientated" is an compounded adjectival noun. Since the usage is as a gerunded adjective, "object-orientated" is just grammatically awkward. But I'm not a grammatical prescriptivist, so you guys do you.
- gingerBill 6y agoYou are correct. I am British and write in British English. I naturally say orientate rather than orient. It's also a minor joke to add both but whatever.
- ceceron 6y ago> The sorts of confusion seen here are quite common in philosophy, which has great difficulty staying grounded to facts of experience, something I think Wittgenstein complained of. I have to comment this, being myself a multi-class character (both computer science and philosophy graduate). The confusion seen here is quite common when somebody without a proper philosophy background is trying to hold a discourse on abstract philosophical topics. Obviously it happens often in philosophy, but often due to the outsiders (computer scientists, physicists, sociologists, artists) who believe, they have revolutionary ideas ;) Wittgenstein's (or rather Kripkenstein's, depending on the interpretation) were rather of a different, more profound, nature. In my opinion author has decent ideas but lacks skills in communication to express them properly. > because the facts of problems to be solved and, moreso, of the physical machines we use in solving them provide ground truth. It is a very optimistic view of the programming as a knowledge domain. IMHO in real life "The facts of problems" are often very blurry and prone to similar problems seen in the philosophy. I am not talking about academic toy problems, but real-life problems that have to be solved.
- gingerBill 6y agoThank you for your comment. I mostly wrote this article as a way to get an idea out of my head rather than present it as a thesis on the topic. I am not a philosopher, but a physicist by profession, so I apologize for my lack of correct terminology to explain the topic correctly. I do enjoy reading philosophy but there is very little in terms of "philosophy of programming" in order to have a common language to talk about. I could either go full mathematical and most people will not know what I am talking about, or go full example based, but then lose the essence of the problem. What I wanted to say is that ownership semantics can only deal with "linear" problems whilst most problems are "non-linear" in nature. And that designing an entire language around this idea to ensure "safety", especially without it being "proven" in a smaller language, is/was very risky and dodgy. I also wanted to explain the mentality that many (not all) people have with regards to ownership semantics and how it regards to a certain concept of "agency", and how it is related (not the same) as the OOP mentality. P.S. The original commenter is confused about my views, and made mistakes about what I stated. https://news.ycombinator.com/item?id=24999902 https://news.ycombinator.com/item?id=24999902
- gingerBill 6y agoWhereabouts do I confuse the role of inheritance in C++? I just used it as an example of a language which has inheritance built into it. It's completely optional, of course, and I was not suggesting anywhere that it was required. In fact, I rarely use it at all in my own C++ code, and when I do, I usually go the old fashioned C-like approach (for numerous reasons which I won't explain in this comment). In the article, I define inheritance as the following: > Most people generally view inheritance as a combination of subtyping and dynamic dispatch through virtual method tables (vtables). So I did not confuse anything between regular and virtual member functions. You have made a lot of assumptions about my views which are not even in the text. And I agree Computer Science is very much not a science in the natural sense. I do with many more people would either say it is just mathematics (formal science) or start giving empirical evidence for their claims that "X is the best way to Y" (natural science).
- chrismorgan 6y agoI suspect that a lot of the inconvenience of modelling non-linear problems in Rust actually doesn’t come down to ownership semantics alone, but the combination of ownership semantics and the low-level memory model. However, I don’t have any solid evidence to support this, because ownership semantics have only really been implemented with the low-level memory model, because the low-level memory model strongly benefits from it (memory safety; it more closely matches how computers work internally at that low level) and GC languages don’t need ownership semantics, and people don’t generally restrict things without cause (and ownership semantics are definitely a restriction). My thesis here is that Rc<RefCell<_>> and similar are an effective escape hatch to ownership semantics, but they’re much less convenient than a garbage-collected type in a scripting language specifically because of the language’s low-level memory model. A GC language with ownership semantics might be able to obviate RefCell, which is the cause of Rc<RefCell<_>>’s inconvenience. I’d be interested to see experimentation with ownership semantics in languages with higher-level memory models (which broadly means GC languages). My thesis could turn out to be quite wrong, and I haven’t worked out all the details of how the combination would work (especially I’m hazy on parts of removing RefCell, which is pretty critical), but I think it could be worth some research—ownership semantics for its own sake, rather than ownership semantics for memory safety. > 10. Getting used bypassing the borrow checker to reduce fighting implies people have just found a way to cope with the constraints it imposes. Here’s the thing, though: it’s not just about finding a way to cope with the constraints it imposes; it’s also about thriving within the constraints it imposes, because it stops you from doing problematic things and guides you in the path of better designs much of the time (though non-linearity can definitely be a problem; it’s not all buttercups and daisies). When I work in JavaScript, I spend half the time missing ownership semantics, occasionally feeling downright miserable because ownership semantics would have made a problem far easier or less dangerous. Remember what I said about ownership semantics for its own sake rather than ownership semantics for memory safety? Yeah, most of the time I love Rust’s ownership semantics for the modelling rather than the memory safety.
- KenoFischer 6y agoYes, I think you're onto something. Essentially what if we modeled linearity like in Rust, but then did GC over the maximally linear data graph we can find. I've been wanting to play with some ideas in this direction, but haven't had the time.
- brundolf 6y agoLots of interesting thoughts, and a good outline of ownership's limitations, but I think some big leaps were made. "Fatal flaw" is quite a hyperbole, and the comparison to OOP, while interesting, is much too hand-wavy to be used as evidence for that assertion. But they were spot-on about what is arguably Rust's biggest weakness, and the things people do to work around it, and I think there's kind of an open question whether that status-quo can be improved upon. I.e. Rust right now is excellent at certain things ("linear things"), and okay at non-linear things. But could it be made to be really good for the latter too? Or will it remain somewhat confined to its specialization? The language occupies uncharted territory either way, so these kinds of questions are not surprising, and I for one am excited to see where things go.
- dan00 6y ago> I.e. Rust right now is excellent at certain things ("linear things"), and okay at non-linear things. But could it be made to be really good for the latter too? Having written programs in Rust and Haskell, which are in this regard quite similar, I think that you can express most of your application in a "linear" fashion and only have a bit of "non-linear" things at the top. For example if you have to handle some "non-linear" things like events from the system or a gui library, then you might have - in Rust terminology - a 'RefCell<Rc<AppState>>' to be able to have shared mutable access to the application state. At the top of the event handler you would transform the 'RefCell<Rc<AppState>>' into a '&mut AppState', which is the switch from the "non-linear world" to the "linear world" and involves a runtime check that there's only one mutable reference. All the following code of the handler can then be verified at compile time. This also makes the reasoning about the application easier, because you might even reduce the mutation of your application state to the switching area. So most of the event handling could be a pure transformation of the application state.
- nicoburns 6y agoI think Rust (or a new Rust-like language) could potentially be improved significantly by having language-level sugar for things like Rc<RefCell<T> Arc<Mutex<T>> or even some kind of Gc<T>.
- jevgeni 6y agoI’ve reached the bit about Aristotelian metaphysics (why??) and I still can’t tell what is the author’s point. EDIT: Alright, I’ve skimmed to the end and it seems to me it is a very r/iamverysmart way of saying “I prefer to use RefCell”. Honestly, I have trouble trusting someone’s judgement in programming language semantics when they can’t seem to be a good judge of their own written language semantics. Why define an agent at the beginning, but leave “agency” undefined? What does even “capability to act in a certain environment” mean? Is a function/method something with “capability to act in a certain environment”? Is a C++ class that?? Also: > It is also a category error to treat them as “real objects” since “real objects” and “programming objects” have little connection with each other ontologically. Mate, you link to the Wikipedia article about categorical errors, where it says that a CE is defined as comparing things that are ontologically different, thus showing your whole sentence as a tautology. What’s the value added for the reader??
- xeyownt 6y agoThis article made me to think immediately to https://www.sciencemag.org/careers/2016/01/how-read-scientific-paper https://www.sciencemag.org/careers/2016/01/how-read-scientif...
- SuperCuber 6y agoMinor nitpick: "Taking a value by self Drops the original value" is wrong, moving a value does not call Drop on it.
- bobthebuilders 6y agoI read the entire article, and the actual criticisms seems to be that not everything that can be represented with ownership semantics. I don't see how that would be a "fatal flaw" in any way, and it just seems to be a sensationalized headline.
- TrueDuality 6y agoEspecially when they are explicitly taken into account through escape hatches in the ownership system
- chrismorgan 6y agoYet the safest escape hatches are decidedly limited. Take Rc<RefCell<_>> nodes in a graph (struct Node { edges: Vec<Rc<RefCell<Node>>> }), for example: mutable cyclic traversal is somewhere between difficult (requiring some typically-significant convolution of your algorithm) and impossible. Meanwhile, a GC language can model the same thing trivially. So you start reaching for more dangerous escape hatches, or modelling the problem in some completely different way that lets you skip the problems of ownership semantics for the given domain.
- fpoling 6y agoModeling an arbitrary graph with reference counting immediately leads to the problem of cycles and the need of some form of GC to collect them. It is better to use a GC from the start (not collecting things until the graph owner decides to discard the whole graph is often a useful approach), or reduce the graph to a tree and use weak references for references between branches. Or even use handles as advocated by the article, which essentially reduces the graph to an array and uses its indexes as weak references.
- DougBTX 6y ago> or modelling the problem in some completely different way that lets you skip the problems of ownership semantics for the given domain Maybe that's an interesting way to think about the article too. The obvious way to think about a graph using ownership is to start with a root node, then to say that nodes own other nodes through their edges. But that model won't generalise to disjoint graphs (eg, social network with separate friend groups) and it isn't always clear which node is the "root" node.
- deleted 6y ago[deleted]
- justicezyx 6y ago> Ownership semantics are a form of an affine substructural type system1112 which means that they are fundamentally described by a linear logic, and explains why it struggles to express non-linear problems What is a “non linear logic” or a “non linear problem “ in this context?
- chrismorgan 6y agoLinked lists and graphs are the canonical examples of things that are difficult to model and express effectively in Rust. In other languages you can just store a pointer/handle/reference to the things each node is connected to, which is commonly not the most efficient way of working (and as systems scale up they routinely replace such techniques with fancier techniques), but is very straightforward conceptually and matches people’s intuitions about how to design such a thing. In Rust, you simply can’t do that directly, roughly because it’s not provably safe (in fact, in the general case, it’s provably not safe). So you have to solve things in other ways, the simplest being to wrap each node in Rc<RefCell<_>> or similar, which is basically a way of saying “I can’t cope with ownership semantics, gimme a kludgy way of checking it at runtime”; but it’s also common to immediately reach for fancier data structures like https://lib.rs/crates/petgraph https://lib.rs/crates/petgraph. Yet even with that, you’re often spitting in the face of ownership semantics with your traversals, because traversing a potentially-cyclic graph is fundamentally against ownership semantics, so you have to be careful because some things will be being checked at runtime. In the case of these fancier data structures, it is perhaps also worth pointing out that many of them actually do follow ownership semantics, down to things like allowing shared access to multiple nodes, or exclusive access to a single node, so that no runtime checks are necessary. This is where I think the original article severely missteps in calling it a fatal flaw—because people are successfully building safe ownership-oriented abstractions using unsafe code. That’s a super-important capability of Rust.
- johnnycerberus 6y agoEven in Java I have problems with non-linear stuff. Clojure is my favorite when it comes to graphs and algorithms that require highly dynamic data structures. I'm not experienced in Rust (but read most of the open-source programming book), but isn't it possible to use macros to create a DSL that can describe those structures? Is this what petgraph does?
- correct_horse 6y agoThis article compares the hierarchical nature of the type system of OOP languages (think Java) with the hierarchical nature of ownership in languages with Ownership/Move semantics (Rust and newly C++). The author notes that "composition over inheritance" is a rejection of the strictly tree-shaped OOP type system. In the same way, Rust's `RefCell` is an escape hatch from the strict hierarchy of ownership, maintaining a run-time invariant of one owner rather than a compile-time invariant. One difference I see between these two escape hatches are switching costs. Rewriting the Java standard library to use composition and not inheritance borders on impossibly difficult. Rewriting the rust standard library to use RefCell instead of &mut everywhere would be arduous and possibly automatable, but not impossible.
- ncmncm 6y ago"...and newly C++"? C++11 had move semantics. So did C++14 and C++17. C++20 still does. It is a stretch to suggest Rust had them longer, considering Rust 1.0 came out well after C++11, and cribbed them. It is a shame that C++ can't be move-by-default and const-by-default, but that's backward compatibility for you. Rewriting the Rust std lib to use RefCell everywhere would be possible, but would make it almost entirely useless.
- gpderetta 6y agoMove semantics even predate C++11. The need for move only types was identified very and such types have existed in various form for a ling time.
- bregma 6y agoC++98 had move semantics using std::auto_ptr.
- correct_horse 6y agoI probably shouldn't have said newly C++, but my frame of mind was relative to the lifespan of the language. > Rewriting the Rust std lib to use RefCell everywhere would be possible, but would make it almost entirely useless. Maybe not useless, but certainly worse than it currently is. The point is that you can switch one function to using RefCell (a breaking change, but) totally possible
- yason 6y agoThis minor observation caught my eye, very well articulated: "There are many criticisms of OOP456789 but my general criticism is that by placing emphasis on trying to solve problem in the type system, it shifts focus from the data structures and algorithms, the core of what a program fundamentally is."
- ncmncm 6y agoMore confusion: anything solved in the type system drops off the list of what needs to be solved with data structures or algorithms, for a big gain. Essentially, math has there replaced programming. We are not interested in solving all problems by programming. We should solve with programming what is best solved that way.
- gingerBill 6y agoThis is not a confusion but a fundamental difference in viewpoint. Not everything can be, nor should it be, solved at compile time. "anything solved in the type system drops off the list of what needs to be solved" AT A HUGE COST. Everything has a cost to it and even if you could hypothetically most solve things at compile time (you cannot), it might take a damn long time to compile it.
- ncmncm 6y agoTrue, a difference in viewpoint: your HUGE COST is to me PRACTICALLY FREE. Some things can be solved before compile time, some during compile time, some during startup, and some only by running as long as needed. The earlier the better. If you like, you can think of compile-time as its own runtime.
- gingerBill 6y agoFor me, performance is much more critical, and the languages with ownership semantics do not easily allow me to get those performance benefits unless I ignore/bypass the ownership semantics of the language. It's one of the reasons I started my own language, the Odin programming language. I wanted the ability to have control over memory layout and memory allocations, and be tied to a specific model of how structure and design my program determined by the programming language itself, especially ideas which have yet to prove themselves as being "good" (by whatever metric).
- lmm 6y ago> Dealing with singular values can be very useful, but not everything is a value. Some things are fundamentally “non-values” e.g. instructions/control-flow/declarations. If there are important things in your language that aren't values, that's a problem in your language. You really don't need any non-values; just look at, say, Haskell. > As I have described above, both the OOP and OS both share similarities: > Traditional-OOP: A (linear) value hierarchy of behaviour. The values act as agents. > Ownership Semantics: A (linear) value hierarchy of responsibility. Agents are responsible for values. This is just bollocks once you actually look at the details of it. An inheritance hierarchy is fixed once and for all at compile time, and can't ever change; either there's no way to change which class a given class inherits from at all, or at best there's some uncontrolled dark magic you can do. Whereas a defining characteristic of ownership semantics is that ownership can be safely passed from one owner to another in a controlled way.
- flohofwoe 6y agoIn my simple peasant brain I always associate "ownership" with a simple chunk of memory, not with "objects" as in OOP. As soon as a piece of code "knows" about this chunk of memory it has certain responsibilities, like not randomly scribbling over values or freeing the memory while others pieces of code might attempt the same. "Ownership" and "Move Semantics" are entirely artificial conventions to give some structure to those responsibilties. Casting those conventions into "hard language rules" introduces tradeoffs, evaluating those tradeoffs is important when deciding what language to use to solve certain problems. And this is where Rust comes in. Rust just enforces a couple of such "made up" conventions, none of those rules are dictated by the "real world" (e.g. the hardware the code runs on)... it's easy to get all tangled up in theoretical concepts like type systems, and functional programming, but in the end the only thing that counts is the machine code that's running on a concrete CPU. Sometimes I feel that language designers are losing sight on this simple reality ;)
- gingerBill 6y agoI absolute agree with you, but you already knew this. I think the terms "ownership" and "move" are confusing and what it really is "responsibility". > ...ownership/move semantics is fundamentally based around the _responsibilities of values_ by tracking value usage. > ... > If we were to call Ownership Semantics a paradigm, it would be the orientation around the responsibility of values in a hierarchical fashion, placing emphasis on this system of responsibility, shifting focus from data structures and algorithms. I am not a brilliant writer (which I already knew, even though loads of people have commented on that), but I was trying to get an idea I had in my head onto paper. I wanted to explain that this abstraction is not as good as it is being advertized and does have its limitations. It's not a criticism of the concept, but its application to a bunch of problems.
- yakubin 6y agoI failed to find an example of a practical problem in the article. What I did find was a load of circling around the subject from a distant philosophical perspective, all boiling down to essentially "you know what, there exist problems that ownership semantics aren't suitable for" (but using lots of wisely-sounding language), forgetting to present the problems. The article also suffers from the syndrome of taking a feature of a language and pretending that everything has to be seen through the lens of that feature. Well, newsflash: ownership semantics apply to only some things in Rust. They apply to values and bindings. But they don't apply to e.g. indices. I can take as create as many i's, where i=5, all referring to the same Vec, which later are going to be used to mutate the Vec, as I like, and Rust won't stop me. Similarly, there is Rc and Arc. It also included one of those "wise" thoughts along the lines of "You know what? The true nature of computers/economy/life/love is..." - one of the templates of meaningless sentences. In this case it was "however virtually all computers are fundamentally mutable things". Hmm... Did we suddenly forget about pipelining, instruction ordering, caching, instruction-level parallelism, C/C++'s problems with memory aliasing? C is not a low-level language[1]. [1]: https://queue.acm.org/detail.cfm?id=3212479 https://queue.acm.org/detail.cfm?id=3212479 If we were to write a statement analogous to the one advocated for in the article, but talking about mathematics instead, it could be "the fatal flaw of mathematics is that a lot of it is about reducing problems to linear algebra". How ridiculous does that sound?
- MauranKilom 6y agoThe title isn't "The Fatal Flaw of Programming". I'm not sure why you think mathematics is to linear algebra what ownership semantics are to... Rust I guess?
- yakubin 6y agoIf anything, that would be inverted. But anyway, just as linear algebra is just one tool in a mathematician's arsenal, ownership semantics are just one tool in a Rust programmer's arsenal.
- gingerBill 6y agoOne of the points in the article is that most problems are non-linear in nature, rather than linear. But a language like Rust, has designed its entire type system around this concept of ownership semantics which can only deal with linear logical problems. The biggest appeal of Rust to many is that it is "safe" and it is "safe" because of its ownership semantics and lifetime semantics. There are many other reasons to use Rust, of course, but this is the main reason it was made. I would argue that its "safety" is fundamentally the biggest reason to use it. I don't disagree with you that C is not a low level language, but a very high level language. But you have made a false dichotomy regarding "mutable things" and then talking about other things about a computer. I am not saying "a computer is only X", but "a computer is X, but also Y, Z, W, ..." The "fatal flaw" bit is purposeful click bait. "A critique of ownership semantics" is not necessarily a good.