This is an interesting idea. I guess the key question is just *how*
negative heap allocations are. I think you are likely overstating the
case, or perhaps underestimating the extent to which the price of heap
allocations can be ameliorated by optimizing the allocator. But I don't
claim to have extensive data on this point.
But I have another concern as well. Regardless of how expensive heap
allocations are, they are likely to be frequently *necessary*. Much as
I love borrowed pointers, they are only suitable for things whose
lifetimes follow a stack discipline. Moreover, without a more complex
type system, there will be cases that do follow a stack discipline but
for which borrowed pointers are not complex enough to express. Given
that, forcing uses to write `ptr<Foo>` where in any other modern
language they would probably just write `Foo` doesn't seem like it's
going to win us any friends. `@Foo` seems a reasonable compromise to me.
I guess my fears boil down to this: I am already concerned about Rust
feeling too heavy-weight and ponderous. I like that Rust exposes things
like the program stack and gives a fair amount of room for
micro-optimization while still retaining type safety, but if that ends
up making the language feel less convenient than e.g. Java it may not be
worth it, given the speed/memory capabilities of today's computers (and
tomorrow's). So I'm hesitant to make changes that tax users of GC more
than we already do.
Niko
On 7/12/12 11:41 PM, Sebastian Sylvan wrote:
Hi Rust team! First of all, congratulations on the 0.3 release!
I have a bikeshed proposal to selectively simplify Rust's syntax in a
way that has the side benefit of applying "negative syntactic
pressure" on expensive constructs. It boils down to this: remove all
special syntax for heap allocations and heap pointers. Keep special
syntax for borrowed pointers, keep special syntax for fixed size
vectors. E.g. a heap pointer might be ptr<T>. Allocating a block of
uninitialized memory of type T might be heap_alloc<T>(), with the
normal literals used to initialize it.
Now, this sounds a bit crazy, and I'm pretty sure it won't be adopted,
but I'd appreciate it if you gave it a moment's serious consideration
and thought about what the impact would really be. I don't think it
would cost as much as you might initially think (modern C++ does
essentially this with all the shared_ptr etc., and many of the actual
allocation calls are hidden behind constructor functions anyway) and
there are strong wins.
The two main benefits would be:
1. Reduce the complexity of the syntax. In particular, reduce the
amount of "special symbols". You've all heard jokes about Perl looking
like line-noise, I'm sure. Reducing the amount of special characters
you need to know about before understanding code is a win. Getting rid
of some of the symbols and treating those types in a more regular way
would also kill a lot of design problems like "what does a heap
allocated fixed-sized vector literal look like"? Even more
importantly, it would make it easier to see what a complicated type
means because it would follow simple nesting rules that you already
understand, because it's the same rules that apply to user-defined
types. It would also make library-pointer types look like the "real
thing" (e.g. arc<T>).
2. Apply selective negative pressure to constructs which should be
avoided if possible. IMO good syntax makes "preferable" constructs
easy to write, and non-preferable constructs harder. Rust does a
pretty good job here already (e.g. sharing mutable memory between
tasks is suitably clunky). I personally think that heap allocations
deserve to be in the "non-preferable" category, too. They add memory
management overhead (GC/refcounting). They reduce locality. They add
waste (header words, the pointer itself, maybe ref counts, etc.). They
increase fragmentation. I believe controlling allocations will be
essential to good performance in the future, as heap sizes grow
massive (esp. for GC which is O(live_objects)). Heap allocations are
absolutely essential sometimes, of course, but it's preferable by far
to try to store the data on the stack or interior to the owning data
structure, or in a big memory pool, and use borrowed pointers to
access it indirectly - only resort to heap pointers if there is no
other option. This is also why I think the *only* syntactically
preferred pointer should be the borrowed pointer. IMO, Rust makes it
far too easy to allocate memory on various heaps - just add a little
sigil and you're done. C makes you appreciate the implications of what
you're about to do when you type "malloc".
Anyway, as I said, I don't think this will gain much traction, but
it's one of those small niggles that I would do differently if I was
designing the language, so I thought I'd float it for consideration.
Thanks for your time!
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev