
Rust for JavaScript Developers – Functions and Control Flow - rkwz
http://www.sheshbabu.com/posts/rust-for-javascript-developers-functions-and-control-flow/
======
MuffinFlavored
I just converted a relatively simple node.js program to Rust (because the
native libusb bindings for node.js crash immediately on Windows 7 64-bit)

Rust made me worry about a lot more than I wanted to. Threads, locking,
mutability. What was 80 lines of:

1\. open USB device, get handle

2\. start a WebSocket server, accept clients

3\. proxy incoming USB device traffic to all WebSocket clients

4\. proxy incoming WebSocket traffic to USB device

in node.js turned into battles with dyn FnMut traits to pass "callback/event"
handlers around, spawning threads to not block on libusb reading / WebSocket
client reading, borrowing, cloning, mutex locking, reference counting with
Rust like you can in JavaScript.

You can't just "move variables from one scope into callback/lambda" scope with
any sort of ease in Rust.

~~~
bluejekyll
It sounds a bit like you tried to write Rust like you do JS.

Rust is “move” by default. Passing ownership of a variable to callbacks
requires making sure you have the correct types along the way, especially if
you want to mutate. It can be easier in many cases to only deal with “owned”
data in Rust at first. Clone a lot, and so on.

------
hardwaregeek
It'd be nice to mention that Rust has if expressions, not if statements.

Therefore the example could be simplified to:

    
    
       fn calculate_tax(income: i32) -> i32 {
         if income < 10 {
           0
         } else if income >= 10 && income < 50 {
           20
         } else {
           50
         }
       }

~~~
65536
Speaking of which, coming from Rust (well, when I say it like that it sounds
like Rust is the only language I ever used which is of course not true. I
think Rust as a first language would be highly unusual still), I enjoyed being
able to say

Rust code:

    
    
        let foo = if x <= 0
        {
            0
        }
        else if something_else > 50
        {
            9000
        }
        else
        {
            42
        };
    

And I miss this in Swift.

The ternary operator is fine on its own but I’m not a huge fan of nested
ternary operators. With a bit of whitespace it's somewhat readable still but
still not as comfortable and easy to read correctly.

Swift code:

    
    
        let foo = x <= 0 ?                0 :
                 (somethingElse > 50 ? 9000 :
                                         42 )
    

One way of writing something that is more similar to the way I'd write it in
Rust would be to make a closure and then run it.

Swift code:

    
    
        let foo =
        { () -> Int in
            if x <= 0
            {
                return 0
            }
            else if somethingElse > 50
            {
                return 9000
            }
            else
            {
                return 42
            }
        }()
    

But it's a bit annoying still, both to read and to write. Also, even in the
current version of Swift (Swift 5), the compiler cannot infer the return type
of the closure on its own even though all of the branches return an Int, so
I'd have to explicitly annotate that as I have done in the code above.

I guess for a lot of people they would just make foo mutable and write the
code as

Swift code:

    
    
        var foo = 42
        
        if x <= 0
        {
            foo = 0
        }
        else if somethingElse > 50
        {
            foo = 9000
        }
    

I concede that this is probably the most readable out of all of the three
Swift code samples in my comment. But the point is that I didn't want foo to
be mutable. I wanted to assign a value to it based on some simple logic and
have it be immutable.

~~~
bobbylarrybobby
I find ternary operators perfectly readable if you split the parts across
lines — they map exactly to the conditions and statements in an if-else group.

    
    
        Cond1 // if this
        ? Result1 // return this
        : cond2 // else if this
        ? Result2 // return this
        : cond3 // else if this
        ? Result3 // return this
        : ResultElse // else return this

~~~
mekkkkkk
I've come to hesistently accept nested ternaries, but I try to have all lines
lead with a colon. This kinda mimics a switch statement with returns.

    
    
      firstPossible ? thenThis
        : secondPossible ? thenThisOtherThing
        : thirdPossible ? thenThisThirdThing
        : defaultThing
    

Always fun to see how people treat ternary nesting. They still feel a bit
naughty to me. The terseness is sort of unbeatable though.

~~~
Kkoala
It's funny how people have so many different preferences for ternary
formatting. I can't think of any other operator that would have tens of
different format prefs.

------
FranceBacce
Coming from writing JS all day, I've recently started learning Rust and I find
it extremely refreshing. Yes, it is heavy, low level and forces you to think
about how things work under the hood, but it empowers me to do high
performance stuff I just coulnd't do in JS before.

Def recommend it as a second / third language

------
crazypython
In response to this post, I wrote "Dlang for JavaScript Developers." Here it
is:
[https://news.ycombinator.com/item?id=23747652](https://news.ycombinator.com/item?id=23747652)

~~~
giancarlostoro
Thanks for that, I don't do enough D to know some of these syntatic features
but I do love the language. I do plenty of JS so this overview is spot on for
me.

------
jFriedensreich
Could someone explain why there is no dereference in let double = |n: &i32| ->
i32 { n * 2 };

~~~
rkwz
This SO answer explains the reasoning -
[https://stackoverflow.com/questions/54100030/why-do-i-
need-t...](https://stackoverflow.com/questions/54100030/why-do-i-need-to-
dereference-a-variable-when-comparing-it-but-not-when-doing-ari)

:)

Edit: On hindsight, I should've picked a simpler example that doesn't deal
with references.

------
oaiey
Now it is official: I like (modern) JavaScript.

I am a C# guy and every time I see modern Rust, C++ or Go syntax I am really
surprised by its deviation from the norm (which is interestingly no longer C
but a hybrid between JS/Java/C#). I mean why different Rust syntax for
closures and functions. || vs ().

On the other hand, the linage is not Java/JS/C# to Rust but C/C++ to Rust.
Considering that, it is an improvement.

~~~
chrismorgan
Rust has a philosophy of easy machine and human parsing. ECMAScript-style `(…)
=> …` requires that you get to the => before you know whether the (…) is a
parenthesised expression or function arguments. With `|…| …`, you know you’re
dealing with a closure immediately because there’s no unary pipe operator.

~~~
esperent
What's the reason for including ease of machine parsing? Aside from the fact
it might make the compiler slighty easier to write I guess.

I'm sure that code that's easy for machines and humans to parse is harder for
humans to parse than code where humans are the first class citizens.

~~~
chrismorgan
Many languages require arbitrary lookahead in order to parse code. (Some are
even worse, e.g. C++ requires a full compiler to parse it because of the
question of whether `(a<b, c>(d))` is calling a generic function _a_ , or
doing two comparisons; and Perl is unparseable, you’ve got to run it before
you can figure out how certain things should be parsed.)

Rust’s philosophy has been to avoid that, and make it simple to parse, because
that helps tooling and people alike.

Most people don’t see why this is a big deal. Here’s why: humans parse code
when they’re reading it in a very similar way to how computers do. This holds
true of natural language parsing, too, and is much better documented in that
industry. If it’s hard or takes longer for a computer to parse it, it’s very
likely to be hard for a human to parse it.

If you have fat arrow syntax, you need to skip ahead on the line to find it to
confirm that what you’re looking at is a closure. Pipes say from the very
start “this is a closure”. This could be said to be why Rust uses the `let`
keyword too, which is theoretically unnecessary (though you might need
something to replace it in a small fraction of cases). Not only does it make
parsing _way_ easier for machines (in a way that makes extending the language
grammar later much easier too, but that’s part and parcel of the parsing
philosophy), it makes the intent of the line immediately clear to humans.

~~~
oaiey
I agree to avoid look ahead etc, however, that could be solved more
consistently when you look holistically at the beginning of your language
design. Considering Rust was fresh restart (similar to C#), I expected more
consistency.

But maybe I should take a step back, considering my limited Rust knowledge :)

------
dgb23
> Arrow functions are a popular feature in modern JavaScript - they allow us
> to write functional code in a concise way.

> Rust has something similar and they are called “Closures”. The name might be
> a bit confusing (...)

This is in turn confusing to me!

I can't imagine a world where you know JS and especially "functional" JS, but
haven't heard of the term "closure".

"Arrow functions" are just sugar. They don't have any special meaning. All
functions in JS, regardless of whether they are declared, assigned, returned
etc., are closures and capture their environment.

Similarly a normally declared function in Rust are first class values as well
and for example can be passed into higher order functions.

Giving the benefit of the doubt, I assume that the author knows this and just
wanted to introduce the term in a beginner friendly manner. But I think it
would be less confusing to just use the term and link to an official
documentation:

Rust: [https://doc.rust-lang.org/book/ch13-01-closures.html](https://doc.rust-
lang.org/book/ch13-01-closures.html)

JS: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Clos...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Closures)

~~~
esperent
> "Arrow functions" are just sugar

This statement is incorrect. There are important differences between arrow
functions and regular function.

> An arrow function expression is a syntactically compact alternative to a
> regular function expression, although without its own bindings to the this,
> arguments, super, or new.target keywords

[https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)

~~~
dgb23
I include this in sugar as in:

You can refactor an arrow function into a specific regular function but you
usually end up with something more verbose.

Or in other words you can express all things "arrow" before it existed. Which
is exactly what we did before they were adopted. And we still in fact do, just
automated by transpilers like Babel[0].

But more importantly, in the context of the article: all functions in JS are
closures, regardless of how you write them.

[0] [https://babeljs.io/docs/en/babel-plugin-transform-arrow-
func...](https://babeljs.io/docs/en/babel-plugin-transform-arrow-functions)

~~~
FranceBacce
Well you couldn't resolve "this" lexically without some closure tricks like
that = this , so sure, you could do everything you do with arrows without
them, but not with one function alone

------
elramon
Neat! Thank you so much for this series, you have made a great work explaining
complex concepts in a simple way.

------
29athrowaway
Doing currency manipulation using with i32 as an example for developers of a
language that only supports float. What can go wrong?

Not only this is a bad idea from a programming perspective, or a teaching
perspective, it is also a bad idea from a taxation perspective. In terms of
taxation, what you suggest would result in [at least] civil penalties.

If you are going to create examples of code that manipulates currency, at
least take it seriously and think about what would actually happen to people
if they decided to use your code. Otherwise, use another concept to illustrate
your example.

~~~
kybernetikos
> Doing currency manipulation using with i32 as an example for developers of a
> language that only supports float. What can go wrong?

Using i32 for currency calculations is probably a bad idea (although there are
situations where it would be OK), but this has absolutely nothing to do with
javascript - it's no worse in js than it is in rust, since javascript fully
supports all i32 numbers. In fact, it has a number of bitwise operators that
operate on i32 numbers, and a bitwise operator that even works on u32 numbers.

------
Jysix
Good, now i need the same thing but for async :)

