by bkolobara on 10/17/22, 10:28 AM with 40 comments
by mckirk on 10/17/22, 5:41 PM
But as someone who often has to jump into unknown codebases and get up-to-speed quickly, I've certainly been confused by framework magic before, which makes it almost impossible to reason 'up' from the concrete implementation of e.g. a request handler. Since the keywords to grep for aren't explicitly mentioned in the handler anywhere and the 'dispatch' side of things is hidden under mountains of abstraction, you usually have to resort to tutorials to understand what the hell is going on, and even then the codebase might use some extra-magical properties of the framework that aren't clear to anyone that isn't at home within it.
So it could be argued that this magic saves you code in exchange for a need for more documentation, at which point you might just be better off being more explicit in your code -- at least explicit enough so things remain greppable.
by kibwen on 10/17/22, 6:38 PM
Ecosystems are rarely monoliths, and I assume that the people writing web frameworks in Rust are likely to have experience with (or at least be inspired by) more magical frameworks in other (usually more dynamic) languages, whereas the libraries that eschew magic are presumably written by people with prior experience in low-level languages. The fact that Rust has some amount of appeal to both of these crowds (not to mention the functional programming folks) makes it a bit of a melting pot.
by losvedir on 10/17/22, 6:11 PM
On the whole I still found experience pretty compelling, though, as I did eventually get a little web app running with great performance and very low memory usage.
by kubota on 10/17/22, 6:49 PM
by dathinab on 10/17/22, 7:37 PM
For example extractors on the json body will always _move the body out of the request_ (independent of the position the extractor is in).
Sure there is some copying for e.g. request parameters, but you very often do that anyway as you e.g. do some urldecoding, parsing and similar on the parameters, e.g. extracting a Uuid type from a `/user/9313ba53-955e-4ce1-8b53-de8f92656196/bar` path.
Similar if the extractor doesn't return the error type you want you can wrap it an map the error when extracting. Sure with actix-web and warp there are some error handling situations which they don't handle well, but that got improved on in axume.
Application state is shared across threads (or at least across time) so it's anyway in a `Arc` or `Rc` so you are just cloning the reference pointer but not the data behind it.
Lastly if you have a very special situation you can decide to just accept a `Request` moving (not copying) it into the handle and do the rest yourself by hand.
Without question the system has potential for improvements, but for now it has become the de-facto standard due to it being very convenient, does work well for many use cases and does not add a relevant performance overhead for a lot of use cases.
Now their solution is targeting backend WASM so they probably use will focus in single threaded WASM with some snapshot mechanics to easily sandbox each request so their requirements are anyway a bit different but looking into history routing macros where common in the past as far as I remember, and they are pretty much all gone by now.
But then they probably will go through a bunch of revisions of their system, so it's not like they can't add it back in later one.
EDIT: Just to be clear their solution is a fully valid reasonable approach.
by mleonhard on 10/18/22, 3:41 AM
https://crates.io/crates/servlin
Servlin contains no unsafe code. I picked dependencies to have as little unsafe code as possible. I wrote some unsafe-free deps: safina (async runtime), safe-regex, fixed-buffer, permit, temp-dir, and temp-file. I plan to replace other unsafe deps: url, async-net, and serde. Eventually Servlin's only unsafe will be in the standard library and `polling` crate.
Servlin supports single-file webapp deployments by including web assets in the binary. I plan to develop Servlin until it is as strong as nginx and can run reliably with no load balancer. And someday a good Rust unikernel will exist and we will run Servlin binaries directly on hardware. That will be the world's shortest, most secure, and most performant web stack.
Please contact me if you would like to help improve Servlin.
by brundolf on 10/17/22, 10:45 PM
Bigger picture: I think the reason so many Rust frameworks favor this kind of magic is to lower the bar (accessibility, but also development velocity). Being lower-level, Rust starts off with a disadvantage when it comes to quickly building out high-level application logic like you would on a typical web server, so when people are trying to expand its reach into areas like that, they try to close the gap by making their libraries as easy-to-use and boilerplate-free as they can. Rust's macro and type systems are the mechanisms it provides for eliminating boilerplate and generally making it act like a higher-level language, so that's what people use. And that makes well enough sense, even though it comes with trade-offs.
by SevenNation on 10/17/22, 7:49 PM
What's the difference between programming "magic" and "using the language to its fullest"?
Wikipedia has an article dedicated to the concept of magical programming. It starts with:
> In the context of computer programming, magic is an informal term for abstraction; it is used to describe code that handles complex tasks while hiding that complexity to present a simple interface. The term is somewhat tongue-in-cheek, and often carries bad connotations, implying that the true behavior of the code is not immediately apparent. For example, Perl's polymorphic typing and closure mechanisms are often called "magic". The term implies that the hidden complexity is at least in principle understandable, in contrast to black magic and deep magic (see Variants), which describe arcane techniques that are deliberately hidden or extremely difficult to understand. However, the term can also be applied endearingly, suggesting a "charm" about the code. The action of such abstractions is described as being done "automagically", a portmanteau of "automatically" and "magically".
https://en.wikipedia.org/wiki/Magic_(programming)
I think that "true behavior of the code is not immediately apparent" is the key. The harder it is to figure out how something works, the more likely it is to be viewed as "magic."
Do the magical handlers in this article fit the bill? I'm not so sure. All that's going on is generics applied to functions. True, it's not as common as generics applied to other types. But it's also not fringe.
Maybe as a technique becomes more established, it starts to seem less magical. The author notes:
> Exploring this pattern was an interesting journey. I still can’t tell why it’s more popular than the alternative that contains less magic and gives more flexibility to developers. I can only assume that even Rust developers long for some magic and coolness in their tooling.
Maybe it's more popular because it's now widely used across Rust web frameworks and therefore expected as a convention?
by chrismorgan on 10/17/22, 9:10 PM
I’d want a term mentioning that it’s type- or signature-guided or -driven. “Magical” is way too non-specific. How about “signature-driven handler functions”? Seems both accurate and fairly clear.
by insanitybit on 10/17/22, 7:52 PM
by efficax on 10/17/22, 7:19 PM
by gigatexal on 10/17/22, 8:37 PM
by Dowwie on 10/17/22, 7:22 PM