On 22/01/2013 6:55 AM, Dean Thompson wrote:

> I'm looking at some code that Niko Matsakis updated in
> https://github.com/stevej/rustled/commits/master/red_black_tree.rs
> 
>   pure fn each(&self, f: fn(&(&self/K, &self/V)) -> bool) {
>     match *self {
>       Leaf => (),
>       Tree(_, ref left, ref key, ref maybe_value, ref right) => {
>         let left: &self/@RBMap<K,V> = left;
>         let key: &self/K = key;
>         let maybe_value: &self/Option<V> = maybe_value;
>         let right: &self/@RBMap<K,V> = right;
>         left.each(f);
>         match *maybe_value {
>             Some(ref value) => {
>                 let value: &self/V = value;
>                 f(&(key, value));
>             }
>             None => ()
>         };
>         right.each(f);
>       }
>     }
>   }
> 
> I understand this code reasonably well. I greatly value the attention
> to safety in Rust, and I appreciate the value of pointer lifetimes in
> maintaining that safety.
> 
> My gut reaction, though, is that this code is almost as intimidating
> as Haskell. Even more worrisome to me, I think most mainstream
> programmers would find the *explanation* of this code intimidating.

I agree that the cognitive load on this code sample is high. This is the
main risk we took (aside from "potential unsoundness", which I didn't
really think to be a big risk, judging from Niko's comfort with the
semantics) when adopting first class region pointers: that the resulting
types would be too complex to understand, and/or require too much
chatter when writing out in full.

To my eyes the matter is not yet entirely clear. It's complex but it's
not quite "impossibly complex"; if you made all the '&self/' symbols
into just '&' it would be, I think, not so bad. Compare if you like to
the associated bits of code from libc++ required to implement
roughly-equivalent "iterate through the treemap" sort of functionality:


_LIBCPP_INLINE_VISIBILITY
__tree_iterator& operator++() {
    __ptr_ = static_cast<__node_pointer(
        __tree_next(
            static_cast<__node_base_pointer>(__ptr_)));
    return *this;
}

template <class _NodePtr>
_NodePtr
__tree_next(_NodePtr __x) _NOEXCEPT
{
    if (__x->__right_ != nullptr)
        return __tree_min(__x->__right_);
    while (!__tree_is_left_child(__x))
        __x = __x->__parent_;
    return __x->__parent_;
}

template <class _NodePtr>
inline _LIBCPP_INLINE_VISIBILITY
bool
__tree_is_left_child(_NodePtr __x) _NOEXCEPT
{
    return __x == __x->__parent_->__left_;
}

template <class _NodePtr>
inline _LIBCPP_INLINE_VISIBILITY
_NodePtr
__tree_min(_NodePtr __x) _NOEXCEPT
{
    while (__x->__left_ != nullptr)
        __x = __x->__left_;
    return __x;
}

And keep in mind that there is no memory-safety in that code: if I
invalidate a C++ map while iterating, I just get a wild pointer
dereference and crash. If I rewrote it in terms of shared_ptr<> it'd be
even chattier.

> Who is our target audience for Rust? Graydon has said it is
> "frustrated C++ developers", but how sophisticated and how "brave"
> are we thinking they will be?

The target audience is frustrated C++ developers, same as always. If
they balk at the syntax for lifetime-bounds on borrowed pointers, then
yes, we've blown the cognitive budget, and have failed.

It is not clear to me yet that that's true. But it's a risk. One we're
all aware of and worried about.

> How intimidating do we think Rust is today? Am I just overreacting
> to unfamiliarity?

I don't know. It's a very hard thing to measure. I know of lots of
languages that have failed for this reason. It's a major hazard.

> How can we calibrate our "intimidation factor" before language
> decisions start getting harder to change?

If you search our mailing list, IRC logs or meeting minutes for
"cognitive budget", "cognitive load" or "cognitive burden" you will see
we have always been keenly aware of this risk and treat it as a primary
constraint when doing design work. It's a leading reason why many
features have been removed, simplified, minimized or excluded from
consideration.

> Do we want (and is it feasible) to define a simpler subset of the
> language that beginners are encouraged to stick to and that most
> libraries don't force clients away from?

Personal opinion: no. That just makes the issue even more confusing. The
way to approach this is head-on, by looking at the things that cause the
most confusion and trying to make them cause less.

Thanks for bringing this up. I'm interested to hear others' opinions on
whether we're past a reasonable limit of comprehensibility. It's a hard
thing to hear, but better to hear now than later, if true.

-Graydon

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

Reply via email to