Hacker News new | past | comments | ask | show | jobs | submit login
Getting started with Rust by building a tiny Markdown compiler (jesselawson.org)
178 points by jesselawson 49 days ago | hide | favorite | 34 comments

I'm not completly new to Rust, but for some reason writing a Markdown has become a routine project I do in every language I'm learning.

This tutorial looks fantastic. Is the layout based on a 3rd-party theme or template? I really like the presentation.

I appreciate that you took the time to comment. Thanks for that.

If you are referring to the layout of the website, it's a custom theme I wrote specifically for writing tutorials like this. It's heavily inspired by the Octopress theme for Jekyll.

Thanks for your Elixir tutorials!

For those who don't know, Alchemist Camp is a YouTube channel and website for learning Elixir: https://alchemist.camp

Wonderful, thank you!

Hmm, I see the author liberally using _filename as a variable name saying "I just use names with underscores as functions arguments names".

However: In Rust, variables starting with underscores are usually indicating unused ids and if you actually forget to use it - you will not get a warning. As a tutorial material this sets very wrong mindset for the beginners. ONLY start variable with an underscore if you mean to not use it.

@jesselawson - please update this.

Thanks, berkus. I've added an [issue](https://github.com/jesselawson/rust-tiny-markdown-compiler-t...) to track these valid concerns. I appreciate your help!

I think the author did a great job with the format of this tutorial!

It includes all the steps needed to write the app, has exercises, is neatly splitted to chapters with clear expectations and summaries for each chapter and so on. Everything needed to reduce frustration, maximize knowledge retention, and make it a nice experience as possible to the reader. Awesome work!

Thank you for taking the time to share that. I appreciate your feedback. :)

1. This is more of a "taste-teaser" than a tutorial in my opinion, but it's nice enough I guess.

2. Perhaps a different page for each chapter/part would have been nice.

3. I wonder how different would a C++ "taste-teaser" with the same scope and goal be.

4. I'm not a Rustian (Rustic? Rust-guy?); this seems strange to me:

    // Try to open the file
    let file = File::open(&input_filename)
                    .expect("[ ERROR ] Failed to open file!");
why am I expecting an error? Shouldn't that keyword be "on_exception" or something?

> Rustian (Rustic? Rust-guy?);

"Rustacean", pronounced like "crustacean" without the initial 'c'; remember that Rust's logo is a crab (named Ferris).

Also, regarding ".except": like ".unwrap", you almost never want to use it, because it panics on failure. Instead, you can write:

    let file = File::open(&input_filename)?;
That will propagate the error upwards; if you propagate an error out of main, Rust will print an error message and exit with exit code 1, which is often what you want. Some error handling libraries also let you add context to the error before propagating it.

> why am I expecting an error? Shouldn't that keyword be "on_exception" or something?

`expect` takes an input that is either an error or a value, then turns that input into just a value. The provided string is the error message if something goes wrong (i.e. the input was an error).

A little counter-intuitive IMHO. But - I live with C++'s template voodoo, so I guess I can't really complain.

The way recoverable errors are signalled in Rust is through the return value, which is done using the `Result` enum. That enum is basically[0] defined like this:

    enum Result<T, E> {
Opening a file can, of course, fail for whatever reason, so `File::open` returns a `Result`. The `expect` method in that example is one defined on `Result` which takes that result and a message string, and if it's the `Ok` variant will return the value stored that variant. If its the `Err` variant it will print the input string and start an unrecoverable [1] panic, ending the program.

You would typically use `expect` (or `unwrap`, which does the same thing but without a custom message) when you either know for certain that it can't fail, or the failure condition is not something the program can recover from.

[0] Full definition can be found at https://doc.rust-lang.org/std/result/enum.Result.html

[1] Technically, you can catch a panic unwind [2], but it's more awkward and intended more for FFI boundaries than normal code. There's also no guarantee that the program will unwind. The compiler might have been set to abort on a panic instead of unwinding, in which case there's no unwind to catch.

[2] https://doc.rust-lang.org/std/panic/fn.catch_unwind.html

I read as it as "I expect this to work" since expect throws a panic! if it can't unwrap the result. Essentially you're saying you expect this to work because otherwise you'd handle the error properly using pattern matching or something.

it is intended to be read as “expect this to work”, or “expect this isn’t an error”

But the argument is an error message, so it's not "expect this to work"...

That's technically the second argument. Just like in C++, when using a chained method, the first argument is implied to be the thing you're chaining on. So this is the same thing as calling Result::expect(File::open(&input_filename), "[ ERROR ] Failed to open file!"), but I've never actually seen someone ever use expect that way.

See also the definition of expect: https://doc.rust-lang.org/std/result/enum.Result.html#method...

I'm a bit confused by the use of the word "compiler" to refer to something that turns markdown into html.

Perhaps 'transpiler' would be clearer? As many consider an HTML page to be an 'executable' (which is run by a browser) converting a text file into an executable would meet the CS definition. Pedantically the process of "compiling" markdown is more akin to "typesetting" but using the phrase 'markdown typesetter' would be even more obscure.

If there a word for the action of converting the description of a ritual to the actual practice of that ritual, that would provide a suitable root word form here. That said, using the closest example I can think of, music, the root word there is 'performing' when the music is performed and recorded when the music is performed into a storage medium, and transposed when the music is converted from one description to another description while maintaining the overall musical relationship between the timbres.

It is that latter version, transposition, which suggests the word 'transpile'.

I once worked on a source-to-source translator from C++ to C. In that era, that was the common term for that kind of software. I think that's more clear than "transpiler".

However, what we're talking about here is closer to TeX than cfront-to-c or even TypeScript-to-Javascript.


[ kuh m-pahyl ]


verb (used with object), com·piled, com·pil·ing.

to put together (documents, selections, or other materials) in one book or work.


Thank you for posting the non-computer definition of the word. I was aware of that before I posted.

A large fraction of the words I use in physics and math are not used the same way, within the field, as the generic dictionary definition.

I would say the definition linked is the computer science definition. Its just commonly the case that the compilation target is some final binary, but in this case it is an html document. A lot of the terminology in CS stems from analogous similar actions we perform in real life (I saw an article a week or two ago on here listing all terms used in an instance like this)

I hate it when people blindly post definitions like this without explanation, it comes off super aggressive and doesn't solve much.

CS history has a long history of similar pieces of software being not called compilers.

Normal CS jargon has "assemblers" and "linkers", both of which might appear to be compilers according to this dictionary definition.

CS history also includes things like TeX, which formats text for a variety of outputs, and was rarely called a compiler.

Web browsers often include a JIT compiler for Javascript, but their text formatting system isn't usually called a compiler.

I wrote a long comment, and immediately deleted it because I'm trying to avoid being a confrontational jerk.

I disagree with your assessment of "normal CS jargon". I'm wondering if you mean "normal jargon in the C/C++ community".

In my experience with compiler textbooks and computer science professors who specialize in compilers, compilers are any formal-language-to-formal-language translator. Yes, sometimes sub-types of compilers have specific names, but they are all compilers.

Is there one word for the subject material of the dragon book? I think there is, and I think that word is "compiler". Including source-to-source translators, including assemblers, including preprocessors, including linkers.

I'm glad you're not trying to be a confrontational jerk. I'm all for disagreeing politely.

The project in which I worked on a C++-to-C translator didn't call it a compiler, it called it a source-to-source translator. It was a CS project in a CS department funded by the NSF. I have read the Dragon Book, and would be surprised if the authors would consider an interpreter, assembler, or a linker to be a compiler.

So yeah. I don't expect you to agree with my opinion, but I do appreciate it that you're trying to avoid being confrontational jerk.

In my understanding, interpreters are generally not considered a member of this category, as they don't in general have formal languages as output. That is, I believe that a classically-defined compiler operates offline (there's no feedback from output to input during a given run of the compiler), and an interpreter generally operates online. Of course, to a sufficiently theoretical theorist, online is just a special case of offline, but of course to real software that is absolute nonsense.


As for the dragon book... okay, I got over my laziness and went and got my copy of the dragon book. I see no edition number, but this copy is "reprinted with corrections 1988". 33rd printing.

Page 1. "a compiler is a program that reads a program written in one language - the source language - and translates it into an equivalent program in another language - the target language".

Page 1. "Target languages are equally varied; a target language may be another programming language, or the machine language of any computer...."

Page 17. "Some compilers produce assembly code, that is passed to an assembler for further processing. Other compilers perform the job of the assembler" (emphasis mine: they explicitly state that assemblers are compilers)


Edited to add: Btw, I feel like I'm on the shakiest ground claiming that linkers are compilers, and probably the problem there is that my understanding of what qualifies as a linker is shakier than most of the rest of this subject.


In general, if I had bought a pickup truck, I'd be more likely to describe it as a "truck" than as a "vehicle". If I was seeking grant funding for a source-to-source translator, maybe it would be prudent to use specific language in my grant application (I understand that grant-writing is an art).

However, if someone else in a blog post about their hatchback called it a "tiny vehicle", and that blog post was posted to hacker news, it'd be weird to call them out on it. They're not wrong, their hatchback is indeed a vehicle!

Thanks for this. I did spend a lot of time pondering over whether I wanted to use the word "compiler" or "interpreter," but in the end it was my CS students who encouraged me to use the term that more people would recognize than the one that is technically more accurate.

This is my first time sharing one of my tutorials on HN so I am still feeling out where I will slip and where I can slide.

Thanks for pointing out that the other choice is perhaps technically more accurate -- I'm getting a lot of downvotes for pointing that out.

The Internet is often more like a bar brawl than a reasoned conversation.

The really gross part is... to my eye, the deeper into the thread we get, the more upvotable your comments get ("kind, thoughtful, substantive", to quote the guidelines), but the lighter gray they are. Although I've downvoted none, I can kinda see downvoting the top-level comment as being snarky, but that comment is solid black. Topsy turvy.

Thank you! I have the same amount of snark now as the top comment, i.e. none that I can tell. It would be nice to have a conversation about this topic that didn't involve me being downvoted.

I tried Rustlings, found it a wee bit too easy to do, but I'm not quite finished yet.

Looks great, thanks for creating this!

Thank you!

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact