
Rust for Web - EugeneOZ
https://medium.com/@eugeniyoz/restful-api-in-rust-impressions-63250d611d15
======
kibwen
I'm continually delighted to see so many programmers with backgrounds in
dynamic languages feeling at home in Rust, given that that's my trajectory as
well. :) I'm giving a three-hour Rust tutorial at OSCON this year and I'm
honestly torn over whether I should tailor it towards people coming from
dynamic langs or people coming from C/C++. I feel like I might end up just
having to write two tutorials and take a survey as people come in to determine
which to focus on.

~~~
StevePerkins
The creators of Go assumed that their primary audience would be disgruntled
C++ devs, and were surprised to find instead that it's mostly Ruby and Node.js
people.

Despite all of the "systems language" talk, it would not shock me in the least
to see the same thing happen with Rust (or whatever new language comes along
next year).

I don't intend for this to be a slight, but the plain fact of the matter is
that "dynamic" languages come in and out of fashion every 5 years or so. Those
people are accustomed to that cycle. They get bored easily and PREFER that
cycle. The senior ones are usually on their second or third language cycle (or
beyond).

In contrast, C++ and Java are ENTRENCHED in their areas (systems programming
and business applications, respectively). Whatever ultimately displaces them
someday... it will have to be an order of magnitude better, and it would still
take years.

By all means, market your favorite new language(s) to all possible
demographics. Just understand that the "PHP/Python/Ruby/Node/Go/Elixir/Swift"
crowd are going to be your primary adopters (and conversely, the first to grow
bored and leave when the next thing comes along).

~~~
pcwalton
> Whatever ultimately displaces them someday... it will have to be an order of
> magnitude better, and it would still take years.

I actually think there's no room for any language to displace C++ in that way,
_ever_.

The biggest reason that people give for bouncing off Rust is that the novel
aspects of the language--lifetimes and borrowing--are too unfamiliar and/or
hard to learn. Any language that is to be an "order of magnitude better" than
C++ will necessarily have aspects that are unfamiliar and hard to learn. Long-
time C++ users will bounce off that language for the same reasons they're
bouncing off Rust.

No non-C++ language will ever appeal to C++ users who don't want to learn new
concepts. C++ is very good at being C++, and for that reason it's immortal.
Rather, new languages will continue to chip away at the uses of C++, making
its use more and more marginal. This is a process that has been going on since
the '90s--remember that in the '90s practically all software was written in
C++, whereas in 2016 most new programmers aren't even learning it anymore. C++
has been declining not because it's being replaced but because its domains
have become smaller and smaller. Rust is just a continuation of that trend:
now there's a better option for security-critical software that can't be
written in a GC language for performance and/or flexibility reasons (to name
Rust's strongest domain), which has reduced the domain of C++ just as Java did
15 years ago for the server space and the rise of the iPhone App Store did in
2008 for the consumer app space. The continuation of this trend is what will
gradually make C++ more and more niche going into the future.

~~~
zanny
My only gripe with Rust is that they should have taken a page out of Python's
book in making a langugage syntax both stringent and beautiful. Not only is
PEP-8 the greatest thing when dealing with a community project ever, but the
syntax is designed around human readability in such a great way.

I think syntax like fn foo(bar: int) -> string {}; is a step backwards. More
glyphs, more arcane nomenclature, and I just get a ting of change for the sake
of change or "I want to be a functional hipster".

What is wrong with rettype name<templates>(argtype argname): ?

Why am I still writing all these damn semicolons and curly braces? I'm already
intending the code and newlining every statement.

Why are there so many damn macros when C++ is realizing having language
features rather than preprocessor macros is a huge usability gain?

I still think Rust is the best language out there today, but the failures in
my view drive me insane that its not perfect. Its so close!

I guess I kind of just want a native compiled statically typed Python, though.

~~~
pcwalton
> My only gripe with Rust is that they should have taken a page out of
> Python's book in making a langugage syntax both stringent and beautiful.

I prefer Rust's syntax to whitespace-sensitive languages.

> I think syntax like fn foo(bar: int) -> string {}; is a step backwards. More
> glyphs, more arcane nomenclature, and I just get a ting of change for the
> sake of change or "I want to be a functional hipster".

No, Rust's type syntax is the way it is to avoid the lexer hack, which causes
real problems in C++ (typename qualification, in particular).

> What is wrong with rettype name<templates>(argtype argname): ?

The lexer hack.

> Why are there so many damn macros when C++ is realizing having language
> features rather than preprocessor macros is a huge usability gain?

Rust macros are not preprocessor macros, not even close. Macros _are_ language
features.

~~~
zanny
What is the lexical hack in relation to the syntax I proposed?

I'm not arguing it, I'm just curious why Rust is using the prefix _var pointer
syntax when you are almost never supposed to use those in language.

I guess my point is more you could start from a clean unambiguous syntax (when
is "rettype name<templates>(argtype argname):" ambiguous?) and rather than
just verbatim copy C's glyphic syntax append vocabulary to the language to
describe ill-used features.

One thing I have always considered a reasonable design choice going forward
would be to _start* with somethking akin to ptr(foo) rather than _foo to
denote dereferencing. In general I would like to see languages in this field_
start* with vocabulary and transition to glyphic grammar only on the most
frequently used language features.

That would mean you could start with a language that does things like this:

    
    
       int foo(5)
       short bar(3)
       long res(foo.plus(bar))
       bar.equals(foo)
    

And then you could have just int, short, long etc classes that have operator
overloads for =, +, etc and systemically avoid glyphic overload ambiguity
because you are forced to handle that ambiguity in the operator descriptions.

With modern compilers (particularly LLVM) this could probably work very well,
because the optimizers are so good even if you start defining your primitives
in object notation and handing off really ugly bytecode that is treating
everything as a non-dynamic object the backend llvm equivalent asembly
generator will almost certainly be able to strip all the overhead out and
return you back to optimized platform specific math operators onregister-sized
words.

I'm not a language designer (obviously). I'm just a developer frustrated with
how every language but Python is so much harder for my uncle to read (who is
not a programmer) and thus makes _me_ spend more brain energy deciphering it
than if it were less verbose and more plaintext. And after writing a few of
the Rust tutorials on the weekend a few months ago and giving a crack at
writing a webrtc library for it I was really frustrated with how much
extraneous glyphic grammar I had to learn and deal with in the language, since
it seems so much worse than C++ from my perspective.

~~~
kibwen
(Note that your comment is a bit difficult to read because Hacker News turns
asterisks into italics.)

Putting the type name before the variable name can grossly complicate your
tooling (the aforementioned lexer hack,
[https://en.m.wikipedia.org/wiki/The_lexer_hack](https://en.m.wikipedia.org/wiki/The_lexer_hack)
), which is part of the reason why tooling for C and C++ is so relatively
rudimentary despite thirty years of time to address it.

There are also semantic difficulties that can arise from putting the type name
before the variable name. For example, C++ recently added a return-type syntax
that resembles what you see in Rust:

    
    
      auto multiply (int x, int y) -> int;  // this is valid C++
    

The reason why this syntax exists is because, well... it's a bit complicated
to explain here, read [http://www.cprogramming.com/c++11/c++11-auto-decltype-
return...](http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-
after-function.html) instead. :)

Furthermore, the `name: type` syntax is simplest solution when your language
supports both patterns and type inference, as Rust does. IMO it also reads
more nicely because when scanning code I care more about what a value's name
is than its type (which may only be because Rust's type system is relatively
strong, and I count on it to catch me if any types are out of place).

There's also the emerging historical trend: AFAICT, every language designed in
the past ten years has put the type after the variable name. Rust, Go, Swift,
TypeScript, Nim, Crystal, Pony... even Python 3
([https://www.python.org/dev/peps/pep-0484/](https://www.python.org/dev/peps/pep-0484/)).
All the proposals that I've seen for optional types in Ruby and Javascript put
the type after the name as well. And this syntax has roots in a much older
language, ML, and is generally shared by ML's descendants (such as OCaml, and
also possibly Rust).

~~~
zanny
For someone who uses Reddit and HN too much I sure can forget about markdown.

The function syntax C++ has seems more like a bandaid around the broken
scoping rules inherited by C more than anything. If you were writing a
replacement it seems like it would be one of your first considerations to make
each statement scope limited to the scope of the declaration. I mean, that is
what auto is effectively doing in C++ nowadays - you have to evaluate the
whole statement to resolve what auto is supposed to be at compile time.

I would take consistency of using postfix typing as a sign there is legitimacy
and simplicity in compiler design to do so, but I don't think the Python
example is particularly fair, since it (and the C++ ->) are both extending a
language that already had declaration syntax and thus the kind of glyphic
overhead imposed by colons and arrows is less condemnable because they had to
maintain backwards compatibility.

My gripe boils down to the difference between "August 5th" and "5th of
August". The latter can convey the information in a more meaingful sense (you
usually care about the day more than the month if you are using both) but it
comes with a grammatical overhead "of" that, if were writing and reading a
_lot_ of dates of this form, would have a tangible impact on overall reading
and writing efficiency. It would of course be minor - that is why its a gripe,
and I still love Rust from what I've done with it - but it nags on you like it
could have been done better.

And I also can understand the concept of name over type, but as someone who
strongly favors static typing over dynamic after about five years of Python
and three of C++, I think just conceptually "Canister Bob" is easier to parse
than "Bob the canister". It is almost certainly just habit, but I justify my
appreciation of the habit because it doesn't need to involve those damn
conditional constructs (be they the, if, or a colon) that clutter up my
reading and writing.

------
sjustinas
"<...> but I don’t understand why I need to write code for both cases, error
and success, when I only need value from successful case and I can completely
ignore Err or None results."

Have you considered `if let`? Seems like the exact thing you need here.
[https://doc.rust-lang.org/book/if-let.html](https://doc.rust-
lang.org/book/if-let.html)

~~~
CuriousSkeptic
That page illustrates an important distinction between expression based
languages and procedural ones. You couldn't do that in an expression, as it
wouldn't type check without a value for the None case.

When I first saw Option it seems like a great way to force handling of the
None case, either explicitly in place, or by passing on a mapped option as a
return value (monadic composition make this a nice thing).

This resembles how exceptions are handled in most procedural languages, either
you catch it and handle it, or you don't, and someone else gets to do it
further up the call stack.

The example on that page looks like the equivalent of an empty catch block.
It's almost certainly a bad idea that will bite you in the ass some day.

~~~
tpush
Maybe I'm misunderstanding you, but why wouldn't it work in an expression
based language?

Isn't

    
    
      if let pat = expr1 { expr2 }
    

just syntactic sugar for

    
    
      match expr1 {
        pat => { expr2 }
        _ => { }
    

meaning the type of expr2 must be unit, and thusly if let is always of unit
type?

~~~
CuriousSkeptic
Granted. But a unit expression is only useful for its side effect so I guess I
put that in the gray area between paradigms, not really in the spirit of only
evaluating expressions. Which brings us back the point of my comment: It's
almost certainly a bad idea.

------
squiguy7
I wish there were more articles like this as I'm genuinely curious of people's
experiences using Rust as a backend to their API's or websites. The only
example I had known of before this was Rust's own crates.io [1].

[1] [https://crates.io](https://crates.io)

------
Ciantic
I've been considering Rust (or Swift) for webapp backend, but these cons are
spot on: Named parameters are missing, and one can't build natural looking
JSON validation if one can't nest them nicely.

Swift looks promising though, if a bit in flux.

I've been ramming my head against Scala lately, and while it's nice at times I
would like to have compiled language.

~~~
kazagistar
Could you show an example of what you mean by "natural looking JSON
validation"? I am not sure I have seen what you are referring to.

~~~
Ciantic
I think succint is the word I want. Nested validation logic that looks like
the object you are validating.

Unfortunately Play docs are not succint, but you may get the idea from here:
[https://www.playframework.com/documentation/2.3.x/ScalaJsonC...](https://www.playframework.com/documentation/2.3.x/ScalaJsonCombinators)

I tried to implement similar (typesafe) myself using TypeScript:
[https://github.com/Ciantic/model-
validation](https://github.com/Ciantic/model-validation) there are certain
problems I hit with TypeScript, and also I don't want my backend to be
JavaScript so I've stopped working on it.

------
nickpsecurity
Good write-up and experience summary. Nice to see that people from dynamic
language backgrounds are able to pick it up.

------
rubyfan
I tried Rust with Iron as the article mentions but JSON parsing and writing
wacky match expressions turned me off to Rust early on.

~~~
dikaiosune
Out of curiosity, how long ago was that? I've found that over the last 2-3
months (I started tinkering around 1.4), the ecosystem has already become
quite a bit better.

~~~
rubyfan
About 6 months ago I think. It was pre-1.0 and yes some things weren't fully
mature. Maybe I'll give it a whirl again soon.

I was initially excited about Rust because it appeared to achieve system
programming language performance and stability with application programming
language expressiveness.

The nature of static typed languages doesn't allow for things like first class
lazy JSON serde. Java, C, C++, C# all have the same issue.

In the grand scheme of things it's not a huge deal if performance is #1 but I
value my enjoyment level while coding.

------
shockzzz
Is it just me, or is using Rust for web apps kinda odd?

~~~
excepttheweasel
The main downside to using Rust for web apps - at least in my opinion: is
having to learn and use a type system which includes affine types: lifetimes,
borrowing etc. But if you've already put in the effort to get to grips with
this part of the language, that's not as big a drawback. Then you get all the
other positives of the language, like its strong type system, fast speed,
sensible package manager, lack of GC pauses etc.

~~~
pcwalton
I'm in full agreement with this. The learning curve (and the compilation speed
I guess--but that's improving quickly) is the main drawback to writing Web
apps in Rust. If you've already learned it, though, then it's basically just
down to the typical static vs. dynamic typing tradeoff, with Rust just being
like any other statically typed language.

~~~
EugeneOZ
Rust's errors handling and memory safety are important differences too.

------
krullie
I was wondering how you would test web apps written in rust. In particular the
api you're building. Right now as my first rust project I'm trying to
implement an HTTP protocol with hyper but I'm not really sure how to test it
properly next to just creating a client connection and throwing requests at
it. Btw my final idea is to have it as a library that gives you a handler to
use with what ever rust framework you choose to use. Not really sure how to do
that though, I'm using a lot of hyper stuff.

------
poorman
[http://arewewebyet.com/](http://arewewebyet.com/) \- (You can use Rust for
web stuff, but the ecosystem isn’t mature yet.)

~~~
brobinson
This website is quite out of date. It hasn't been updated in 9 months.

Related:
[https://github.com/teepee/arewewebyet/issues/24](https://github.com/teepee/arewewebyet/issues/24)

