Still in love with Rust
dpc.pw
dpc.pw
> [if] you like it or not.
This is probably the best in-a-nutshell statement that describes what a good programming language is for me.
I had similar moments in the past. Before Python I cared about indention to some degree. But once I got used to the way Python forces you to indent your code, I came to the realization that this is pretty much the way I should format my code anyway and it influenced my coding style in all other block-based languages for the better.
Clojure was another language that showed me how functional programming should be done. My code in all languages changed and I used a lot less variables and a lot more constants and parameters. My code and the systems I created became a lot simpler and much more robust as a consequence. I had used Haskell before but it never really transformed my mind the way Clojure did. I also got a really good grasp on destructuring and list comprehension.
Rust offered me several relevations. I finally understood test-driven-development because the language has excellent support for it. I also understood RAII more deeply. Traits became clear to me (Clojure protocols and Haskell type classes felt strange to me). I finally understood why the Maybe monad in Haskell/ML is one of the simplest and yet bests ideas in programming.
And there is the borrow checker. I already had a functional programming mindset when I picked up Rust. But having a clear owner of data takes the mindset of functional programming even further[1], even when mutability is involved. It is a lot easier to reason about your code when you know exactly which operations can (and should) change a variable.
An aspect that the Python, Clojure and Rust communities have in common is that they emphasize idiomatic code a lot. Therefore it is much easier for newcomers to find examples of professional-level code and learn things the right way. And it is much easier to dive into a new codebase. Clojure is actually a very extreme case of this, because Clojure code tends to use a lot of 1-letter parameter names. In most programming languages you are allowed to have the variable "i" for looping over numbers. But not much more. In contrast, Clojure has a list of well-established 1-letter variables that are recognized by everyone in the community.
[1] This does not adhere to the classical definition of functional programming but I feel that it is a natural extension to it.
x[1][4] = a[2] + b[4]
Black will format like either of these: x[1][
4] = a[2] + b[4]
x[1][4] = a[
2] + b[4]
But not like either of these, unless you insert the brackets yourself: x[1][4] = (
a[2] + b[4])
x[1][4] = (a[2]
+ b[4])
Maybe this sounds like just one little problem but I think it's a fundamental flaw. I have seen the result of a Python formatter (not Black but had the same problem) applied to a couple of files and it's a total mess. I'd take inconsistent column widths over that any day. I asked the creator of black about it and he was pretty dismissive. x[1][4] =\
a[2] + b[4]This is the result of writing hopelessly long lines of code. Python doesn't force you to write long lines.
I've done it myself, many times, but gradually made efforts to avoid this. I'll move deeply indented code into a new function or split up a long expression with a temporary variable. If I run into a particularly hard-to-format portion of code, it's usually a sign of that my code could be better.
ys = [x + 1
for x in xs
if x > 0]
or: ys = [
x + 1
for x in xs
if x > 0
]I find the split comprehension more readable than the equivalent for loop. That's mostly because I'm used to that style, of course, but it's also because it's more constrained. Comprehensions have a very limited grammar, but there are multiple ways to write a for loop that builds a list.
That said, they are almost always harder to understand than an equivalent for loop with an if statement. A list comprehension by its very nature groups a number of actions into a single expression, it’s harder to break up the parts.
Even an experienced developer who sees them all the time and can understand one in a second, would probably take a half second to understand the equivalent for/if statements.
List comprehensions are basically a watered down gateway drug to functional programming. Everyone who has ever taken a functional programming course loves it (rightly so), and often tries to find places to use it. Comprehensions do quite a bit in a single expression, it's easy to see that inch towards functional programming.
However, junior developers haven't taken a functional programming courses. They learn to program instructions or statements line-by-line. They are told (not entirely accurate) that every clock tick, the processor moves forward one unit at a time. Your mind starts to imagine the processor in that way, executing a line and going on to the next. Do this, then move forward, then do that. This is procedural programming.
A list comprehension doesn't quite fit that model, because it does quite a bit in a single line (generally map + filter, sometimes reduce). They teach you that units of complexity can generally be broken down line-by-line.
Of course list comprehensions can be formatted to multiple lines, but it is intrinsically something quite different. A list comprehension is not a statement (e.g., var foo = b + 5), it's an expression (['b' if x < 1 for x in y]) and a pretty complex expression at that.
Junior software developers are taught about statements, going line-by-line. They aren't taught about functional programming or complex expressions. I love python comprehensions, but I wish they were presented in a way that was as easy to understand as a for loop with an if statement.
Senior developers wouldn't care, but it would open up a giant world to junior devs.
When compared to a set of functional style mapping and filtering functions, it quickly becomes much less readable as your needs become anything more than trivial. My main issue is that focus for the important aspect of what is being accomplished swings back and forth from the front to the back of the statement multiple times, especially if nested and with conditionals. e.g.
[(x,y) for x in range(10) for y in range(10) if y > 5 if x < 6]
or, in a similar formatting to what you show: [
(x,y)
for x in range(10)
for y in range(10)
if y > 5
if x < 6
]
In both cases, the accurate reading requires scanning back and forth from beginning to end of statement (whether vertically or horizontally) because the conditionals always postfix the rest of it (and this example is not as complex as it could be). For loops would likely have the conditionals preceding everything, making it obvious, and a set of filtering statements. The functional style also allows for a fairly straightforward reading of what's going on: toTen.filter(y=>y>5).flatMap(y=> toTen.filter(x=>x<6).map(x=>[x,y]) );
or: toTen.filter(y=>y>5).flatMap(y =>
toTen.filter(x=>x<6).map(x=>
[x,y]
)
);
Of course the functional style does require at least some minimal knowledge of some concepts often extraneous to novice programmers, so I understand why that wasn't chosen in Python's case. I just wish they had put conditionals in the same positional flow as the rest of the statement. >>> [(x,y) for x in range(2) for y in range(2) if print(x, y) is None if print(x, y) is None]
0 0
0 0
0 1
0 1
1 0
1 0
1 1
1 1
[(0, 0), (0, 1), (1, 0), (1, 1)]
Both conditionals have access to x and y.So the list comprehension is equivalent to this:
[(x,y) for x in range(10) for y in range(10) if y > 5 and x < 6]
And could more clearly be formatted like this: [
(x,y)
for x in range(10)
for y in range(10)
if y > 5
if x < 6
]
And would look something like this in a functional style, perhaps: toTen.flatMap(x =>
toTen.filter(x => x<6 && y>5).map(y=>
[x,y]
)
);I actually see what's going on a bit clearer now, as I looked closer and found that the correct way to write what I was originally trying to express is actually:
[(x,y) for x in range(10) if x < 6 for y in range(10) if y > 5]
which could be formatted as: [
(x,y)
for x in range(10)
if x < 6
for y in range(10)
if y > 5
]
Which is actually much closer to the functional style's flow, and is correctly eliminating iterations earlier in the loop (which is an important consideration).I was confused because I had seen examples where multiple if clauses where added to the right side, one per loop level (as I showed), and that makes it look like they are operating on the different levels, when in reality they are working on the innermost loop, like you showed.
I'll retract most my complaints then. There's still some question in my mind as to how you would usefully mutate items of the loop and use them in other levels of the loop without recomputing them again, but that might just be my unfamiliarity with the construct.
def txform_item(x):
<maybe many lines, as complex as needed, + can see vars in outer scope>
# right below, for optimal locality of ref for human reader
new_list = [ txform_item(item) for item in old_list ]But a condition can be easily split if it is assigned to a variable, and that variable then tested. And naming said variable well can make a comment explaining the condition redundant.
I don't get at all how being forced to do anything could ever be a good thing. Smells like cognitive dissonance from here. I'm all for powerful tools that enables me to write better code faster; but being forced, really? That's the best thing about Rust? Ew.
If you don't prefer tools that can automatically check if you were a good developer or not, it not only does not scale (to trust the software you build), it's that I wouldn't want to work with you as a teammate.
You are pretending there are no trade offs.
> it not only does not scale (to trust the software you build)
I think we should all be able to agree that empirically that is nonsense.
So anarchy it is, then?
But they're not.
> I don't get at all how being forced to do anything could ever be a good thing.
You specifically say that being forced to do anything couldn't be a good thing. The only other option is for nothing to be forced.
There are very few rules in C; same in Forth, Common Lisp and Perl among others; they provide tools, not religions. Python was always borderline.
These days it's like they're in some kind of competition to stuff as many rules as possible down peoples throats and get away with it. And that's not even the weird thing, the weird thing is that users are begging for more.
Or, for an alternative view, someone makes an extreme statement like "I don't get at all how being forced to do anything could ever be a good thing" and when called on to explain it in common contexts you note how you are harshly being attacked because of someone's ideology.
> There are very few rules in C
There are tons of rules in C. You have to type your variables. You often have to cast between variables to change type. You've likely just internalized them and accepted them as common so you don't think of them as cumbersome.
> same in Forth, Common Lisp and Perl among others
Even Perl is opinionated in spots. Have you ever wondered why postconditionals only work on statements, and not blocks, while regular conditionals only work on blocks, and not statements? e.g.
do_something() if $var_as_bool; # Valid
{ do_something(); } if $var_as_bool; # Invalid
if ( $var_as_bool ) { do_something(); } # Valid
if ( $var_as_bool ) do_something(); # Invalid
A choice was made to enhance the positive and suppress the negative aspects and possible uses of each.The thing is, what Rust is doing with the borrow checker isn't even as subjective as that. It's enforcing a constraint which, like type constraints, is based in a mathematical understanding of how to entirely prevent certain classes of errors. Like most type systems, there are escape hatches to allow you to do what you need as long as you take responsibility. So, since it's in some aspects in concept and execution to type checking, it's natural to ask someone that is critical of it what they think of type checking, as it leads to a natural explanation of how it works and the benefits.
> And that's not even the weird thing, the weird thing is that users are begging for more.
People like street signs as well. That doesn't mean they are always followed, but it is useful to see how to work well within the system most the time.
It's not like Rust has any rules just to make your code look funny.
> These days it's like they're in some kind of competition to stuff as many rules as possible down peoples throats and get away with it.
Could you expand on this please?
> And that's not even the weird thing, the weird thing is that users are begging for more.
... which users? And if the majority of them, then this perfectly explains the competition, but why are you surprised about the users' need for rules?
Jokes aside, I see rust borrow checker is just another dimension of type checking, it is type checking for access behavior and that's all about it.
Just as you can wrap your data in memory into static type system and leverage it to make a class of mistake impossible (passing wrong data to a function), you can wrap your access behavior into lifetime type system (converting raw pointer access behavior to reference with correct lifetime/access using unsafe) and make a class of mistake impossible.
In my definition, that's a powerful tools that help me to write better code faster.
I think a more proper tooling analogy is safety tools, like the Saw Stop. They don't guarantee that you make a good construction, but they do either prevent or significantly reduce the chance of you losing a thumb.
Edit: This place is disappointingly childish... It does not reflect well on Rust, either.
You're getting downvoted not because of the alleged childishness of this place, but because you're trying to win a discussion on a complex issue by scoring a simplistic "gotcha".
Anyone trying to sell you a tool by claiming that "it will make you a good whatever" is just trying it on. Yes, a good tool can help achieve better results but that's not the same at all.
Then, all the replies I received were seemingly defiant but all in fact agreed to the point while trying to sound smart.
Childish, because I feel that some commenters see posting as a pissing contest.
I'm genuinely surprised by the reactions.
And where exactly is the problem? You've received exactly the type of answer you wanted. steveklabnik repeatedly agreed with you by saying that a programming language cannot make you a good programmer.
Remember, your "simple truth" is just a small part of the whole story. The other part is that less strict languages allow you get away with mistakes and be lazy but later on fail catastrophically (e. g. by "losing a thumb"). You're dismissing this very important part as "trying to sound smart" or by calling it childish.
In addition, there was this thread: https://internals.rust-lang.org/t/concerned-about-rust-2018-...
All in all, Rust will be great when stable (including the ecosystem).
The only large change that I had to make over the last year due to ecosystem changes was going from error-chain to failure. Of course, this was not strictly necessary, but failure seems to be more popular now and I generally prefer it over error-chain.
This is also my experience. The feeling towards Rust is highly depends on the dependency of choice.
Rust itself is mostly very stable though. I've implemented few pure algorithms in Rust a little over two years ago, and it still compile and runs today without having to change a single letter.
Wish one day I can say the same thing to my other Rust projects :)
In which sense? That dependencies evolved?
For instance one project:
error[E0010]: allocations are not allowed in constants
error[E0015]: calls in constants are limited to tuple structs and tuple variants
Another: error: could not find native static library `brotli`, perhaps an -L flag is missing?
error: aborting due to previous error
error: Could not compile `brotli-sys`.
And I'm not talking what happens if you don't fix versions in Cargo.toml.And the second one is because a system library is missing. You're saying you have it installed, and it used to build, but does no longer?
const characters: Vec<char> = vec!['7', '+', '-', '*', '/', '^', '0'];
For the second, I do have brotli installed (via brew) and I have no idea why it can't find it now. It used to build. Note that I don't use brotli directly but it comes as one of the 274 dependencies (!) of that code. npm again...Do you know when the first one ever compiled? I tried it on Rust 1.0, and on every version from 1.20-1.30, and it always failed.
Ah, bummer. I haven't used the brotli lib, but that is unfortunate.
I even have a bit of Rust in production at work and I haven't encountered any maintenance issue so far.
Now the ecosystem itself can move pretty fast depending on the dependencies you use, that's true, but that's a different issue. You're never forced to update if you don't want to, you code keeps compiling with newer Rust releases. Compared to most languages I've experienced with, Rust has been very stable post-1.0. And they seem to take that issue very seriously.
The thread you linked might have some truth in it but it seems like the main point is "look, you've had a .2 patch release!" That's not a good thing of course but unless you happened to jump on that new functionality as soon as it got released the impact is rather minor and bugs happen.
Is it? I’m used to languages which bundle a huge set of standard libraries as part of the language.
Except of dangling pointers, Rust has everything else from this list.
About compilation time issue: it doesn't exist anymore. Current versions do "cargo check" in a few seconds even for big projects (my biggest project is 45k LoC) and it takes a couple of minutes to compile it because of incremental compilation. For libraries it takes seconds to compile and 1-2 seconds to run "cargo check" (or clippy).
About race conditions: https://doc.rust-lang.org/nomicon/races.html
try: module.find_element() except: # handle not found else: # handle found
Or this:
if module.find_element(): # handle found else: # handle not found
I don't think 45k LoC could be considered big, and I _do_ think a couple minutes compile time is a problem. I say that as a C++ programmer, a full recompile will easily get me out of the zone
I have Rust projects that are many times smaller but take much more time for a non-incremental build. Of course, a large difference is that a fresh Rust build (after a cargo clean) compiles all its dependent crates, whereas many C/C++ libraries are provided pre-compiled by whatever system you are compiling on.
Couple of seconds for 45k lines - I think you are too demanding :) But if C++ can compile it in couple of seconds - great, good competition for Rust :)
If you include a couple of C++ stdlib headers you're already well past 45kloc per compilation unit (for instance, including <vector> pulls in about 25kloc of code). Such a file usually compiles in a second or so, but the problem in C++ projects is that each source file pulls in the same headers over and over, which explodes the line count the compiler has to crunch through (I bet that in most bigger C++ projects, the actual project code is less than 5% of what the compiler actually needs to compile).
C is much more predictable, a 45kloc C project should compile and link in under a second for a full rebuild without optimizations, and at most 2..3 seconds with optimizations. The link-step is usually the critical part, since that's hard to speed up by throwing more hardware resources at it.
Lack of binary library support on cargo, not having incremental compilation and linking does hurt.
Facts:
Incremental compilation from 1.24 stable: https://blog.rust-lang.org/2018/02/15/Rust-1.24.html
Cargo recompiles dependencies only after "cargo clean" or after Rust version update.
Cargo surely recompiles common dependencies across crates, unless one uses the workspace trick and even then recompiles do happen.
Just get Gtk-rs, get nightly and then trace the build log. I once even mailed Rust devs about it.
Incremental compilation still isn't up to incremental compilation + incremental linking, which is why I explicitly mentioned both on my comment.
1. Hacker News won't let you downvote someone who replies to you, so it is literally impossible for you to have downvoted in this situation.
2. Both of you are correct, because you're talking about different things. Evgeniy means "You only need to compile your dependencies upon the first build", and you mean "if I use the same dependency in two projects, it will be compiled twice, once on the initial compile of both."
Even when I sometimes sound negative, I really appreciate your work.
Rust achievements thus far already influenced design decisions in other languages.
Given how often Rust updates, it might as well.
I think this hits the nail on the head for me: abstract structure first, the choice of language C/C++/Rust/... is then a secondary consideration.
I'm not saying Rust is the right answer but not paying attention to, or worse, putting our heads in the sand, when it comes to our tools is not the answer.
The point of a programming tool is to help the programmer to be a better programmer, there is indeed no point using a very strict language, statically typed with lot of constraints attached for a perfect programmer.
But for commoners it would certainly help to have some guiding.
Essentially the ecosystem today is C and C++ for embedded FW and middleware. Even if we are careful, we rely on static analysis tools to avoid some categories of bug. (Plus a humongous amount of tests). Typically bugs that would be caught (mostly) by the Rust compiler at compile time. I think it is a great idea to have some safety guarantee at compile time.
Would Rust fixes every problem ? Absolutely not, you'll always get logical bug or implementation not conform to the requirements but I think it is a move in the right direction, and I hope that slowly in next 10 years Rust will grow in the embedded space.
And overall cargo is nice, C/C++ don't have standard package manager. The test infrastructure is there by default, this is a breeze to add them in your code, rather than relying on an external framework, so this is also good.
I don't really see an alternative today for small footprint SW where C and C++ is king, and I hope that embedded toolchain vendors are taking notes.
If today you mostly code in javascript or python, unless you need bare metal like performance or to have stronger safety guarantee, maybe it does not make sense to move to Rust.
FWIW, my Rust setup in vim is mostly the following plugins:
* NERDCommenter, for commenting stuff
* rust.vim, for general rust things (like integration with rustfmt, playground, and the next two plugins)
* tagbar, for showing the list of tags (of the ctags-esque sense) in a sidebar.
* syntastic, for on-the-go syntax checking.
Then
:CocInstall coc-rls
and should work out of the box.I also use https://github.com/w0rp/ale to provide linting. Also works out of the box.
You can get these things running on vim8, but honestly it's easier to just use neovim.
If it's of any use, you can check out my full config at https://github.com/tom-james-watson/dotfiles.
So far I had two faltering attempts to learn Rust but somehow I didn't find good enough material to get me hooked.
I am looking for something similar to the Tour of Go[1], where you can interactively try the language by solving minimal tasks. Does someone know of such material?
As a somewhat experienced Rustacean, my biggest frustration as of now is the lack of a comprehensive reference where I can look up very specific things (e.g. the syntax for byte string literals, or an exact definition of how borrowing works in some particular edge case). There is [2] but as it says on the first page it's incomplete.
I think most of these programmers, and their project are not the target of Rust? If you're writing Java/C# or higher level languages, you already made the choice to sacrifice some computing efficiency for programming efficiency.
I always thought Rust was more destined to convert C and C++ (and D/Swift/Go ?) programmers, that need the raw power and control.
Or you just don't know any better, as was the case for me.
There are many benefits to Rust that are not related to runtime efficiency.
What kind of projects do you work on, and what made you switch?
My current job is not in ruby any more, now I do Lua - I'm a core dev at Kong - https://konghq.com/ . It's much lower-level than ruby, but still not as low as you can go with rust.
* "systems programmers", aka the C and C++ folk
* "functional programmers", largely Haskell folk
* "scripting programmers", mostly Ruby/Python/JavaScript folk
Each has gotten something out of Rust, and also brought some things to Rust.
I don't personally hear from many self-identified Java/C# people who are coming to Rust. Maybe they exist and I don't hear from them, or they don't describe themselves as such.
There are some Go developers, but it seems the languages attract very different types of people, so there aren't many. There are some people who do love both.
There are only a few people from D (of which technically if you squint I'm sort of one, incidentally.)
I stayed because I found Rust to be a language that not only doesn't get in your way, but also helps you out of some situations.
I mean, I had the compiler say to me "Perhaps you could [...]". Perhaps. And nine out ten times it was a good suggestion.
While I have not personally dappled this far into concurrency in Go myself, I have read plenty of articles where developers recommend using the mutex package rather than the goroutines themselves.
But I've also read about Rust's thread and resource handling -- and I'll admit, I've been looking for an excuse to write some Rust again -- and so inspired by this entry, I've decided to finish the prototype in Go, and build the real version in Rust.
What would I miss in Rust if coming from the F# background?
The biggest thing missing in Rust that are in both are higher kinded types. The biggest thing missing from OCaml is parameterized modules.
I take rust after 2 years on F# (that I continue to use). I have like 2 months of Rust now. I still struggle to solve things that are "no-brainers" in F# or swift (mainly, because Rust is VERY strict about know statically all about the code, and VERY hard to build generic, dynamic code).
So, it will look less expresive, IMHO. I still ramping-up and start to get more a more of the rust style of programming, so the pain is reduce. With the additions for rust in the near future it will reduce it more, I hope.
- non-type and template template parameters
- constexpr functions
I understand that Rust macros can replace them some of the time, and they are much better then the C preprocessor, but that's quite a low bar to meet. Last time I checked non-type template parameters (called "const generics" in Rust) is on the roadmap, so it is promising.
The equivalent of "non-type template parameters" has a design, but is not yet implemented. It's being worked on.
There's no direct design for the equivalent of "template template parameters", but a similar feature has a design, but is not yet implemented. It's being worked on.
If you write the Fibonacci generator in one of the first chapters of the Rust book it will create a 4MB binary. Even stripped it's over 400KB.
If you write the same code in Nim it compiles down to 112KB with debug symbols, unstripped. Statically linked against libc (still with debug symbols) it's only 850KB.
850KB statically linked versus ~450KB dynamically linked and stripped.
For code that is virtually identical.
https://internals.rust-lang.org/t/jemalloc-was-just-removed-...
This should reduce binary sizes quite a bit.
Mac OS:
- 1.30.1 before strip: 573K, after strip: 380K
- 1.32.0 before strip: 267K, after strip: 178K
Ubuntu 18.04 LTS:
- 1.30.1 before strip: 3.9M, after strip: 407K
- 1.32.0 before strip: 2.3M, after strip: 191K
when isMainModule:
echo "Hello World"
nim c hello.nim:Before strip: 113k
After strip: 92k
nim c -d:release hello.nim:
Before strip: 79k
After strip: 63k
nim c -d:release --opt:size hello.nim:
Before strip: 46k
After strip: 30k
Kind of a toy example but it illustrates my point. An unstripped version of the Nim program with full debug symbols is still 78k smaller than the stripped, release version of the Rust equivalent. But it's great that they're trying to work on this problem.
I don't know how the Rust team thinks, but I believe that minimizing binary sizes is not a very big priority for them. The cost of a gigabyte these days is, ~0.01$ (or less) for local hard drives, $0.4 for NVME and about $0.1 for AWS EBS...
Technically of course it's cool how small Nim binaries are, and it does make certain things feasible which with larger binary sizes might be difficult.
That said, the smallest executable produced is 145 bytes: https://github.com/tormol/tiny-rust-executable
OOP does not force one write complicated graphs of objects. OOP has its applicability, FP has its applicability and well-written code in conventional languages is a mixture of those two.
Rust today demands static knowledge of all relationships. But class APIs, inheritance hierarchies, and the like are powerful tools for dealing with dynamic relationships: code that runs together yet evolves separately, where Rust is feeble. Good programmers recognize that different problems require different solutions!
Mildly horse shit. It takes both on a team.
Also, what opinion rust devs have over golang?
Rust doens't have objects. You have structs, which are purely data, and functions, which are purely behavior. OOP puts the two together. So in Rust, you don't tend to design things by saying "what are the objects I need?" but rather "what is the data I am manipulating and how do I manipulate it?"
> Also, what opinion rust devs have over golang?
I am not 100% sure what you're asking here, could you maybe re-phrase? Are you asking why Rust is better than Go?
> Are you asking why Rust is better than Go?
No, just the opinion in general, why rust over go? I know go is more oriented to distributed systems, but it seems like rust eventually will be used for that as well. And I also see golang being used to build just anything, like gopass for example.
I got involved with Rust over Go because if I'm going to use a statically typed language, I need generics. That was the initial thing, but other things ended up going similar ways (I think package management is extremely important, for example.)
I think Go has made great choices to accomplish its goals, but I'm personally more interested in a different set of tradeoffs.
curl https://sh.rustup.rs -sSf | sh
Really?The script is less than 400 lines, and is pretty easy to audit. We wrote it in such a way to prevent some issues like "if the download gets cut off only part of the script gets run." It's served over HTTPS.
You can also probably get an install from whatever package manager you use, if you prefer that.
If you're auditing it, you've already downloaded it, so it's unclear to me why you'd re-download and pipe rather than just running it.
Encouraging people to run code from some random URL on the Internet is always bad.
It seems like an ever-changing work in progress at the moment, with idiosyncrasies such as this.
I was and still am very much in favor of the ideas and concepts, but when I actually tried to use it my opinion on it turned by 180°:
- The syntax is awful - No dynamic libraries - Slow compile times - Many checks are too stupid to figure out some valid cases (maybe that improved meanwhile)
- No dynamic libraries
This is technically incorrect, but practically correct, by the way.
> (maybe that improved meanwhile)
The next version, released on December 6th, ships "non-lexical lifetimes", which does make the borrow checker smarter.
I wish D would have won the C++-successor race.
While I understand that some people prefer this, I prefer static linking to dynamic linking. So much in fact that I refuse to use environments that only do dynamic linking in any of my projects.
Yes, I have to make a few concessions to that because of the idiocy of glibc, but other than that.
I generally do not mind syntax. I like OCaml’s and Erlang’s, for example, which are usually considered ugly, but for some reason I can’t enjoy the look of Rust code. I think all the nested <<<>>> and the use of :: are a large part of this.
But the real issue for me was refactoring owned struct fields into borrowed ones. The ‘a lifetimes leak everywhere; you have to add them to the struct field, after its “impls”, and everywhere the struct name appears.
I’ve found that Pony provides the same level of safety in a much more lightweight manner with its capabilities system. Interestingly, if I’m not mistaken, early Rust was somewhat similar to Pony.
Unfortunately Pony doesn’t have the same development resources and thus the ecosystem is somewhat lacking.