Big asterisk on this: they don't, not on the abstract machine, at least. On the abstract machine, there's shadow state (that isn't represented on the physical machine) which is handled differently for shared or unique references: the retag/reborrow operation — in Stacked Borrows (Miri) this is what manages the borrow stack and puts the Shr/Uniq tags into the borrow stack. At an abstract machine level, it truly is two different functions, which may trivially reduce down to the same concrete machine code and be deduplicated.
Lifetimes, however, actually are a purely frontend construct; the abstract machine only cares that references are operationally used in a valid way.
This post gave me the idea that maybe it could be spelled ~mut instead of inout? Instead of C: constness, we have M: mutability which applies to all ~mut uses within the function/struct/etc.
I wonder if this would allow one to write Iter and IterMut impls with a single syntax in some way?
Why don't you separate the finding from the getting, i.e. return some index/search result type from find_child and then implement both Index and IndexMut for that type?
Similar to how find-Methods on arrays usually return an index and not a reference to the element.
Quick note: in the library I'm currently working on (fork of druid called widget-cruncher), I'm realizing that mutability effects would be less useful than I thought.
That's because, although my code still does a lot of tree visiting and stuff, the code that visits with shared references and the code with mutable references end up being very different, mostly because mutating the widget tree requires propagating changes.
I don't think that means an inout syntax would be useless, but at the very least it wouldn't be useful for my current use-case. I felt it was important to mention that.