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