Hi all, Rust was recently mentioned on reddit again
(http://www.reddit.com/r/programming/comments/n4zsy/rust_a_safe_concurrent_practical_language_made/)
so I decided to check in on its development by reading the tutorial.
In general Rust looks to be progressing very nicely, and I had a few
thoughts.  I haven't searched the archives, so apologies if some of
these suggestions have already been considered.

1. Supporting the ternary operator "?:" when "if" is already an
expression seems redundant. "?:" causes confusion for C beginners, so
I think it would in rust as well. If there is a behavior difference
between the two that merits them both existing it would probably be
worth mentioning this in the tutorial. If there is no difference I'd
strongly suggest just sticking to "if"; operators are a rare commodity
and there are lots of semantics "?" could be intuitive for (e.g.
builtin optional<T>)

2. Inferring the type of 'x' in "let x = []" is neat, but is this type
of inference a privilege restricted to the builtin types? (i.e. are
you pulling a Go with generics inference instead of generics? ;) Can a
user define a generic data structure where the type arguments can be
inferred based on the structure's usage? If not I'd consider making it
mandatory that the type is obvious from the constructor (you could
still come up with ways that it needn't be explicitly specified, like
passing the 'default' value and inferring on that).

3. The subject says semantics but this is really a syntax objection. I
think "3 as float" will ultimately be a language wart, because 'as'
will be the only operator that operates on a runtime value (3) and a
compile time type (float) with the same infix syntax as regular
operators that only operate on runtime values. For generics you've
already established the C++/Java style Foo<T> syntax, so why not use
this for 'as' as well: "as<float>(3)" . As an added bonus the syntax
becomes more intuitive for C++ users accustomed to static_cast, etc.

4. target_os and similar attributes may seem convenient but I suspect
will have Rust biting off more than it can chew. What version of win32
does target_os="win32" mean? It's typical for projects to have
separate builds for Win95, Vista, etc. Generally speaking the whole
approach of toggling things based on the OS target is frowned upon
compared to testing for features with configure tests. Getting results
of configure tests into the compiler and having them affect the code
in a more robust way than the C preprocessor's text snipping and
find-replace hackery  (e.g. config.h and #ifdefs) seems like a better
problem to solve. If you could make the inclusion of a function
definition dependent on looking up a value in a dictionary file,
something like "#get_config_result(has_pthreads)", that might be
sufficient. The idea of an attributes mechanism in general though is a
good one.

5. bind as described (using only _ to indicate a missing argument)
doesn't let you change argument order, which you can do with
boost::bind. I don't whether or not this is an essential feature, I'm
just pointing it out. With boost::bind you can do "auto
print_args_reverse = boost::boost_bind(&print_args, _3, _2, _1);"
Looks like you guys are already considering removing bind, just using
lambdas instead would solve this, but I haven't thought the memory
management implications through so I'm holding back from suggesting
bind be removed.

6. Having curly braces after a function act as an implicit block
parameter is sweet. If I'm not mistaken though, you can use them to
build python like context handlers. Instead of using a resource, you
can write a function that takes a block, allocates some resource,
executes the block, then frees the resource. Though maybe this is
frowned on due to exceptions (if the block throws the free will never
run)? The tutorial didn't mention whether Rust is going to have them.
Anyway, if it is useful for inserting before/after behavior (e.g.
glBegin/glEnd) that seems worth mentioning.

7. Not sure if this is intentional or an oversight: but it looks like
there's no way to extend a polymorphic data type while maintaining
independent compilation. Tags let you make an abstract type with
several concrete subtypes, but all possible subtypes have to be
declared where the tag is declared. This is the trade off between
variants and abstract bases with virtual functions -- the former you
can know if you've covered all types when destructuring, but the
latter you can extend outside of the original declaration.

8. Having a 'cycle collector' for shared box types seems as bad as
having a garbage collector. The advantage of having reference counting
is supposed to be determinism -- if you're going to have something
nondeterministically freeing some objects (or is there a predictable
semantics for when cycle detection will run?) you may as well go whole
hog. I'm not sure if Rust's semantics make it possible to statically
detect if cycles are possible, though that would be nice. The compiler
could check for cycles in the types, so that a shared Foo couldn't
directly or indirectly point to other shared Foo's, or at least only
weakly to them (adding a concept of weak references), but that could
be tricky depending on your compilation model and you could be forced
to use weak references in instances where you know a cycle will really
never occur.

9. I'm curious as to the justification for making log a builtin
keyword rather than a builtin library. What is gained by giving the
compiler direct awareness of logging? Having a mechanism for
converting types and expressions to pretty string representations is
definitely worthwhile (I've contributed code to the Toast C++ library
to add this capability to C++ and it was invaluable for serialization
and log messages when doing policy based programming where the type
can totally describe a class's behavior), but seems oddly conflated
with logging. Unless you have plans for the compiler to say, patch the
code at runtime based on log level to overwrite log calls with nop
instructions (like the Linux kernel) to avoid the performance hit of
branching, then this seems like an odd choice (and even then it'd be
cooler to provide a non-logging specific mechanism for patching away
branches). Most heavy duty apps will need fairly customized logging
and you don't want the compiler to have to support all the possible
output types (file, syslog, zeromq, database, etc.).
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to