Some subjective thoughts on Rust


#1

Hello rust community, I’m very new here.

I first vaguely heard about Rust couple months ago when v1 was released. I’ve only started to have a deep look at it about 48 hours ago, looking for a C++ alternative, so far I’m very excited (and confused too), and I could see reasons to believe Rust might become mainstream in a near future.

Rust looks awesome in so many ways, however there are some aspects I do dislike. So if I had super powers and could change things, here is what I’d do.

edit: posted this by accident, so I’ll write my little wish list next :slight_smile:


#2
  • closures |x| {} would have been nicer with this style: x => {}
  • camelCase is nicer than underscore_style for functions/methods
  • modules namespaces should be clearer, in PascalCase, (and overall the api needs to be better organized).
  • Box <T> as a core feature, should have some symbol or keyword, to express instances allocated on the heap.
  • Result<T> should have something nicer than myResult.unwrap() (maybe *myValue ?)
  • Instantiating Smart pointers should be nicer, more intuitive and less verbose than Arc::new(T) (maybe renaming these types)
  • I don’t like the ‘let’ keyword, I don’t really know why haha.

Overall I see Rust very promising for its core paradigm choices, but the language in itself, the namespaces, type names could have been cleaner. What I did like about the D Language is its clean syntax.

Then, it’s just subjective. I’m from C# world by the way, it may explain things =)


#3

Too late :wink:


#4

Thank you for the RFC’s, they are very interesting. Those guys are bright! It shows my first impressions were not too stupid =)

I feel it’s not. Rust is not mainstream yet, there aren’t many tools depending on it and overall there isn’t that much codebase depending on it. So even if the core language was announced stabilized earlier this year, the early adopters would forgive breaking changes for a more polished language.

There are still many improvements to be made on various ergonomic aspects, that must be done before it’s really too late.

It’s just too early for Rust to already be tied to its legacy. Here is an idea:

The most pragmatic way to not depend on v1.0 would be to build a language migration tool. (any RFC on this? :wink:).
This (cargo?) tool has to be able to walk an old Rust AST, and update the code for the current version.
Why not even send automatically a pull request to all crates repositories? :sunglasses:

How feasible would this be?


#5

I would guess you could find out yourself by trying it? You’d first have to write suitable RFCs for each of your requested changes, and then convince enough of the user-base that they were valuable and more beneficial to the language than the status quo. Then you’d have to implement your tool for automatic migration (which sounds easy and stuff but is probably pretty difficult) and you also have to remember the code which isn’t in git or accessible via crates.io and is behind private things which may never see that you’ve asked to change things.

You have to remember that there have been various RFC’s and policy decided already which has dedicated the release systems to keeping these things which would be vastly breaking changes to a minimum, and even if you got all of these features down, they’d automatically qualify for bumping the version to v2 (if not more because of staggering the deployment of these changes)

(disclaimer: I’m not really much of a person around here, and haven’t really coded any rust either)


#6

No, it is too late. It’s not happening. We’re at 1.0 after years of breaking changes in various forms. Fundamental things like let and closure syntax are just not going to change.

If you’d like to see the language improved, I’d recommend focusing your efforts on changes that do not break existing code.


#7

What looks nice really depends on the language one is coming from. To a c++ person, x => {} is familiar but rubyists will be familiar with the |x| ... syntax. Furthermore, x => {} itself is ambiguous (some_fn(x, y => {z}) could be either some_fn(x, (y) => {z}) or some_fn((x, y) => z)) so really, you have |x| {} versus (x) => {}. I’d much rather type the first one. Finally, if I see |... I know I’m looking at a closure. With (... I have to scan till I see => to know this.

Regardless, it really is way too late. Rust actually does have quite a few users and even a few commercial users who would never come back if we pulled something like this.

unwrap() will (probably) never get this kind of sugar but the try! macro might. Unwrap is really an assert (assert_not_error) and should only be used when an error indicates a bug.

Currently, CamelCase means “it’s a (non-C) type” and snake_case means “it’s not a type”. There is no better/worse just what one is used to.

As killercup said, we’re going to be getting box X for boxing X (probably). However, we’re unlikely to bring back a special syntax for boxed types (Box<T>). We used to have ~T but this was abused (it was too easy to just box everything). Furthermore, I think the rust developers would like to make Box as non-magical as possible.


Regardless, thanks for taking the time to write up these suggestions.


#8

I know you guys are all right, I’m just feeling disappointed I wasn’t been here lobbying a year or two earlier.

I would love to write some RFC in the future. One of the big challenge would be to improve the the quality of my english. =)

I am indeed from a C++ / C# background.
The let keyword is fine, I can live with the closure syntax too. I have no doubt useful non-breaking sugar syntax that can be added in the future.
I think the most unfortunate thing lies in the Api structure, from the naming conventions used, to the module organisation.
Also I saw the Float trait earlier, binding specialized methods like sin, cos… to the primitive float type. It is a bit strange to me. My feeling overall is that Rust as a core language brings lots of innovation and is very well thought, but at the same time an unclean Api. I feel the D language got its naming conversion and organisation right.

However, I have chosen Rust for a new project, so I’m betting on it.


#9

Thanks for joining us @raizam!

Rust has already had countless breaking changes over its many years of development. There are many things I don’t like about the final syntax, but at the end of the day, it’s the semantics that matter.

The team made a promise. 1.0 will always be backwards compatible until the next major version (with the exception of bug fixes to for safety/soundess issues). Changing the syntax yet again would make people lose confidence in commitment, and discourage wider adoption. In addition, we have enough old pre-1.0 documentation, blog posts and tutorials out there.


#10

FWIW, I disagree completely with all of your suggestions, and as you said, they are subjective so it’s not like we could please everyone. I don’t get why changing syntax will make a language any better.

I really don’t like reviews like this because you have little to no experience using the language, so it’s very hard, for me at least, to trust your opinion.

I also absolute detest arguing syntax, so maybe that is a a reason I don’t like this review very much.

What do you think about Rust’s semantics? It’s library desgin ideals? That’s what I want to talk about.


#11

Hi sinitersnare,

I knew at some point my opinion might not be liked by everyone. But in the end, I just wanted to create a debate, not imposing my views.

The point here is to provide a fresh point of view, a feedback after 2 days playing with Rust, from a C++/C# guy. I haven’t followed the history of the language, as I’ve just discovered it. The reason I’m here is… that I love Rust =) and as it is somehow community driven, I saw an opportunity to do some (constructive) lobbying =)

I believe a language with great expressiveness and conciseness involves a nice syntax. For example, I wouldn’t be here if Rust had a Basic-like syntax. On the core syntax I did talked about closures and ‘let’ however these are really details (and I do regret I talked about these meaningless details)
But what I tried to emphasize, is mostly to add keywords on core features that are currently using types or functions, that are currently too verbose to me.

So here is what I love in Rust so far (to lower the tensions a bit).

The compile time safety paradigm is a bright approach, and makes this language unique. The “polymorphic enums” are just awesome, Combined with the “matching pattern” switch it’s very powerful. Being able to cast an instance as a trait enables abstraction, this was a must.

I was worried me about Owner/Borrower requirements for complex structures self referencing each others. But I saw the std::rc::Weak struct earlier, so I’m a lot less worried.
I still haven’t looked at concurrency features in depth, but look straightforward. (I’m not a big fan of lock/mutex approach tho, but there are probably alternative).
I wished exceptions was there, but I do understand why they are not and for good reasons. (Which makes the Result struct as a core object, and needs some sugar syntax to make it less verbose).

The only (constructive) criticism would be that Rust could be cleaner, and less verbose. I’m sure it will be less verbose in the future, but I’m unsure whether on not its standard Api will have cleaner feel. Maybe my mindset will shift at some point, and see its beautifulness, I don’t know. But still, I’m adopting it, it’s worthed it =)


#12

[quote=“raizam, post:4, topic:2650”]
I feel it’s not. Rust is not mainstream yet, there aren’t many tools depending on it and overall there isn’t that much codebase depending on it. So even if the core language was announced stabilized earlier this year, the early adopters would forgive breaking changes for a more polished language.[/quote]You discovered Rust just a few month ago, but it has been developed on the open for 5 years, and has already changed a lot. You can be sure that all the points you rise have been considered many, many times before Rust reached 1.0

Rust 0.1 seem really like a completely different language : most of the keyword changed, a lot of language features moved to library, there where 4 different pointers types with a sigil for each one, …

I disagree with most of your points except the standard library that may have been cleaner. The most obvious for me, is the module for core type that should have been grouped in a module.


#13

Personally, I actually like these kinds of reviews. Most (if not all, at least those that I’m aware of) things people feel are pain points when coming first to Rust have very good reasons for being like that. Knowing where people are coming from, and what they are familiar with has definitely helped me in the past when explaining the choices Rust made.

I would also assume that once stabilization lies further in the past these discussions will turn more into “What are Rust’s reasons for doing X like Y?” questions. If there is then a group of these issues that come up very often, those might be integrated more prominently in the introduction part of the documentation.


#14

If the reviews are, " I find borrow checking to be a difficult concept, especially when i tried X", then that is a great review, because it can provide valuable feedback to the community. If the review is “I dont like snake_case, because im used to camelCase”, then it is totally useless, because it is a wholly subjective opinion, and the style guide will not change.

I am fine with ‘how did X become a thing?’ questions, as Rust has a long. complicated, and varied history. If x == style or syntax questions, then the answer for every community ever will be ‘we had to choose one’. I just find syntax discussions unproductive. I do not see the style guide ever changing from snake_case to camelCase for variables, not switching the closure syntax from |bars| to fat => arrow.

OP was possibly getting somewhere with let, but he did not substantiate his claims, and resorted to ‘i dont like it’. let is very cool and Rust, and I love explaining why let is better than other declaration constructs in similar imperative languages like C# or C++, but I am not even sure what his issue was.

Sorry, I am bored waiting for the semester to start monday, so ranting on online forums is all ive been doing.


#15

I can certainly appreciate your point. Engaging in such (often repetitive) discussions can be tiring and feel like a waste of energy. Especially for the things that just don’t have a chance to change for many possible reasons.

I maybe should’ve clarified that often it’s not just the original post I find helpful, but the discussions that follow. For the “I don’t like it” example, the question would be “Why?” I don’t have a problem with walls of text, but some people will be more hesitant to go into detail at first. Even if the answer is just similarity, if this comes up often, maybe it means that Rust should add more information about the reasons of differing from other languages to the intro documentation.

Given that Rust in many ways does satisfy the familiarity requirements of C/C++ developers, collecting the places were people have a rougher time to improve the documentation in those places seems like a good idea.

I think the center of my argument would be: This kind of feedback will always come in one way or another. And I believe there is still some value in having them, and having a newcomers viewpoint present. Of course not for language design, but more for seeing where someone new is irked. The value is enough for me that I wouldn’t want to discourage these kinds of discussions.


#16

I have to agree that proposing changes to the current syntax feels like it gives little to nothing, now when it’s all solidified. It won’t change, even if it’s not as elegant as [insert the most beautiful language you can imagine], except for maybe a sugar or two, but still. It is what it is.

Same goes for the never ending CamelCase v.s. snake_case discussion. It’s like fighting over how ripe a banana should be. Some people like them almost green and some won’t eat them unless they have a few black spots. The measurable difference is probably too small, anyway, to matter in the long run (I haven’t checked). I like how the two styles actually has a meaning in Rust, by the way. It’s really nice to be able to look at an identifier and know right away that it’s a type and not just, say, a module.

Discussing differences and similarities between languages has a much greater value. I agree with what @phaylon wrote about using those kind of discussions to know what people from different backgrounds may need help with. Knowing that some people often get confused by certain parts of the syntax or that certain concepts are hard to grasp can definitely help when they need to be explained.

People who have only used the language for a short time will most likely not have a deep understanding in how everything works, and not being able to grasp what is causing a speed bump may be enough to convince them to abandon it all. It’s not worth their time. Listening to feedback from people who doesn’t understand, and finding out how they are thinking, is very important if you want to explain something.


By the way, @raizam, thank you for sharing your thoughts. It may be too late to change most of those things, but it’s still nice that you want to help improving the language. I hope you understand that some things will just be as they are because, well, people have different opinions and there’s not always one correct answer (if any at all). New things and improvements are on their way, though, so it’s not too late to contribute.


#17

I understand Rust has a lot of influences from functional languages, which 80% of coders never practiced (because companies haven’t adopted them) . Nevertheless, when lambda expressions were added to C# back in 2007, it was a huge innovation, leading to a more elegant and a lot more concise code. Then Java 5 adopted it, then C++11 adopted it.
These last few years, interest has grown towards functional languages, and a shift is slowly starting in the industry, mostly because of the problems it solves in concurrent programming area. And Rust has a lot of compelling arguments, as an hybrid language.

I made this post to share my opinions after toying a little. (and I insisted on the word subjective). But I thought my opinions might be useful as it may reflects what most mainstream coders would feel getting started to Rust.

Have to admit I’m surprised there are so many people defending the snake_case, as I’ve never seen it before for method names (didn’t even know how it was called). But hey it’s just cultural, I know I’ll have to live with it.

I maintain that manipulating core features like Box<T>, Result<T> and shared pointers, need to be more cleaner, more concise.

Andrei Alexandrescu managed to build Dlang with a beautiful Api layout. The Java api has a clean layout, the .NET Api as well. The C++ standard library is not very clean, but still better than Rust’s.
And that’s my own subjective opinion.

Now, I’m a newcomer here, and in some way I might not be legitimate to openly share my opinions after 2 days of toying.
However, if this community is as great as I heard, this should be taken lightly, just for what it is, with good intentions after all.

Now everyone is telling me it’s too late, and I can understand that. There must have been a lot of debate already indeed.

C# /.NET had breaking changes between version 1.1 and 2.0, at the time it wasn’t mainstream but started to get popular at version 2.
So I’m still hoping Rust won’t be tied to legacy for version 2.0.
I’m hoping the community will remain open, and not become conservative.

The idea of a code migration tool could be useful, this is a feature the Go language has, in order to keep a flexible evolution of the core language/standard api.

From now on, I won’t throw these subjective things anymore, I’d like to dig Rust a little further, build a first crate, and as someone mentioned I should rather write more formal RFCs if I want to push some reforms.

Happy coding


#18

A Rust 2.0 is allowed to make breaking changes. But there is an art to choosing when a 2.0 should be released and what exactly is worth breaking. (My current read: not soon.)

It is called go fix and it was in widespread use before Go hit 1.0. The tool still exists today, but Go the language is stable. Users of Go do not run code migration tools when they upgrade Go. (I actively use several pieces of Go software that I wrote and haven’t touched in a few years. They have never broken. This is wickedly awesome.)

It would help to provide some examples so that we can improve! :slight_smile:

Python (well, PEP8) uses it.

There are a lot of combinators already defined for Result, which makes composition quite nice. try! can make it even nicer.

N.B. Result is far more heavily used than Box or Rc types in my experience. If I look through my own code, there are 70 instances of Box (most of them for trait objects), 3 instances of Rc and 891 instances of Result. (If I look at a larger—but not complete—sample of code from crates.io, then the counts are 328, 29 and 1991, respectively.)

Understood. If you’re up for some heavy reading, you might trawl through the closed/merged RFCs. Not every feature of Rust is there, but a lot of them are, typically with very long and very thorough discussion.


#19

First impressions are also important, so that was a nice thought. I appreciate it and I’m sure other people does, as well.

CamelCase and seem to have become quite ubiquitous recently, so I wasn’t surprised that you would prefer it. I’m not an expert on the subject, but it seems like snake_case is relatively common in the C world, and apparently also in Python, as @BurntSushi mentioned . That’s where I can remember that I have seen it the most, but there are also exceptions. It’s quite cultural, as you said, and I’m sure you will get used to seeing it around. :smile:

I’m interested, how would you describe “clean” in this case? Do you mean short names? Descriptive names? Similarity between APIs? Well organised? I think “clean” can mean a lot of different things and I’m interested in knowing how you would describe it. You have mentioned a few APIs (and I can’t say that I’m familiar with all of them), but I’m not sure what exactly they have in common that you like.

There are still things that needs to be done with Rust 1.x, so I don’t expect version 2.0 to happen soon. When (or if) that day comes, you can be sure that many of the syntax pain points will have been addressed and debated, and some of the things you mention will certainly come up again. People will still have their opinions and compromises will still have to be made, but they will be backed with more experience than before.

The problem is that dependencies may be stuck with old syntax and APIs, which would cause incompatibility problems. You could try to run the dependencies through your migration tool, but it’s still not guaranteed to succeed. Rust has made a promise of not breaking builds with backward incompatibility, and that may come with issues like sub-optimal designs (subjectively or not), but it does come with a sense of security. It worked yesterday, so it will work today. That’s a big deal.

Don’t be afraid to give feedback to the community, like this. The issue was not that you expressed your opinions, but rather how you did it. It can be hard for others to grasp the benefits of what you are proposing (especially when they are used to how it currently is), so giving more details regarding why you think that something should be different will help others to understand your point of view. This will, in turn, be incredibly helpful when improving the language, documentation and ecosystem.

Constructive feedback is golden, so don’t hesitate.

Thanks, you too :smile:


#20

At some point, if I keep Rust-ing, I surely will dig into it =)

Results are definitely something that needs to be addressed.
try! is useful when the result is always ok, but otherwise there is a potential panic right? There must be a right way to solve it.
(RFC paper coming soon :wink: )

Sometimes I can troll quite a bit indeed, but it’s not always intentional haha.

snake_case is indeed used for plain C functions, as C don’t have classes nor namespaces, it was a way to prevent conflicts from duplicate names between libraries. Once C++ was introduced (adding namespaces and classes) the convention used by the standard library was to keep using snake_case for classe names, and camelCase for methods. But over the years, third-party/opensource libraries ended up using a different convention, using PascalCase for namespace and classes, and camelCase for method names. Underscores are used to prefix private methods.

Here Rust is a structured language, it has modules, structs and traits are in PascalCase (which is nice) but the fact member functions are in snake_case like C functions, break somehow conventions of most OOP languages, which tend to use camelCase. (except .NET which use PascalCase everywhere).

Descriptive and well categorized :smile:
To me, ideally, Types should self-describe precisely what their nature/function is, lying in their module organized in categories. Which would follow the pattern

{source}::{category}::{TypeName}

Hence for std::rc::Rc<T>, it may look something like std::ptr::SharedPtr<T>. Or std::boxed:Box<T> may become std::memory::HeapAlloc<T> (just quick examples).

I mentioned earlier core types used should have syntax shortcuts, this is still the case here, but average types should keep an intuitive description.

Also, as an example a module like std::thread is named directly after the main type Thread. It would have been better to give a name describing a category like std::threading

Also looking at a trait like std::convert::AsMut is named after the operation as_mut it exposes. A trait being by essence an addable capability should be reflected it in its name. In .NET, interfaces (traits here) tend to use the “-able” suffix, which is intuitive for “This trait adds a capability”.
so I would have preferred something like std::converters::Mutable (or AsMutable or MutConvertable). For Drop it might be Dropable.

Here I was just illustrating a philosophy, I’m not properly proposing how to rename. It’s all about intuitiveness in the names chosen, and providing to the user a nicely categorized browsing experience in the docs.
It’s also important to guide the community to follow intuitive naming conventions, so the third-party crates won’t get too messy overall.