This is a somewhat simplistic view of ownership and borrowing for modern programming languages.
Pointers are not the only 'pointer's to resources. You can have handles specific to your codebase or system, you can have indices to objects in some flat array that the rest of your codebase uses, even temporary file names.
An object oriented (or 'multi paradigm') language has to account for these and not just literal pointers.
This is handled reasonably well both in Rust and C++. (In the spirit of avoiding yet another C++ vs Rust flamewar here, yes the semantics are different, no it doesn not make sense for C++ to adopt Rust semantics)
struct resource {
resource(ctx *c, ...) {index = c->store(...); ...;}
size_t index;
ctx *c;
~resource() {c->free(index);}
// copy constructor+op creates new handle
// move constructor+op copies the handle, maybe zeroes the current one
};
With this you can rely on RAII, smart pointers, upcoming lifetime checks and annotations, etc. The core idea is that you treat objects of classes like this as values and everything works out seamlessly. Even if they are 'pointers' in all but name. You can also overload the dereference operator for it to have pointer-like syntax, but that is discouraged.
When you have just once resource this might be overkill but for large projects with tangled webs of resources, this sort of setup really makes the code simpler and easier to design.
That's C++ for you, simple things look complex but once you get into big hairy projects things stay at the same level of complexity instead of becoming an unmanageable mess.
D almost supports RAII, and the compiler seems to do some automated copy to move conversion, but this is the sort of thing that really, really needs a large number of users and compiler implementers to iron out issues and corner cases. Nothing against D, the language is pretty neat!
But if I'm not mistaken, this is just handling index allocation, release and avoiding dangling manually. The programmer is still responsible, right? And I don't think Rust can do better for indices, since indices are normal, "eternal" values.
> this is just handling index allocation, release and avoiding dangling manually
No, it is abstracted away. You just have to follow best practices when writing a library.
resource foo(...); // This gets freed at the end of scope. See RAII.
auto x = make_unique<resource>(...); // can be moved, freed when owner is.
auto y = make_shared<resource>(...); // freed on zero reference count
I don't know D so I'm probably missing some basic syntax. If pointers cannot be copied how do you have multiple objects referencing the same shared object?
OOP and ownership are two concepts that mix poorly - ownership in the presence of OOP-like constructs is never simple.
The reason for that is OOP tends to favor constructs where each objects holds references to other objects, creating whole graphs, its not uncommon that from a single object, hundreds of others can be traversed.
Even something so simple as calling a member function from a member function becomes incredibly difficult to handle.
Tbh - this is with good reason, one of the biggest flaws of OOP is that if x.foo() calls x.bar() in the middle, x.bar() can clobber a lot of local state, and result in code that's very difficult to reason about, both for the compiler and the programmer.
And it's a simple case, OOP offers tons of tools to make the programmers job even more difficult - virtual methods, object chains with callbacks, etc. It's just not a clean programming style.
Edit: Just to make it clear, I am not pointing out these problems, to sell you or even imply that I have the solution. I'm not saying programming style X is better.
I work at a D company. We tend to use OOP only for state owners with strict dependencies, so it's rare to even get cycles. It is extremely useful for modeling application state. However, all the domain data is described by immutable values and objects are accessed via parameters as much as fields.
When commandline apps were everywhere, people dreamed of graphical interfaces. Burdened by having to also do jobs that it was bad at, the commandline got a bad reputation. It took the dominance of the desktop for commandline apps to find their niche.
In a similar way, OOP is cursed by its popularity. It has to become part of a mixed diet so that people can put it where it has advantages, and it does have advantages.
>one of the biggest flaws of OOP is that if x.foo() calls x.bar() in the middle, x.bar() can clobber a lot of local state, and result in code that's very difficult to reason about
That's more a problem of having mutable references, you'd have the same problem in a procedural language.
Very few OO languages track reference mutability with any level of rigor. In C/C++ most devs don't even know what restrict is or how to write code using it correctly (which is very difficult an bug prone), const is unfortunately not enough.
In fact I don't even know of any production language that handles variable mutability with any rigor other than Rust.
It worked alright for Rust, and yes Rust does support OOP, there are many meanings to what is OOP from CS point of view.
I have ported Ray Tracing in One Weekend into Rust, while keeping the same OOP design from the tutorial, and affine types were not an impediment to interfaces, polymorphism and dynamic dispatch.
I don't think it worked well for Rust - in fact one of the core issues of Rust imo, is that it somewhat encourages this OOP style which can cause major headaches when you design an app in a traditional OO way - object compostion, complex and stateful, non-copyable objects full of 'smart' behavior, necessitating clones, and state that needs to be reconciled.
The whole concept of OOP is a major conceptual regression in how it treats aliasing, which is a major headache for compiler writers, necessitating either whole program analysis or JIT like techniques.
On the flipside, with OOP is usually quite easy to put a debugger breakpoint on a particular line and see the full picture of what the program is doing.
In diehard FP (e.g. Haskell) it's hard to even place a breakpoint, let alone see the complete state. In many cases, where implementing a piece of logic without carrying a lot of state is impossible, functional programming can also become very confusing. This is especially true when introducing certain theoretical concepts that facilitate working with IO and state, such as Monad Transformers.
That is true, but on the flip-flip side, while procedural or FP programs are usually easy to run piecewise, with OOP, you have to run the entire app, and navigate to the statement in question to be even able to debug it.
Imho, most FP languages have very serious human-interface issues.
It's no accident that C likes statements (and not too complex ones at that). You can read and parse a statement atomically, which makes the code much easier to read.
In contrast, FP tends to be very, very dense, or even worse, have a density that's super inconsistent.
> In contrast, FP tends to be very, very dense, or even worse, have a density that's super inconsistent.
Depends on the FP. Pipes make things fairly legible. Example from Elixir:
def some_function(thing, doodad, doohickey) do
thing
|> foo(doodad)
|> bar()
|> baz(doohickey)
|> quux()
end
Also easy to debug -- break on any of those lines, or insert `|> IO.inspect()` at any point for good old fashioned print debugging.
Conversely, the non-FP non-pipe version of this would:
(a) be monstrous and difficult to segment: `quux(baz(bar(foo(thing, doodad)), doohickey))`,
(b) needlessly require OOP: `thing.swizzle(doodad).razzle().blorple(doohickey).dazzle()`, where the functions are methods defined on the preceding construct (or some parent construct, to god-knows-what generation), or
(c) require a lot of throw away variables (you get the picture).
I wish more languages had a pipe construct. It's very handy.
Interestingly, D is one of the few languages to have uniform function call syntax,[0] which makes the dot syntax effectively act as a pipe operator, requiring no OOP coupling for its use. Very neat!
I agree with the sentiment, I really like D and find a missing opportunity that it wasn't taken off regarding adoption.
Most of what made D special in D is nowadays partially available in mainstream languages, making the adoption speech even harder, and lack of LLM training data doesn't help either.
Eventually yes, when incapable becomes a synonymous with finding a job in an AI dominated software factory industry.
Enterprise CMS deployment projects have already dropped amount of assets teams, translators, integration teams, backend devs, replaced by a mix of AI, SaaS and iPaaS tools.
Now the teams are a fraction of the size they used to be like five years ago.
Fear not, there will be always a place for the few ones that can invert a tree, calculate how many golf balls fit into a plane, and are elected to work at the AI dungeons as the new druids.
While I don't share this cynical worldview, I am mildly amused by the concept of a future where, Warhammer 40,000 style, us code monkeys get replaced by tech priests who appease the machine gods by burning incense and invoking hymns.
Same for ERP/CRM/HRM and some financial systems ; all systems that were heavy 'no-code' (or a lot of configuration with knobs and switches rather than code) before AI are now just going to lose their programmers (and the other roles); the business logic / financial calcs etc were already done by other people upfront in excel, visio etc ; now you can just throw that into Claude Code. These systems have decades of rigid code practices so there is not a lot of architecting/design to be done in the first place.
Nick Offerman wants to have a word with you. Given the choice of building my own furniture and things or IKEA and I had the skills I’d go the build it myself route. It’s doable. It was before. And it still is. All we got now is super duper capable auto correct and text completion. Use it for what it is. Don’t let it replace you.
> Yeah, that is why carpenters are still around and no one buys Ikea.
I'm sorry, what? Are you suggesting that Ikea made carpenters obsolete? It's been less than 6 months since last I had a professional carpenter do work in my house. He seemed very real. And charged very real prices. This despite the fact that I've got lots of Ikea stuff.
Nah, IKEA has replaced moving furniture with throwing it away and rebuying it. Prior to IKEA hiring a carpenter was also something that is done a few times in a lifetime/century. If anything it has commodized creating new furniture.
> Compared to before, not a lot of carpenters/furniture makers are left.
Which is it? Carpenters or furniture makers? Because the two have nothing in common beyond the fact that both professions primarily work with wood. The former has been unaffected by automation – or even might plausibly have more demand due to the overall economic activity caused by automation! The latter certainly has been greatly affected.
The fact that people all over the thread are mixing up the two is mindboggling. Is there a language issue or something?
There is a language issue: carpenter is used as synonym of woodworker. It's like someone who doesn't know anything about computers using the term 'memory' to mean storage rather than working memory (i.e. RAM).
> that is why carpenters are still around and no one buys Ikea
The irony in this statement is hilarious, and perfectly sums up the reality of the situation IMO.
For anyone who doesn't understand the irony: a carpenter is someone who makes things like houses, out of wood. They absolutely still fucking exist.
Industrialised furniture such as IKEA sells has reduced the reliance on a workforce of cabinet makers - people who make furniture using joinery.
Now if you want to go ask a carpenter to make you a table he can probably make one, but it's going to look like construction lumber nailed together. Which is also quite a coincidence when you consider the results of asking spicy autocomplete to do anything more complex than auto-complete a half-written line of code.
These guys made one of the most amazing tables for someone I know: https://rustictradesfurniture.com/. If you said "you're not a carpenter because you aren't slapping 2x4s together", you'd get a wry chuckle that means 'who is this idiot'.
> I think you have misunderstood what a carpenter is. A carpenter is someone who makes wooden furniture (among other things).
I think _you_ have misunderstood what a carpenter is. At least where I live, you might get a carpenter to erect the wood framing for a house. Or build a wooden staircase. Or erect a drywall. I'm sure most carpenters worth their salt could plausibly also make wooden furniture, at an exorbitant cost, but it's not at all what they do.
I sanity checked with Wiktionary, and it agrees: "A person skilled at carpentry, the trade of cutting and joining timber in order to construct buildings or other structures."
My experience is that all LLMs that I have tested so far did a very good job producing D code.
I actually think that the average D code produced has been superior to the code produced for the C++ problems I tested. This may be an outlier (the problems are quite different), but the quality issues I saw on the C++ side came partially from the ease in which the language enables incompatible use of different features to achieve similar goals (e.g. smart_ptr s new/delete).
I work with D and LLMs do very well with it. I don't know if it could be better but it does D well enough. The problem is only working on a complex system that cannot all be held in context at once.
The complaints are against the open-weight LLMs, I didn't try them much. I do use mostly Claude as that's what the company is paying for. They don't pay for laptops with GPUs or locally hosted LLMs to test those.
It's not like it knows perfect D, it does make mistakes and I don't work on a C++ or Rust project to compare its behavior. Generating templates from scratch is a bit of a challenge but given we have plenty of examples in our code with some prodding it manages to write well enough.
Ownership and borrowing are so much less baroque in D than in Rust. And compile times are superb.
In a better world, we would all be using D instead of C, C++ or Rust.
However in this age of Kali...