It is readable, but you are right it is terribly formatted with a lot of not-very-important information in huge fonts.
I think rustdoc needs quite a lot of work in general. For example it doesn't even give a list of methods at the start of each type's page. Want to know which methods you can call on a `String`? Enjoy scrolling...
> I think rustdoc needs quite a lot of work in general.
It does. Honestly, it's quite hard to contribute to at the moment. This is going to improve in the very near future; there's a PR in the queue that's the start of the ability to start making it easier. I hope to make it vastly so someday in the future. Always so much work to do...
Wait, that thing is a button? I never knew that. I guess you can tell because when you hover over it, the status bar on your browser says "javascript:void(0)". I feel like this bit of design might just be a little bit too flat.
Maybe you could add a responsive right bar with the list of methods, visible when the screen is large enough. My 24'' monitor has 30% wasted space right now.
The docs make sense once you get used to them and understand what they're telling you, but it does take some getting used to. The general output of rustdoc could also be improved in my opinion.
A bit more summary of available methods/trait impls somewhere would be nice.
I'd appreciate a three scrollable pane setup, first pane similar to whats already there on the left, but always visible. Second pane type, usage, examples, methods, impls. Third pane in the middle, widest, actual information in long form. Inline examples of each method are incredibly helpful and the std library docs have quite a few of those but not always. Its sometimes hard to understand how to use a method or type or impl depending on its signature.
Panes should scroll+highlight currently viewed items in the actual doc (third) pane.
I find rustdoc's default layout to be suboptimal. Javadocs[0] give you the method summary table right below the prose and they are screen-filling like wikipedia, so the prose does not take up too much space.
With rustdoc you have to click on the [-] in the top right to get an overview of the available methods.
But yes, once I have that overview I can usually pick out the methods I need. The type signatures can be a little complex, but so are C++ templates.
The first time I went on a Rust doc page I felt exactly like you: «what the hell is this mess ! I understand nothing».
But a few weeks in, it started to make total sense, and now I see the page you link to and I'm like «That's pretty clear, no problem here». It just takes a little time to get used to the documentation syntax and formatting I guess.
Given the description of State, the fact that it only has two methods to get at the inner value (.inner() and Deref::deref()), and each returns a different lifetime (one is 'r which is longer than or equal to the lifetime of the State, the other the lifetime of the State), it should be reasonably obvious to people who've coded Rust for a while. The example helps, obviously.
I'm not a rust guy, don't know it at all... and to me it's not too much different than interface/type definitions for the .Net framework in C#.
It's often easier to work from examples though, but I do know that you often see interesting ways to do things when you look at API docs.
OT: the framework looks interesting... routing as attributes is pretty cool, would be nice if one of the examples on the main page used a route variable though. I am curious how this compares in terms of requests/second of hello world vs. alternates... I would imagine the memory overhead would be much lower, but curious on throughput for the underlying model.
My initial instinct is to ignore all of that documentation in your screenshot.
Specifically, the first thing, inner(), says that you generally don't have to call it because there's a Deref implementation. Deref is a trait that lets you implement things that loosely resemble smart pointers or similar wrapper types: for instance, CString, which tracks a Rust-owned C-compatible string (null-terminated), has a Deref implementation to an array of bytes. So I know that I can usually use a State<T> when a function seems likely to want an &T or Box<T> or similar, and I can carry on and not care very much more until I need to.
The rest are trait implementations of common traits (Debug is like Python's repr, PartialEq and Eq are comparisons, etc.), and the documentation is from the trait. I think this is a rustdoc weakness, but I know about it, so I can ignore reading the docs.
The documentation is not easy to read, and it often lacks important descriptive context about how to use a library. I started learning Rust about a month ago, and I feel like the documentation has made my life more difficult than it needed to.
In fact it's a pretty awesome example of Rust's traits in practice since it requires Sync + Send so you know it needs to be thread safe(and the type system will enforce it).
It is, but I think people accept that these are automatically generated outputs from compiler-created code.
Like any notation, once you understand how to break it apart and you learn what symbols mean, it becomes easier to interpret large fragments like this.
One pretty significant issue for newcomers is that rustdoc emphasises traits, rather than methods. Sometimes there is more indirections. It takes more insider knowledge to know that fmt() is actually called by the println!() macro, so you're unlikely to encounter that method unless you're digging into the internals.
The font sizes are dubious, as it is drawing more attention to type signatures than the actual function name and description. Once you draw your eye to the right place it seems pretty reasonable to me.
The "traits" feature of Rust's type system provides a lot of nice polymorphism and general ergonomics, but one consequence of its existence is that you see a lot of trait-related noise in the docs and it's maybe emphasized more than it should be by the styling.
If you know Rust, it's pretty easy to cut through it if you know what you're looking for, and sometimes it's actually useful.
One thing I've noticed is that the answer to "how do I use this library?" is often hidden away in a sub-page about one of the traits it defines.
Many libraries are made of boring top-level code and then interesting trait implementations. Structuring the documentation like the code doesn't work out very well in that case.
I think that out of all the bad things about Haskell that may or may not be reflected in Rust, this is one that annoys me the most: a lot of libraries have very strange interfaces that they do a poor job of explaining, often seemingly enabled by fancy uses of the type system. A recent example I ran into is formatted reading/writing of date/time objects in the `chrono` crate, which seems to be the blessed option for all I can find on Google. Anyway, just getting the bare minimum functionality that I could use in other languages by calling e.g. `strftime("%Y-%m-%d")` required researching a bunch of interlocking types and traits scattered across the crate, documentation nearly or entirely absent, and resulted in some pretty ugly code to boot.
I expect that the interface works this way in an attempt to avoid parsing format strings at run time ("zero cost abstractions" and all that), and that's great, but the lack of documentation made it pretty miserable to use, and I would classify my Rust skills as "intermediate". I expect a beginner would have just given up (and taken to HN to complain about the learning curve).
This is something I've seen, but does it apply to chrono? I'm looking at its README on GitHub (https://github.com/chronotope/chrono), and useful examples are right there up front.
DateTime::format seems to do the same thing as strftime, with a format string parsed at run-time.
I wonder if it would be useful if the docs offered a "what functions should my type have" hint for trait-heavy functions. That way all the required functions are in the same place.
What exactly do you mean by this? Could you provide an example?
Personally I think some big gains in documentation clarity could be made by sorting the methods differently, possibly more compactly; I remember when I was first starting with Rust it was easy to overlook trait impls, e.g. a useful `Deref<[T]>` implementation because they tend to show up further down in the docs.
I might also have benefited from a clearer overview of all the core traits in one place, especially the ones having to do with taking references. IIRC `Deref`, `Borrow`, and `AsRef` are all different traits and the differences between them (and how to idiomatically use them in common patterns) are not totally clear. But maybe I just skipped a chapter of "the book" or something.
Once you understand traits, those trait bounds really aren't bad. Now if this were some macro-heavy library, I could understand the complaints, but this is just constraining the type of the generic type.
I find it readable, it's saying that the "inner" function returns a reference to the value the State object is containing (which must be of a type that implements Send and Sync), and that reference cannot outlive the State object the value was returned from.
There are many languages I don't/didn't have to learn before I could read and/or patch code written in it. I hacked on C and C++ code long before I understood their basics. Go would've been the same if I hadn't bothered to spend a couple days learning it shortly after first exposure.
I've been using the framework to practice rust and it's really pleasant. I would compare this to "flask" from Python. I've got an experimental static site cms (for my clients eventually) where the administration back end is a dynamic library so I can update the back-end without stopping the serving of the website to the public. Really fun learning experiment and crazy fast server overall. For now, I still use Go, but Rust's meta features are so much more advanced that I'm working on switching.
I have to say, the end user API for Rocket is pretty nice.
But damn, there's a lot of compiler magic in order to simplify the request and response signatures.
It would be great to see more documentation on how to deal with naked Request/Response objects that can be constructed by hand. I'd love to use Rocket to develop some API on top of it, but that means I want more access to the underlying objects below.
I'm curious what's the difference between Managed State and good old Dependency Injection. Is it just a naming difference? In that case, why? People already know what DI is.
I tried to build a simple Rust "hello world" + database web app the other day (edit: not with Rocket) and after four hours I had nothing to show for it. I had a simple static app in just a few minutes, but I could not for the life of me figure out how to maintain state like a database connection pool and make it available to request handlers in any sane and maintainable way. (There are ways to do it insanely and unmaintainably for sure.) Has anyone else had this experience?
Thanks for trying out Rocket! There are a couple of examples in Rocket's repository that illustrate how to use Rocket with a database. The more complete of the two is the todo example [0]. This uses Diesel as its ORM alongside managed state to maintain a pool of database connections. The second example of the two uses raw SQLite without a connection pool [1]. It's meant to be a bare bones illustration of using a database with Rocket.
Managed state is a feature specifically designed to help with this kind of thing. That being said, I still think Rocket can do more to abstract away database connections. I'm tracking improvements on this front in GitHub issue #167 [2].
Thanks so much for the helpful reply! I should've noted that I haven't actually tried Rocket. :) It was a couple other frameworks that I'd played with, all of which seemed to go shrug, not our concern when the question of managed state came up. I'll give Rocket a try and see if I have better luck.
If there's anyone here with experience using both Rocket and Iron, would you be willing to share your thoughts on the differences between them?
I've got an API server started in Iron, but I have to say the claims of productivity and less code overhead that Rocket is proclaiming seem pretty nice right about now.
No. Usually web application would be exposed through FastCGI or similar
protocol.
Insisting that either your tiny web application that can do next to nothing is
the thing that owns 80/tcp (and/or 443/tcp) or runs behind a HTTP proxy is
stupid. Proxying HTTP requests properly is harder than it sounds, which is
surprising every now and then and thus is easy to screw up (what happens to
Host: header? who is the TCP client? is it HTTP or HTTPs?), and your tiny
web application, as I've called it, is not the only thing I want to host on
the machine.
Practically every company I've worked with uses an HTTP reverse proxy. When you use something like nginx, it's really not hard at all to get right. Support for HTTP is more widespread than support for FastCGI these days, especially with more obscure tech stacks.
Edit: You can run multiple apps on separate ports, so that shouldn't be an issue.
> It's not a matter of nginx. It's a matter of what assumptions are hardcoded in the application.
You haven't actually given any good examples for what makes HTTP reverse proxying bad. Things like dealing with the Host header are two-minute fixes that you only have to deal with once, but they really shouldn't even be issues in the first place. HTTP is well supported, well understood, easy to implement, and easy to scale. On the flip side, you might waste a lot of time trying to get your tech stack working with FastCGI if there isn't already existing support, and you don't benefit from any HTTP support you already have.
> Such a deployment looks terrible at best.
Again, "looks terrible" is not a valid argument against it.
> You haven't actually given any good examples for what makes HTTP reverse proxying bad.
Try running anything that generates absolute URLs in its HTML. And then try to
make it running under two different domains, for example. A clear cookie/URL
disaster, and it's all for web protocols from 2002, without talking about HSTS
or CORS yet.
> Things like dealing with the Host header are two-minute fixes that you only have to deal with once,
For every f&ckin' application.
> but they really shouldn't even be issues in the first place.
They shouldn't be, I agree, in that sense that it should be impossible to get
it wrong. With HTTP you don't have this and you need to deploy workarounds.
> On the flip side, you might waste a lot of time trying to get your tech stack working with FastCGI if there isn't already existing support,
Node.js may be the only offender here (I didn't bother to check). Virtually
everything else that is used for web applications supports FastCGI.
> and you don't benefit from any HTTP support you already have.
Like what? What exactly is the benefit of running HTTP between frontend HTTP
server and application's backend? Because the trouble with passing information
about the request is a clear downside.
>> Such a deployment looks terrible at best.
> Again, "looks terrible" is not a valid argument against it.
Oh, quite the contrary. Inelegant systems or deployments usually give a death
by a thousand cuts. Too many exceptions and rules and guesses to work with
them.
Just as we can judge the elegance of source code, we can judge the elegance of
deployments.
> What exactly is the benefit of running HTTP between frontend HTTP server and application's backend?
For some applications (those that fit within the constraints of REST - and, no, that's not all Web "apps") - you can sometimes get easy caching by dropping something like varnish somewhere between the user and the app.
> I only met FastCGI in PHP. All NodeJS apps I saw used HTTP.
And I met FastCGI in Python, Perl, Ruby, and Erlang (though I haven't used the
last one yet). Oh, and uWSGI can expose anything it runs through FastCGI.
My personal opinion is that web crowd (most of JavaScript programmers fall in
here) just doesn't want to learn from anybody else.
> Is there any benefit of doing it that way?
Compared to running the tiny web application on 80/tcp? Sure: I can run more
than one and I don't need root privileges for the application.
Compared to running the application behind a reverse proxy? Ditto: it's
virtually impossible to get the setup wrong, so it's easier in the long run.
Is this readable to Rust people? I mean, can you look at this and say, "ah ok, I'm gonna call this and that then I'll have the state" directly?
I'm lost but I have zero Rust knowledge so this is a sincere question, does this mess make sense when you get into it?