Not being hindered by the compiler telling you what you can and can't do; freeing yourself from the write-compile-debug cycle, reducing it to repl-done; etc.
Not being hindered by the compiler telling you what you can and can't do; freeing yourself from the write-compile-debug cycle, reducing it to repl-done; etc.
Yeah, I certainly understand various language trade-offs, but in my experience any of these early wins of interpreted languages come back to haunt you at significant cost.
I saw someone use the analogy of a credit card on here before: purchases are very easy to make, but have to be repaid in full, and without perfect discipline you'll be paying interest on top. Now consider most development teams (who are generally strapped for resources) like middle-class earners who don't make quite enough to pay back that balance every month. It starts to accumulate, and the owed interest compounds.
Compilers can do a lot to ensure high productivity and a good user experience: (1) be fast, (2) have great error messages, and (3) be easy to use (no makefiles or heavy build systems). Rust's compiler has learnt from the mistakes of its predecessors in other languages, and does all these for you.
If you understood the wins of untyped languages, you'd be aware that this is often the most optimal path for a startup to take. Get features done now + fix them later is, in hundreds of cases, the way that startups win.
It's also a win for people who come home from work and want to get features done on their side projects rather than write perfect code.
It's beginning to get tiresome to continually hear the Rust community go on and on about how amazing Rust is and say, with a straight face, that eventually there will be no reason to write anything in not-Rust. Are you serious? The hubris is off the charts.
If your language doesn't have a REPL, your language is less productive. Deal with it.
That said, the engineering tradeoffs are often a win. I love Rust; borrow checking is frankly incredible. But it's important to keep perspective.
Oh hardly.
As someone who's developed software in Perl, Python, C, Java, C#, Haskell, and a few others besides, a REPL is the one thing I use the least. I've honestly never understood the obsession with it.
Is a rapid compile-run-debug cycle important? Absolutely. If I want to test something in isolation, being able to rapidly turn out a UT to prove my code does what I think it does is incredibly important.
But a REPL is a nice-to-have. Nothing more. Treating its absence as some fundamental black mark on a language is completely absurd.
In other words, if you can't implement a REPL, that's the definition of "less productive language." It's not about the REPL itself but the capability of implementing one.
Think about it like this: On your list of languages, which of them would you say is most productive? It depends on the context, certainly: libraries, familiarity, etc. But let's assume the languages had identical ecosystems, and that you were competent in all of them. Which of them would take the smallest amount of time to write your feature?
That'd probably be Python, Haskell, or even Perl. It seems very difficult to argue that Rust would top them. And the reasons why this is might be true are worth examining.
Here's another aspect. Is the Rust community claiming that the entire history of computing has lead up to this point, where Rust exists, and now nobody needs to write anything in not-Rust? Are people 200 years from now going to write Rust and nothing else? How about 20? 2?
It becomes very difficult to argue that your programming language is the lingua franca of the future. (And that's probably true for every language, not just Rust.)
Define productive.
Are you measuring raw lines of code generated?
Or are we measuring amount of production-ready code?
My bet: with an experienced, diligent developer it's a wash. My gut says what you lose in a slow code-execute cycle of static, compiled languages you gain in lower defect rates from compile-time checks. Conversely, what you gain in a dynamic language, you lose in errors caught at run-time.
At that point I'd select for languages that are simpler with fewer surprising semantics (crossing Perl and Javascript off the list), with more built-in run-time and/or compiler safety (knocking things like C off the list). I generally also prefer compile-time safety over run-time safety, as I'd rather find problems on my workstation than in the field because I missed testing a codepath.
Actually, I think Perl has fairly few surprising semantics after you learn the major ones. The real problem is that the major one (or specifically the major one, context) is somewhat hidden in normal C-like usage until it jumps out at you and confuses you. Once you understand what it is, it's not all that surprising (but there are a few annoyances with it that still persist and cause problems). You can write Perl that looks almost exactly like C 95% of the time, but that 5% where it matters makes people that do this very confused. There are, of course, other parts of the language that are poorly chosen, but I maintain there are actually far less of them than many people seem to think.
As for JavaScript, I still can't get over all the different ways to check for equality and null or undefined. I understand a good portion of that is because I never have to use JS enough to become truly proficient, and some if it is just poor design.
Let's be clear - the person who said there'd be no reason to write in anything else is an enthusiastic Rust user, but they don't work on Rust & don't represent "the Rust community." They were speaking from their own experience, based on their own balancing of the trade offs as a user. Presumably a REPL doesn't rate very highly for them.
However, the reasons we don't have a REPL are mainly two: the compiler isn't architected for it and code doesn't compile fast. The solutions are:
* Re-architect the compiler to support incremental code input. This is pretty similar to what we need to support IDEs (which we're working on), so possibly this will solve the problem.
* Get a reimplementation of the backend which is a JIT interpreter instead of LLVM, which takes up most of our compiletime. Work is underway on a project called miri, though it isn't officially supported right now.
* Make the typechecking part of the compiler faster. This is underway through a project called chalk.
In other words, a REPL is not impossible, it just isn't a top priority right now. There are other lacking tools that we're working on - IDE integration and auto-formatting for example - maybe after those are done it will be the top of the docket.
Respectfully, the community has become increasingly vocal, and it's getting hard to separate the enthusiasm from realism. It's embedded in every HN thread. That's a good problem to have, but it can be a bit repellant to people who aren't Rust converts.
Thanks for the breakdown and future roadmap. I hope the compile times can be kept to a minimum in order to avoid C++'s fate.
It's a relatively recent addition though.
That definition excludes any bare-metal language, and use cases where you want to take advantage of cheap low-level memory protection features such as No-Execute bits. For me, a more interesting benchmark would be how well Rust fares in implementing the runtime of a higher-level language.
Some projects are written as explorational prototypes or MVPs. I don't think anyone is saying Rust is much good for those.
But (numerous) other projects are written as "the first real Quality implementation of [well-known problem], using a decade's experience with other implementations." Much of the common software we use—{server daemons (HTTP, SSH, DNS...), parsers and encoding libraries (for XML or JSON; JPEG or PNG; MP4 or MKV...), databases, load-balancers, distributed queues, ...}—fits this paradigm.
If you're writing Nginx, or Redis, or djbdns, you aren't "adding features" out of some agile user-story kanban; you're carefully implementing a small, curated set of well-known, well-understood features, with much research done to ensure that you arrive at the best and least fraught implementation, the one that will make people prefer your software for its quality and reliability and set-and-forget nature.
Rust is for that kind of software. (Which makes sense, given that Mozilla's Servo rendering engine also has the goal of being that kind of software.)
In the case of startups, their goal is to sell out way before the maintenance phase of the lifecycle. So, it doesn't really matter to them so much as quickly getting out working features. In other cases, esp long-lasting endeavors, then this is a good point to consider.
Or grow so quickly that replacing most the legacy code from a year or two ago is not a significant hurdle at their new size.
In this vein, I wonder if there's actually a third path that might be better than both. Using a low-level but fairly expressive and strongly typed language but very loosely, such that it allows you to iterate fact but with less performance, and you can come back later and replace chunks as needed, but with the same language. I don't have any real experience with that, and I could see it going either way for a number of reasons, but it seems like we have more languages that might fit that criteria now (or at least they are more popular now) than we have previously.
Web browsers are not that kind of software. The web is evolving much faster than any of the other things you mentioned. New features get proposed every year, and you just have to deal with it and implement them, even if they complicate the implementation of the browser. Even if you cut that off, you still have to deal with the horrific mess that is the cumulative total of past web-related decisions.
There's certainly a layer of a rendering engine—the part that translates a CSSOM into rendering pragmas—that changes a lot over time. But rendering the resulting pragmas itself doesn't change much, and features requiring new pragmas come about remarkably slowly.
Clearly, though, you know what a rendering engine is, so I'm not sure what your argument in the GP post was. Was it just a tangential statement (i.e. "rendering engines are well and good, but it'd be silly to write the browser itself in Rust, for [reasons]"), rather than a rebuttal...?
Your post came off as implying REPLs don't have serious benefits for anyone, which felt a bit presumptuous to me.
BTW, I actually stand by your interpretation. I challenge anyone to demonstrate significant productivity gains (as measured by number of lines of tested, production code written) that can be attributed to the availability of a REPL (which was the claim of the poster I was replying to).
I honestly don't buy it. I believe it's a very nice tool for learning a new language, and maybe for exploring an existing codebase, but I can't envision a workflow where a REPL provides significant productivity gains for an experienced, professional software developer that aren't realized in other ways (e.g. writing unit tests).
It's high-speed iteration of code one is exploring that makes both REPL's and incremental compilation superior for productivity to full compilation.
That's not even the beginnings of a useful reply. :)
Give me a highlight of your normal day-to-day with the language. What, exactly, does the REPL offer you that provides significant productivity gains that can't be had any other way?
Because clearly I've missed it.
And it should be pretty easy for you to describe if it's that common and/or obvious.
$ time lein run
Hello, World!
real 0m5.683s
user 0m5.981s
sys 0m0.557sIn a statically typed language, a REPL can still be useful, but the gains from it are less than you'd get with an untyped language. It's easy to see what kinds of data a function works with by just looking at the types. There are exceptions of course, like when the type is very complicated, it can be helpful to see some examples of actual values of the type. And I suppose that's why languages like Haskell and OCaml have REPLs.
No one can demonstrate productivity gains because productivity can't be measured. Lines of code can, and those are often a bad thing. Some of our most productive efforts make programs smaller.
So then the OP shouldn't have made the claim. It ain't my job to prove it. :)
That said, I fundamentally disagree with the idea that one can't measure developer productivity. I agree that there are many potential measures, all of which have the potential to be flawed or distorted. But the idea that the productivity of a developer can't be measured at all is something I've never heard anyone seriously claim.
> So then the OP shouldn't have made the claim
Come now, it was you who moved those goalposts and you moved them half a field or more. OP claimed REPLs "have benefits". Your response was (paraphrased) "demonstrable measurement of productivity improvement or GTFO". That sort of ante-upping just isn't that nice for good conversation, and certainly not when you're demanding a standard none of us can meet about anything.
> If your language doesn't have a REPL, your language is less productive. Deal with it.
That seems exactly like the kind of claim that everyone should view with a healthy dose of skepticism, and I think zzalpha's initial response[2] hit that right on the nose.
I repeat: there are no perfect measures of productivity. But there are imperfect measures that have some utility. The idea that we cannot measure at all because we cannot measure perfectly is simply untrue.
In this case we could, for example, take 1000 individuals with similar years of programming experience and given them two languages and a non-trivial problem to solve and see how long they take to come to a working and correct solution.
Is that perfect? No. But it's still something that's measurable. Do that with a reasonably large sample and you can probably start making inferences.
Our industry suffers from a horrible lack of concrete, scientific studies to back common wisdom. We would all benefit from ignoring Fowler, here, and getting down to the nuts and bolts of finding solutions to that problem. Until we do, while we'll have lots of fun having pointless debates on HN that cannot be resolved because we have no real data, the industry simply won't move forward.
Unit tests provide some additional benefits, but are a heavier approach with a slower, clunkier feedback loop. There are times when those additional benefits are not worth the added cost. Unit tests are also additional code that must be maintained.
I guess it's one of those things that's imho hard to appreciate if you never experienced it.
That's called a remote debugger, and it's hardly unique to languages supporting a REPL.
The true key to understanding REPLs is their role in consuming third-party libraries. While languages both with and without REPLs will have well-used packages in their package ecosystems that are well-documented; languages with REPLs will also manage to have well-used, poorly-documented packages: packages whose "documentation" consists only of the de-facto ability to reflect on the API in a REPL, doing the moral equivalent of exploring a filesystem using cd(1) and cat(1), until you figure out what functions—and what arguments—combine to produce an acceptable result for your use-case.
That may sound like a bad thing, but it's not! Those packages are packages that wouldn't exist otherwise; they're marginal packages, packages which people wouldn't have had time to write if they were required to also document them properly enough to make use of them without a REPL. They're needs being satisfied, that would otherwise—given the stricter requirement of useful API documentation—be going un-met.
If you look at e.g. Ruby's gem ecosystem, there are tons of packages that have more than a million downloads, and either no docs or awful docs. How? Because Ruby is extremely amenable to exploring APIs through a REPL. You take a module or class, ask it what its children are, what its class methods are, what its instance methods are. Find a class with instance methods that sound right, attempt to instantiate it. Figure out you can't do that, look around the class methods for something that sounds like a factory method. What arguments does said factory-function take? Well, feed it some at random and see what error you get. Etc.
For languages with a reasonably sophisticated IDE, use the IDE itself to jump straight to the class/function declarations to understand the surface area of the API, and jump to the decompiled code for the implementation of those functions if you're the type to want to understand the machinery.
Other languages (like Haskell) may not have the IDE support but attempt to solve the problem with auto-generated docs so you can at least see the surface area of the API and can start prodding it.
~15 years experience across C, ARM assembler, Javascript, Lua, Ruby, Python, Erlang, Go, and Rust. Mostly doing Elixir these days.
Admittedly, I've never used an IDE; I write all my C in vim.
> ...you write compiled unit tests and/or test programs to poke around at the API.
That assumes you can get your tests to compile; or that the compilation errors are at-all helpful when they don't. If you've got a library that
1. ships as a binary blob + header files, and
2. most of its functions take handles to structs that are declared opaquely in the SDK headers; and yet
3. nothing you do with the badly-documented "create handle" parts of the API is giving you a struct that the "consume handle" parts of API will do anything with but crash...
...then you'll really wish that you had a REPL; or rather, a language runtime that enforced some level of introspect-ability on everything, so that a REPL could show you what's in the struct and whether your calls so far have failed to touch some obviously-necessary-to-fill-in part of it.
Without such support, you will have to rely on reading the decompilation results of both ends of the API to figure out what's really going on.
Yes. I write roughly equal amounts of C (microcontroller firmware) and Python (overall system control, running on embedded Linux).
I absolutely wish I had a REPL for C. When implementing with a new library in Python, I'll usually use iPython to explore it, and if I need to run a decent amount of data through, I'll use a Jupyter notebook. I'd put the difficulty of grokking a C library somewhere between 10x and 100x harder.
They were quite common advertising in The C User's Journal and Dr. Dobbs.
And now we get to the real meat of it.
It's not a REPL you want.
It's reflection.
It just so happens that the latter is frequently paired with the former.
And I agree, that feature, which separates C#, Java, Ruby, Perl, Python, etc, from legacy languages like C make them significantly easier to use as a developer as the compiler, debugger, and IDE can do a much better job.
But as a feature it's orthogonal to a REPL.
But when you are working in a language with runtime code generation—one where objects can build themselves new runtime-native function handles in response to messages—then a REPL will be able to do things for you that an IDE cannot†.
A REPL in a dynamic language (that takes advantage of its dynamicity) can be used to "explore" down CORBA/DBUS object trees; or fluently walk REST or SOAP endpoints without needing pre-baked WSDL descriptors to guide you to them. Heck, an Erlang REPL can hot-upgrade remote nodes. :)
† Or, at least, not a traditional IDE. You would need an IDE connected to a "live session" of your project—essentially a hybrid IDE-REPL. (Examples: Light Table; Emacs' CIDER extension for Clojure.)
Two dynamic and one static languages.
(Still, doesn't fit all use cases of a REPL for this. REPLs are especially nice for when you want to fit together highly generic APIs)
And if you are writing Coq or Agda—well, you certainly don't need a REPL at that point. The code writes itself. ;)
I happen to use more often the IDE's graphical debugger than the REPL.
Still Visual Studio has had immediate mode (aka REPL) since VB days, followed by .NET support.
When I wonder how something works or if I need my memory to be refreshed, I just fire up jupyter console and test quickly the code. I don't open the doc or search on the net. I have the live result immediatly.
When I want to debug my web server, I drop a REPL in the server and play with the code. It's more efficient that just debugging, because I can actually modify the code live and see what happens.
When I need to understand a format and how to manipulate / tranform data, I use the REPL (or jupyter notebook) because it's the most natural way to do it.
I don't know how much Python you have done, but you have been missing one of the greatest tool of the ecosystem.
It's like saying you don't see that much the benefits of an IDE for refactoring in Java. "yeah it's cool but how much do you use it hu ?".
So a few considerations here: (1) I really have no connection with the Rust community aside from curiosity, so it's quite dishonest to project my opinion onto all of them, and (2) this is very much my personal opinion.
---
I'd still defend the position though. Every language has merits, but especially for a lot of the older ones, there are so many accumulated problems that it's worth considering newer languages just because they're learned so much for the mistakes of their predecessors. For example, I've been doing Ruby for quite a few years now:
* Having so few constraints on implementation (e.g. duck typing) was an interesting concept, but time has proven it to be a nightmare maintainability. It buys you a little early productivity, but any honest person with a huge Ruby codebase can tell you that it's a liability.
* The only way to get truly good performance is to write a C extension. The language's whole implementation and performance-sensitive libraries are all C. Contrast this to modern languages where it's an embarrassment if your compiler is _not_ written in the language itself (Rust, Go, Swift, etc.).
* Core build infrastructure (Bundler) and environment management (rbenv) is maintained separately from the language. It works fine, but the reason it's not more core is not because it's better that way, but because the language's original designers didn't realize they'd be necessary, so they had to be developed separately. This has the effect of making the whole toolchain complex and hard for beginners to understand because none of it is integrated.
* The interpreter starts out faster than a compiler, but it breaks down fast. Codebases in the 100,000s of lines or more will take on the order of 10-100 seconds to start up, and the only way to get back to a fast edit-compile-debug loop is through tricks like Zeus. After you resort to that, unreliable runs and weird loading problems become a part of common life.
These aren't small problems. Also, I'm picking on Ruby here, but you could drill into a lot of existing languages and find flaws that are roughly on this level (JS/Python/C++/Erlang are easy, but even fan favorites like Haskell and Scala have pretty serious ones). Newer languages have their problems too, but rarely anything on this sort of existential scale.
We should stop pretending that all languages are equal with their own share of upsides and downsides. Given decades of language building, it would be disappointing if lessons hadn't been learned. Luckily this isn't the case.
In terms of what we write new projects in given a few years, there are other good contenders, but like I said above, I think that Rust has nailed a performance/safety/productivity/ecosystem compromise that's quite a bit above and beyond most of anything else.
Anyway, I was around for this kind of talk when Java was new and shiny, and there were people in the Java community claiming that Java was the future for programming, and any languages in the future would target the JVM or be phased out. That didn't happen, even though Java did well for itself.
What's really telling is that Java didn't replace C/C++, despite all the hype back then. Those two languages remain widely used.
There is an absolutely enormous amount of Java out there.
That's what is being claimed above, and what some in the Java community were claiming in the 90s. Also, probably some in the Javascript community these days.
But it's never happened. If there was the One True Language to rule them all, then Lisp, C++ or Haskell would have done it by now.
The point with Java is that even though it was targeting the C/C++ crowd specifically, and it became widely popular, did not cause C/C++ to die.
Again, who is claiming this? Can you link me?
If you want to argue with some several post up, please go several posts up. If you want to argue against me, than please do so on the merits of what I said.
The remaining 20% are stuff like device drivers or high performance libraries that are easier to write in C or C++, or legacy MFC applications.
Also if you look at operating systems like Android, Google makes it very explicit that you need a very good reason to down into the NDK dungeons, to the point that the set of allowed libraries only cover the use cases of 3D graphics and bringing native libraries into Android.
Likewise when Android Things was still called Brillo, the plan was to re-write the Android Framework in C++, instead they ended up bringing ART into Brillo.
Citation needed. Just because static typing is has been more fashionable for the past 10 years, doesn't mean it's a closed case. Before that people were extolling the virtues of dynamic languages.
Some people deciding they prefer static typing doesn't constitute some kind of consensus or fact.
I've worked with very big duck typed codebases for quite a few years now (and largely statically typed in C# before that) and the above is my opinion. Duck typing is convenient early on, but it makes understanding code (especially where it gets complicated or you didn't write it) quite difficult, and any kind of refactoring downright scary. After a point you (1) start getting hugely defensive with tests because without close to 100% coverage you just can't know if anything works, and (2) stop making big changes and instead accept that small incremental deployments towards a greater end is the only safe way towards making progress.
I suspect that how much you agree with this statement is strongly correlated to the size of your codebase. I'd be surprised to meet people with codebases on the order of 100k lines or greater that don't largely share this sentiment.
I'll admit, my commercial experience has all been in statically typed languages. But there are a lot of complex, well written pieces of software written using dynamic types. Maybe you don't meet their proponents, but they do exist.
FWIW, I quite like static typing, but I consider it a feature, not a religion.
https://drive.google.com/file/d/0B0cKsRm-3yprYTR5YTRaRFBfR28...
He said they mostly just test everything at the interfaces. However, it's simplicity also allowed for powerful tools in code generation, refactoring especially, and so on.
I like testing as much as the next person and consider it very important, but your tests should be testing business logic rather than whether your syntax is correct. The problem with dynamic languages is that while you're certainly doing the former, you're also doing way too much of the latter. Until you hit runtime, you have no idea whether you misreferenced a variable or invoked a method that doesn't exist, so you end up writing an exaggerated number of tests that are repetitive, slow things down, and end up requiring considerable maintenance.
> (2) is true for pretty much every large statically typed codebase I've worked on.
Yes, incremental deployment is always a good idea, but it's a matter of degree.
Take for example a case where I need to rename a method that's widespread throughout the codebase. In a static language, I wouldn't give this a second thought. If there's a problem my compiler will catch it, and that's the end of the story.
In a dynamic one, this is a dangerous operation: the old method name may still be getting invoked dynamically in a non-obvious way, or another branch may have been merged _after_ I branched but _before_ I deployed that still has an invocation of the old name. Hopefully you have tests on these paths that will reveal the problem, but you might not, and to hedge against that possibility, you have to roll the change out to production carefully and slowly (because even there, it might be some time before some unwitting user inadvertently triggers the bad flow).
I think what you really want here is fast compiles and iterations. You can do that without a REPL if using a language that compiles ultra-fast. Industrial BASIC's I used a long time ago compiled in a split second with me seeing the results immediately. Wirth-style languages tend to be able to do that. I hear Go compiles really fast. The wait doesn't really matter at that speed. Highly-optimized, slower compiles and tests can run overnight in background on dedicated machine, too.
Am I the only one who sees this as pure BS? Some people like REPL's, and that's cool. But not everyone. I find it utterly annoying that in any REPL I've ever used I first have to import (or similar) the libraries I want access to in that repl environment. You end up generally writing a file to do the imports for you, or cutting and pasting.
With all that effort I almost always find it easier to just write a test-case, even in languages with a REPL. At that point I have a repeatable and testable piece of code that can be run, with almost zero error due to the REPL environment not being setup properly.
Please point to a single place where anyone has ever said this. We have never positioned Rust as an end-all be-all language: it's a language that deliberately makes compromises in order to excel at a niche.
Right now, I don't do much serious work in Rust, almost solely because of compilation speed.
If you're seeing very large compile time then it's a good sign that you probably want to break things into smaller crates anyway. I've been working on some pretty large stuff and compile speeds haven't been an issue(aside from the Emscripten linker, but that's not Rust's fault).
Now, viewing this as someone coming from Python, Ruby, Node, etc., I can see compilation as being annoying. Is it really the only reason that they are disliking the language or is that just a strawman?
I wonder if too much attention is being paid to this. Now there are legitimate things we can focus on, such as making cached precompiled libraries very easy to use. This can especially be important in CI environments... This would also generally make most compilations fast.
This is already true today; that is, this cost is only paid the first time you compile. It's still not fast enough for people.
On my machine, a fresh build of rustc takes an hour, and small changes take 20 minutes, and even that makes it a giant pain. It's an ergonomic thing, IMO.
A bit influenced by the fact that rustc has to compile itself three times. :P
https://edn.embarcadero.com/article/20803
And even today Delphi 10 is quite fast.
Same applies to many other compiled languages with modules.
And no where near as fun. Hilarity ensued when I didn't realize there was no garbage collector.
Turbo Pascal was more a kind of simplified Ada than a pure Pascal, which made me look down on C when checking down the laundry list of language features of Turbo Pascal 6.0 versus ANSI C89 in 1993.
Also by 1999 no one was doing anything serious in Turbo Pascal with the last version being targeted at Windows 3.1.
Delphi 1.0 was released for Windows 95, and it did at least have some kind of GC for COM based classes.
Also Delphi 10 might not have every Rust feature, but it surely has it own set of complex language features.
Or if you prefer Ada, C#, D are also possible sources of information regarding performance of compilation toolchains, with relatively complex languages.
I wouldn't expect Rust would ever be as fast to compile, even if it weren't a younger language, because Rust is doing compile time optimization that Java defers until runtime. And that's ok: there may be times what Java does is better, but there are also times it's worse.
To be fair my javac comparison with with Gradle + Android Studio layered on top so it may be a bit slanted in favor of Cargo/Rust. That said I've never seen a Java build environment that I'd call 'snappy'.
Some Rust projects are very quick to build; but some are astonishingly slow to build. e.g. lalrpop is unusably slow (~15mins to build on 2014 Macbook Air).
I think the place here performance breaks down is liberal use of generic types in functions. e.g. AsPath<T> and AsRef<T>, etc.) where the compiler creates the function for all the different types and then tries to collapse them again later on. So one rules of thumb is to only use those in the public APIs and convert the type so it can be passed around without generics internally within a module. Or maybe that's just me trying to do some `cargo cult` heuristics (haha! puns!)
I always thought `cargo new` should have been called `cargo cult`.
Gradle sucks big time, why do you think Google still does talks letting angry Android developers that Gradle + Android Studio will some day be as fast as Ant + Eclipse?
http://androidbackstage.blogspot.de/2017/04/episode-64-gradl...
https://www.youtube.com/watch?v=BKRK4SvMtRk
The Android Gradle plugin being slow as molasses is a typical discussion theme at Google IO since it was introduced. Being partially written in Groovy also doesn't help.
On top of that `cargo watch 'test'`, runs fine on a 100kloc project, way better than my personal experience with Java. Now, when Rust compiles all dependencies from the ground up it is really slow, but that's only generally one time during development or after updating dependencies.
For me, the compile times are fine, and the end product generally doesn't need as much debugging as an interpreted language that requires no compilation at all, or has minimal validation, prior to running.
I think the user experience is more important than the developer experience. Using shared libraries that are likely already in memory provides a better user experience because it's faster, more stable, more secure and uses less memory.
The cargo approach will end up with windows/node level bloat where every app bundles half an OS.
Cargo is to Rust as cpan (the client) is to Perl, as pip is to Python, and as gem is to Ruby. All those other languages also have packages provided in many distros, but the developtment tool listed that downloads and installs relevant packages is also used when appropriate. For the regular, non-developer user that needs a module to support some program, that may be never. For the developer working in those languages that needs the newest version of the package, regardless of the back-patching policy of their distro, that may be often.
As I said, rust is meant to be a systems language, it shouldn't have an equivalent of cpan and, pip or gem because it needs to work with the system, not be yet another platform.
It's meant to useful as a systems language, so was designed with certain constraints in mind. It is whatever people want to make of it. There have been plenty of instances I've seen on HN alone of people mentioning use that isn't specifically tailored for a systems language.
> it shouldn't have an equivalent of cpan and, pip or gem because it needs to work with the system, not be yet another platform.
Those are entirely orthogonal issues. Cargo works with the system just as well as tar and make. They're just binaries. You could just as easily say that traditional source tarballs shouldn't be provided because people might download the source and use their compiler to build instead of using the distro package. This is a non-issue. The only people that will even have the choice are those that chose to install the compiler (whether it be a C compiler or Rust), and even then the vast majority that actually do so will probably end up having a good reason for doing so.
Cargo is part of the build tool chain. Just because it can be used to distribute a package, and even while it probably will be used to distribute a package, that doesn't mean it's purpose is to do so, or that it's inappropriate that it exists. Any feature can be abused. You should not judge it by the abuse, but by its intended and common use.
Cargo does it's own dependency management, so I assume you mean to say that because of this, it makes it difficult to integrate into standard methods package managers use. After reading some of the email threads with OpenBSD, I do get the sense that it's complex in that situation, but isn't that because of Ports? And Ports' expectations? Most things in Ports are C, right? I haven't worked with Ports in a long time, so I don't know it very well.
If you're pre-building something and pushing a package for say dpkg or rpm, I don't see a problem. If you're packaging source, then you'll need have the rust tools installed on the host to do that, which seems obvious.
After that, I can see some debate about blessing versions of crates in the Rust ecosystem for use in the OS' package manager, but this starts to blur the lines between what the OS is guaranteeing and what is the responsibility of the build tool. Should an OS want to bless crates, cargo does have an override for crates.io: http://doc.crates.io/config.html see the 'registry' section. I believe the other options in that configuration would also be things that the package manager on the OS would want to specify as well.
I haven't done any of this myself, but would be interested in trying to help figure it out if you have specific concerns.
Compiling the whole world, including dependencies is big waste of time.
I already tried to play around with workspaces to see if at least crates only get compiled once.
With other AOT compiled languages I use, zero third party dependencies are compiled from scratch.
This old issue discusses a bunch of this: https://github.com/rust-lang/cargo/issues/610 I couldn't find another in a brief search.
Edit: I should add that it does harken back a bit to my Gentoo days, where recompiling the world for that 10-15% architecture boost was a lot of fun, but also a waste of time in general ;)
Exactly, that's why it's a "fuck the package manager" approach, it ignores the package manager.
> If you're pre-building something and pushing a package for say dpkg or rpm
The problem is multi copies of the same dependencies everywhere adding all sorts of bloat and security issues. Not to mention introducing it's own incompatibilities.
> Should an OS want to bless crates, cargo does have an override for crates.io
That's a recipe for dll hell if I've ever heard one.
most binaries would be statically linked and compiled, so there wouldn't be copies, but you do have a valid point of an issue with needing to upgrade an tool that was build with a static dependency that has an issue.
If I understand you, you're saying Rust, a general purpose language, with it's own build tool should do what exactly? I see that you believe it's doing it wrong, but every package manager for every OS out there does things differently, Rust can not fix this.
> That's a recipe for dll hell if I've ever heard one.
The package managers can be configured to work with Rust, and likewise Cargo can be configured to work with the various package managers, but it takes work.
I think what you want is every crate on crates.io to be packaged as an installable rlib and dylib for every package manager out there, with the cargo manifest used to generate the various package managers dependency graphs as necessary. This would probably look a lot like, or actually be an integration with, FPM.
Exactly, it can't fix it but it tries to cover over this fact by bundling dependencies with every app.
> I think what you want is every crate on crates.io to be packaged as an installable rlib and dylib for every package manager out there
Basically, but more to the point, when a bug or security issue is fixed I don't want to rely on individual programs updating their dependencies. Let's say 10 years from now the rust version of gstreamer is widely used and a security issue is discovered, I want to be able to "apt-get upgrade" and know that it's patched. This is how things work now with the c version, but this can't be done with cargo, every app using the library has to update it's dependencies and many (particularly any corporate ones) will never update. Rust might be a boon for security but cargo could undermine the effort.
Aside from that, static linking creates a tonne of bloat, memory and disk. There is a reason windows apps are often so bloated compared to their linux counterparts.
> The package managers can be configured to work with Rust, and likewise Cargo can be configured to work with the various package managers, but it takes work.
I don't think that's good enough, if rust wants to be a systems language then it has to work with the system, not be a layer on top of it like java/.net/node. It can do this technically, but culturally it's looking more like node and less like c.
If I'm installed zlib for general system use, I want a package manager. If I'm installing a Rust compression library to be compiled into the program I'm working on, I want that to be managed by my build chain (especially since the version I'm using in my build may not necessarily match what I have installed on my system to run).
As another example, if someone makes a cook general purpose library using Rust, eventually it should be packaged up and shipped in the normal distro package format by the distro if it's useful. I wouldn't expect cargo to be the normal way to distribute software. It's the Rust equivalent of the old tar -zxvf package-1.2.3.tar.gz && cd package-1.2.3 && ./configure && make && make install. You can do it, but if you have a distro package, use that first.
To be clear, neither does the Rust team. You're exactly on point here.
From the getting started chapter of the rust book (which I believe you wrote?). That implies that rust can't be used without cargo right there. And I'm not seeing any libraries published as ubuntu packages.
After this conversation I thought I should expriment more with rust and it's linking options and quickly ran into an error of some sort (quite possibly a system one) trying to buils hello world with dynamic linking:
http://stackoverflow.com/questions/44012802/rustc-and-prefer...
> That implies that rust can't be used without cargo right there.
rustc can absolutely be used without cargo, and is in larger companies that use tools like Bazel. And we're working on making this even better, see https://github.com/rust-lang/rust-roadmap/issues/12 for one of the major items of work this year.
Second, again, Cargo is a tool you use to build your software, not necessarily one you use to distribute your software. It's like the difference between Make and pbuild or a similar tool; see the parent comment about "./configure && make" vs a system package.
> And I'm not seeing any libraries published as ubuntu packages.
Debian has an entire tool, https://crates.io/crates/debcargo, which automatically re-packages a Cargo package into a .deb. Currently, they only package the Rust compiler itself and Cargo, but this work was done specifically so that programs in Rust could be included in the distro, but packaged the way distros like. They've mostly been working on that stuff; I assume by the time Buster's cut-off date happens, there'll be some stuff; I'd like to see ripgrep, personally.
I haven't used -C prefer-dynamic in a while; usually SO questions get answered relatively quickly though.
The trouble is it's both. It's a build tool like make and I have no issue with that, I'll stick to make personally but to each there own. But I can't do that because It's also the primary distribution mechanism for rust libraries and even some apps. SPeaking of ripgrep, take a look at the installation section of ripgrep (http://blog.burntsushi.net/ripgrep/#installation) "cargo install ripgrep" is an installation option.
And because static compilation is also a distribution mechanism (just not for the end user) the binaries are 10 times larger than grep, not to mention a giant GPL trap for commercial users.
Please don't misrepresent my writing. `cargo install` is NOT the primary distribution mechanism for ripgrep. The installation section starts with instructions that use standard system package managers, and only then suggests installing it using cargo if you're a Rust programmer. Why did you leave that out?
You might also consider looking at the actual README of the project[1], which lists several more installation options, including using brew, chocolatey, pacman, emerge, dnf, yum and nix. There is clearly an effort to suggest that users install ripgrep using their standard system package manager.
Some of the points you've made in this thread are valid concerns, but please don't misrepresent other peoples' hard work while you're doing it. It's extremely rude.
Build tools like Maven and Gradle, as well as IDEs' internal build tools, will be smart and compile only the changed files.
Also a bit disappointed when compared with other languages that support modules, specially the ones whose toolchains support binary dependencies.
Not everyone has a high end development workstation.
I am however confident the experience will eventually improve.
Compilers are pretty hard. Languages like C and Go are able to short circuit the problem by having a simplistic type system, but the Rust team's main option here is hard work, and so far they seem to be more than willing to engage in it.
> At best it can beat C++ compilers - C++ being a language whose build times people love to bemoan - but usually it does far worse.
Citation needed on that one. How can you even make that kind of comparison fairly?
For all I know, that might be true, but it's one of those "citation needed" type things.
But I do take advantage of all VC++ improvements for fast C++ compilation, even playing around with the ongoing research work for C++ modules.
It takes me about half an hour to update rustfmt, racer and rustsym, every time a new Rust release comes out. On a dual core with 8 GB and HDD.
On the same computer, any of my VC++ 2015/2017 builds, configured to take advantage of incremental compilation and linking, using forward classes and PIMPL idioms, with all third party dependencies already available as binary dependencies, takes around 5 minutes.
Lack of incremental compilation and cargo not being able to deal with binaries dependencies has putted me off, after all if I want slow builds I can have them already in C++ when I go template meta-programming craziness, which are not that slow when using the experimental work Microsoft is doing with C++ modules.
Also since our use of C++ is constrained to libraries used from Java/.NET/Android/iOS, the build times are usually relatively fast.
Hard to sell Rust to anyone on the team, if that means their workflow would become slower, in spite of the safety improvements over C++.
I'm used to ~100kloc of C++ taking half an hour per config+platform on a 4-6 core, 16GB+, SSD machine. Less hygenic than your codebase sounds like, but with some beefy PCHs. Toolchain updates are usually a full day affair in this context, although that's not entirely from just the compiler bump.
Of course, incremental vs full rebuilds are no contest. Rust is at least working on incremental builds now that they have MIR AFAIK. And binary cargo support would be really nice as well. As would be compiling in general.
Cite a source? This isn't my experience at all, Rust is still way faster at compilation than C++ on average. The advantage that C++ currently has is ccache which helps avoid needless rebuilds (which pairs well with C++'s smaller compilation units relative to Rust); building this behavior into the compiler is part of what the incremental compilation initiative is addressing.
> It consists of ~7700 lines of Rust
...
> Compile times with Rust are Not Great. This is easily my single biggest gripe about Rust right now. The build for A Snake’s Tale takes 15+ seconds, which makes iterating rather tedious. The current incremental compiler work also doesn’t seem to make the build for A Snake’s Tale’s codebase any faster.
Actually, the compiler isn't the bottleneck - most of the time is LLVM codegen. So 'cargo check' is fast - the miri MIR interpreter likewise.
Why?
Because returns from startups are exponential and the interest rate is higher than the interest rate on the technical debt.
It's why compiled is a great choice for an established corporation with a well defined need and a large user base, while interpreted is better for most other business contexts, especially with tools like Numpy.
I'm still not sure what the best way of doing things is. I tend to think that Rust is going to be the programming language of tomorrows operating system, but I'm not sure if it is going to get the wide library support of something like Cython, since the scientific community isn't as fractured as the software community. Tools like graph-tool / scipy / etc are hard to live without.