5 ms·
You said the fundamental concept in Rust is ownership. What I described is also fundamentally ownership, but much simplified. You can use something without ow
by BulgarianIdiot 3y ago
You said the fundamental concept in Rust is ownership.
What I described is also fundamentally ownership, but much simplified.
You can use something without owning it, because to "use it" you send a message to it, and get a message back (i.e. send input, get output). There are two ways to message something in this system:
1. To own it and message it directly.
2. To own a reference identifier to it, and message your own owner to message it via the reference and return you the resulting message.
The distinction between Copy and Clone is Rust specific. It's not about deep vs non-deep, it's about whether something is moved by default or copied implicitly by default, and they wanted to copy some simpler scalars, like numbers, say, for pragmatic reason. But this odd exception, i.e. does something move or copy by default is very much a defect in Rust. It's a core behavior that differs based on whether the type implements copy or not.
In the simplified model I propose everything is copied (deep) by default, but you don't pay the cost for larger structures being copied, due to COW.
When everything you own is uniquely yours, making all copies deep copies becomes not only trivial, but also the fastest way to copy. And there's no reason to talk about "shallow copy". The concept is meaningless, you're used to it, you have a habit for it, but if people could deep copy everything, they would. "Shallow" copies are a limitation of languages where everything is wired by handles, pointers, and references in an arbitrary graph. And then a deep copy may never terminate, among other things. It's a mess.
Rust's graph is not (as) arbitrary, per se, it's stricter, but it keeps many of the same defects, in part to maintain C compatibility.
Meanwhile, your operating system has a hierarchy-based memory management (single ownership segments, at the hardware level a hierarchy of pages etc.), and COW in select places where as I noted immutability is present for some content, some of the time (like Unix forking). So does your file system.
Everything that's mature does this: DAG for immutables, TREE for mutables. Programming languages are clearly not as mature yet.
- dathinab 3y ago> Rust's graph is not (as) arbitrary, per se, it's stricter, but it keeps many of the same defects, in part to maintain C compatibility. I don't thing a core requirement for the design of an language needed for it's targeted use-cases is an defect, not having it would be an defect. I guess that's just a bad choice of wording. > It's not about deep vs non-deep (side not I noticed my wording choice wasn't grate, with flat copy I meant copy of a continuous memory region, it could still be a nested type as long as there are no indirections). It's all about that. Through more specifically the expected runtime cost associated with it. Copy only works for flat memory copies, is normally very cheap and in turn is automatic. Clone works for everything including deep-clones but might be very expensive and in turn is not ever done automatically and no doing any magic CoW tricks or similar was a very deliberate decision as for the use case rust was designed with in mind you do not want a Clone happen at a "unexpected" time. Sure it's not perfect e.g. there is are "cheap-Clone" types (like Rc) where I would prefer rust to automatically clone in at least some contexts. > In the simplified model I propose everything is copied (deep) by default, but you don't pay the cost for larger structures being copied, due to COW. But this approach has a wide variety of problem iff you want to use it for a system language. Like it being trivial to accidentally introduce potentially very expensive cloning or accidentally using a ton of unneeded memory. And yes you could come up with all kinds of mechanisms to reduce this. But defaults matter and rust by default motivates you to not do potentially expensive clones. This comes at a cost, sure. But depending on you use-case this is exactly what you want. > It's a mess. but a practically very useful mess which has a lot of success in difference to any of the research languages which in the past had tried to archive similar things as you stated. Perfection isn't and was never the goal. You always have to have a compromise between usability, compatibility, maintainability, debugability and performance. And for a "system programming language" this means C-compatibility and fine grained control over when or where copies happen. Doesn't mean it couldn't work for languages focused on other use-case, and could be suited for typical web server or app use-cases. But even through rust is used a lot for this it wasn't designed for this use case.
- BulgarianIdiot 3y ago> Like it being trivial to accidentally introduce potentially very expensive cloning or accidentally using a ton of unneeded memory. You're describing things COW is designed to prevent as things COW causes. There is NEVER a very expensive cloning happening at once with COW. That's the whole point of it. Everything is shared until the last moment when it can't be, and even then only small parts are copied. Makes me think you're missing something here. Maybe not familiar with how COW is used in practice. COW is used in your operating systems' memory management, and in your file system, as I already said. Do you assume they're like "oh yes, we want to have randomly triggered very expensive cloning and use a ton of unneeded memory!"? You may call COW a "magic trick" but this magic trick is fundamental to how your computer works. Not only is it in your file system and OS. It's also essential to virtual machines and containerization. It's essential to virtually all backup & recovery systems. Do you understand how integral COW is to the world of computing? This scary magic trick you're so afraid of? You're fine defending a "very useful mess" and rejecting clear improvements with inadequate or outright misleading conclusions. Most people just react superficially like this to change and I'm used to it. But I'll never stop pointing it out when I see it. As for C compatibility without copying the memory model flaws, it's possible, but it requires more thought than Rust put into it.
- dathinab 3y ago> You're describing things COW is designed to prevent as things COW causes. not quite see below > You may call COW a "magic trick" I didn't call it a magic trick, I stated rust decided against using "magic tricks" of internally implicitly not visible doing things below the hood. Which might involve using a Cow or similar. Cow is just the tool the trick could use not the trick by itself. > Maybe not familiar with how COW I'm very familiar with it. But there is a difference between using CoW manually carefully in some places and using it everywhere all the time implicitly as part of the language design. COW prevents you from always copying everything everywhere at the cost of on-the-fly copying things when needed if everything is COW all the time this will mean most of the copies are not expensive because most parts of the thing you need to copy will not need to be copied because they are also cow but there are some gotchas first if you have it implicitly everywhere it is very easily to overlook how many copies you make, or that you make way to many and should change your code and even with "everything COW" the cost still can be very expensive for all kinds of reasons e.g. in some hypothetical code like `a[10] = 4` you might now have accidentally cloned a 4GiB byte buffer, COW doesn't prevent this because that 4GiB byte buffer is a single thing. Now you might come up with ways to internally split the buffer into chunks or only use lists etc. But that isn't really working for many low level system language use-cases (but totally working for many other cases, including many server programming cases). Similar it means if you have nested types they always need an indirection to the sub-types so that you can just copy the GC or RC references (or whatever you use for memory management) when needing to make a copy of the outer type (except where an optimizer can optimize it away) which is fine, except that for a system language you often need C layout compatible types. So you would need to severely special case C-layout types. And as far I can tell you either special case a lot of thing in a way which isolates them away from your language (things like C-layout, fundamental non-clonable types, etc.) or you need to have a implementation of the nested CoW which no longer guarantees that it's efficient at all. Isolating things away which doesn't fit well with your language is totally an option for a general purpose language but can become very unpleasant and/or hard to use for a low level system language. > rejecting clear improvements I'm not rejecting anything, I'm saying that many of the reasons design decisions you called defects are fundamentally the reason why rust has such a huge success. And calling this aspects defects isn't right. It's like saying city bike without a suspension is defect or a poor decisions. They are not. But I still would prefer other approaches (like a suspension you can switch off). Theoretical improvements are nice, but turning them into practical improvements outside of pet projects is hard. Which is why rust mostly went with decisions where there had been a bunch of successful research and prototyping done before. And even in that aspect with rather conservative choices. I mean that is partially where the name "rust" comes from, it mostly used stuff which was so old (in research) it could have been rusted. Because what rust pursed wasn't being a perfect language which overhauls everything. Instead it targeted a solid improvement over C/C++ for some specific set of use-cases which very intentionally does not do anything too unusual. E.g. they directly support the C-API/ABI so that it reasonably easy to include in C/C++ projects and include C/C++ projects into it, so that you can replace some components of larger C++ projects with rust. > As for C compatibility without copying the memory model flaws, it's possible, but it requires more thought than Rust put into it. If you combine it with higher performance requirements and requirements like wide spread platform support etc. it's very very hard. There had been research on this for years mostly for GC languages and for a long time success was rather limited. I think in "recent" years there had been some nice progress on this topic. But then this design decisions where made for rust nearly 9 years ago... I mean the first stable release of rust was 8 years ago. So not including research which didn't yet exist isn't really a poor decision. Furthermore even that success might not be practically appalling for all use-cases. Not for technical reasons. But sadly programming language design isn't just about technical aspects. Anyway I hop you all success with creating such a language or motivating people to create such a language. IMHO most software today doesn't need to be written in any system language at all. This even includes most "system" components. I mean a huge part of systemd could probably be written in WASM and it still would work fine for a lot of use cases as crazy as it sounds. So good luck.