Part 2 of my adventures in Rust, part one

First a quick note on modules, I’d go into more detail but the importing symatics seem to have changed between my version and trunk (trying to compile in 0.7 but using 0.8 documentation == headache).

The pub keyword I mentioned yesterday marks a function or type or whatever as public (for export) this lets you do use std::module::* without it totally hosing your namespace like it would in Python.

Rust has two sets of libraries, std and extra, extra is more or less equivalent to the standard library in python (though much less extensive) and needs to be imported. the std on the other hand is imported by default is equivalent to Python’s … Python guess, it covers things like integers and other things that Python and JavaScript would consider to be just part of the basic language and not part of a library.

I upgraded to trunk (0.8) and let me say that in 0.8 the libraries make far more sense.

Rust (as of 0.8) has two sets of libraries, std and extra. std covers the basic parts of the language and is linked to by default. Not all of it is necessarily in scope but a subset called ‘prelude’ (for those keeping score at home, this is a Haskel reference) are brought into scope by default, this includes things like printf (the rust console.log). extra includes what a Python or JavaScript person would think of as the standard library, except they would consider it extremely bloated (if coming from JavaScript) or totally lacking in functionality (if coming from Python).

As we noted yesterday the keyword 'pub’ allows you to note things as being public, aka able to export. So since our simplify module uses pub with Point and Simplify that means we can call

and it will bring those (and only) those into our scope. That being said a good programmer has a healthy level of paranoia that some else might screw up so it’s a good idea to only import the names you actually want into scope (This is non-rust specific advise so if rust is different please let me know) and we can do that here with

oh but wait that errors out if we do it, that’s because we have to declare what modules are in scope, which we can do in one of 2 ways, extern mod; links to a compiled library and mod without the extern links to an uncompiled one. Confusingly extern mod must be before any use ones, but mod (no extern) must be after, e.g.

so the first line links the compiled extra library, line 2 bring simplify and Point into scope allowing us to use them like we defined them in this file, the next line brings all things into the json library which is in the extra library into scope letting, and the next brings the library called path into scope, note that we don’t have to link to std but we do have to import stuff from it. Lastly we link to the uncompiled module called simplify.

The difference between what we did for json and path is that with json it’s Json type can be called as simply 'Json’ but for path, it’s Path type has to be called as path::Path.

Control Flow

The if statement at first looks more or less like JavaScript’s but with optional parentheses

But then this causes an error

Remember how I said yesterday that if you leave the final semicolon of a function out of a function it just returns that value for the function? Well that applies to most everything so the reason that causes an error is that it is returning a value that can either be a string OR an int, and that’s a problem because this is valid.

Also since there isn’t any type coersion the statement actually has to be a bool, the only truthy value is true and the only falsey one is false (which is lowercase, the way it should be).

The truth is that you’re probably not going to be using if else statements as much in rust compared to the match statement, which is sort of like the JavaScript switch statement, but instead of being a confusing source of error and overly complicated param handling it’s actually useful.

Now this isn’t full on Erlang style pattern matching, so no

But what you get instead is the ability to write branches to your program in a far more expressive and readable format, so instead of

you can use:

we’ve seen the underscore used before, and it is a placeholder for something we don’t care about. To soup it up even more, you can destructur inside the matches and use gaurds as shown in this example from the documentation

This is used by rust libraries to great effect as the main way to deal with operations that could error is to return something with the type 'option’. This type is called that because, wait for it, it has the option of being different things. So if you want to turn a string x into a float y returning -1.0 if there is an error

You see this a lot where node would take a callback, Python would throw an error, and Erlang would be like fuck this I’m crashing.

Next up we have loops

First is the while loop which works exactly like the one in Python, and the only difference from JavaScript is the block scope but that applies to more most things in life, also don’t forget that the conditional has to be an actual bool.

The next loop type is the loop loop. Which is the equivalent of just doing while true and will go forever until you call break. I actually like this type of loop, I think this is because I often have very complex while loops where about half way through development and just replace the conditional with true and do this anyway.

For loops aren’t really documented in the main documentation but seem to be a crude form of python for loops. Basically containers have an iter method which is similar to the python next method the documentation is unclear if you have to always call the method directly, but calling it does work, as in simplify I iterate through the keys, ignoring the values of a smallIntMap called markers (which was supposed to be a smallIntSet, but the set is omitted from the actual source for some reason but still in the docs in 0.7)

update

dbaupp pointed out on reddit that the most correct (rustic one might say?) way to do this would be via a for loop over the range function ala

Iterators seem to have been put in in 0.8 and are used for the functional methods like map and zip, I will cover them once I figure out how the hell they work, probably after I figure out what all those ~ do.