On 11/21/2010 03:33 AM, Sebastian Sylvan wrote:

On Sat, Nov 20, 2010 at 5:00 PM, Patrick Walton <[email protected]
<mailto:[email protected]>> wrote:

    But there's another problem with objects, and one that's potentially
    far more severe than the performance problem: sending them over
    channels. As I understand it (and feel free to correct me here),
    it's not clear that we're going to be able to send objects over
    channels at all, because they (along with functions) belong to the
    opaque typeclass, which means that we can't tell statically whether
    they contain mutable, shared data.


Isn't the solution to make sure that you *can* tell whether an interface
depends on mutable data? This is the distinction that e.g. D makes
between immutable and const (immutable means the data can't be changed,
const means that *you* won't change it - the latter is needed to make
sure you can write one function that can be used with both immutable and
mutable data).

Patrick exaggerated the concern here. It's not that we can't *possibly* send objects over channels, it's more that there are a few subtle interactions with both versioning and the stratum system that might argue that way, and we've discussed it as a possibility.

We definitely *can* tell when an object or fn is stateful. That's part of its stratum. There are three slightly-complexifying issues:

 1. We can't *freeze* a mutable fn-or-obj into an immutable one the way
    we can with "plain" data, for the simple reason that we can't change
    the methods! If one of the methods of an obj, or the code in a fn,
    happens to cause some mutation, we're not really able to
    spontaneously cook up an equivalent non-mutating version the way we
    can with simpler types (eg. mutable 10 turns into 10 pretty easily).

    But that just says we can't lower a stateful obj/fn to a stateless
    one automatically. If we happen to *have* a stateless one, it's
    stateless and we can sensibly consider sending it over a chan.

 2. If we have a stateless obj with a dtor, its lifecycle is in some
    sense "more observable" than one without a dtor. Like, making a copy
    when we hit a thread boundary vs. moving the value makes an
    observable difference. So we might not want that. One way around
    this is just to reformulate dtors as a form of state, such that when
    you add a dtor the obj moves to the state stratum. Problem "solved":
    you can't send anything with a dtor since it's implicitly stateful.

 3. More subtle is the issue of IPC. We haven't actually nailed down
    the exact level of compatibility we want to require between a
    parent process and child process when you do a "span process".
    (This feature isn't implemented at all just now, so...)
    It's possible that we may want it to be permitted to have a
    subprocess load an type-compatible but code-differing crate as part
    of a scheme for "hot upgrading" a running process. In this case we
    might wish to prohibit fns and objs from chan types just to ensure
    we're always sending "plain old data".

    Personally I'm unsure on this point; it sort of feels like overkill
    and I can think of other ways to achieve it (i.e. special case
    dynamic checks in any sort of hot-upgrade system). It seems like a
    high price to pay, and somewhat of a stretchy / speculative point
    to be hinging such broad-reaching design choices on.

In general I don't think we're painted into the "no objs go over channels" corner yet. We've been talking a bit about this as an extreme stance, but it's not clear that will be the correct balance. Opinions on the matter would be appreciated.

The vtbl and boxed-allocation costs of objs, on the other hand, are indeed the price of admission in our obj system. Though again, I think Patrick exaggerates here by comparing to objc. Objc has no vtbls at all -- just ad-hoc bags-of-methods indexed by unique string -- so it's doing something more analogous to the glib dispatch system or a PIC in smalltalk: an atom-keyed method-descriptor lookup with a cache for the fast-path. This is, I'd guess, a couple orders of magnitude more costly than the single (hardware-predictable) indirect jump you'll get in a rust obj: the objc code involves takes around 30 instructions (including a cache-scan loop!) on the *fast path*.

It's not clear to me yet that the boxing and vtbl'ing costs on objs will really hurt, but we're not venturing into objc territory on dispatch. We're doing more like "C++ with the pimpl idiom".

-Graydon
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to