
Rust-Doom: A Doom renderer in Rust, with no unsafe code - micaeloliveira
https://github.com/cristicbz/rust-doom?updated
======
kibwen
In related news, note that Rust 1.4 was just released yesterday:
[http://blog.rust-lang.org/2015/10/29/Rust-1.4.html](http://blog.rust-
lang.org/2015/10/29/Rust-1.4.html) , which I figure is worth mentioning here
as the announcement thread didn't get much traction on HN.

~~~
eridius
Definitely worth mentioning! I completely missed this release. A bit sad too,
since it's the first release (since Rust started listing contributors) that I
didn't contribute to :'(

~~~
kibwen
There's still time to get back on the horse for Rust 1.6. :)

~~~
eridius
I just need to find the time!

------
estefan
What's the status of Rust these days? I can see it's hit 1.x, but in practice
is it ready for production use? How comprehensive is the standard library,
dependency management, etc.?

From a brief glance through the examples it looks pretty functional... is it
basically a systems-ish scala?

~~~
nbaksalyar
It's pretty stable at this point (1.x means that no backwards compatibility
will be lost as in the past), and it's already used in production (e.g.
Skylight [0] is written in Rust, as far as I know, and don't forget about
Servo).

Dependency management with Cargo is hands down one of the best out there, it
just works. The standard library continues to expand, but there are also many
other external libraries you can find on crates.io.

> it looks pretty functional... is it basically a systems-ish scala?

I think it's better to compare Rust to ML languages family (OCaml, F#, and so
on), as it was clearly influenced by it. It has many features you can find in
ML languages - pattern matching, ADTs (algebraic types that are enums in
Rust), and many other similarities.

Overall, the language feels very robust now, and I enjoy it much - it's a very
decent replacement for C++, basically "C/C++ done right".

[0] [https://www.skylight.io/](https://www.skylight.io/)

~~~
lmm
Scala was also heavily ML influenced and is sometimes considered part of that
family, so I think it's fair to relate the two.

~~~
kibwen
Rust and Scala may be cousins due to their ML influence, but Rust itself isn't
particularly influenced by Scala. In contrast, there are quite a few design
decisions in Rust that were lifted directly from OCaml. Calling Rust "C++20 +
OCaml" would be a decent categorical starting point.

(Caveat: the lead designer of Rust's type system, Niko Matsakis, has done a
fair bit of work with Scala, so there may be subtle influences.)

~~~
justthistime_
> Rust itself isn't particularly influenced by Scala

Agree! Sadly, they didn't use all the lessons Scala could offer them when
designing their own language. :-(

Painful to watch as they introduce stuff where Scala developers already know
that it's completely broken.

~~~
steveklabnik
Would you mind expanding on what these things are?

~~~
lmm
The cascade of efforts at error handling, which I think at one point involved
a macro and a magic method name, rather than getting on with higher-kinded
types to allow them to do it right.

Allowing "return".

Mandating braces for functions and control flow constructs.

Rust iteration, which is both more limited and less safe (laziness) than the
scala/ruby style of passing a closure.

~~~
kibwen

      > The cascade of efforts at error handling
    

You must be referring to ancient Rust with its condition system and such.
Modern Rust code just uses Result types.

    
    
      > rather than getting on with higher-kinded types to allow 
      > them to do it right
    

Er, no, you don't need HKTs to "do it right", you'd just need HKTs to do it
generically. Rust's error handling works fine for specific types; you can even
write macros to emulate do-notation (and people have).

    
    
      > Allowing "return"
    

Welcome to the realities of imperative programming. :) Unlike Scala, Rust does
not aspire to functional godhood.

    
    
      > Mandating braces for functions and control flow constructs
    

Scope in Rust is very, very important for expressing when references go out of
scope and when resources are freed. Leaving scope implicit would be massively
frustrating.

    
    
      > the scala/ruby style of passing a closure
    

Rust _had_ internal iterators for years, and the entire `for` construct was
based around them. They were removed because they were found wanting.

As I've mentioned in a sibling comment, the lessons that Scala may have
learned in its life do not necessarily apply to Rust. They are very, very
different languages.

~~~
drewhk
I am a Scala developer but I agree with your points. The only thing that just
simply drives me mad in Rust is mandatory semicolons. Once you are used to be
able to omit them then it gets really annoying to go back using them.

~~~
kibwen
I actually agree with this one. :) The usual argument in their favor is that
having to explicitly return `()` all the time would get tired in low-level
C-alike functions that mostly operate via side effects, but I'm not
particularly swayed that we should be optimizing for that use case (but then
again I'm also of the opinion that bitwise operators don't deserve their own
symbols, so I may already be an enemy of this crowd :P ).

------
polskibus
Can anyone tell how performant this code is vs original C code? How much do we
lose (if anything) by using Rust in comparison to C?

~~~
fsiefken
In general Rust is fast but slower then C: "Rust is safe indeed but,
unfortunately, far from fast. By the moment of writing this article, it is
comparable to Java, Go, and Haskell regarding performance"
[http://www.viva64.com/en/b/0324/](http://www.viva64.com/en/b/0324/)

~~~
yokohummer7
Please not this again. The article you mentioned is incorrect in many places,
and was heavily criticized in various communities.[1][2] It doesn't qualify as
a valid criticism. It is rather a badly written static analyzer promotion.

Also, microbenchmarks are usually not very good at representing the real world
characteristics. But then again, please look at the current version of the
linked benchmark.[3] Rust now positions itself in the second place, thanks to
the recent improvements given to the Rust programs used in the benchmarks. I
believe Rust isn't as fast as highly optimized C, but I think it is safe to
say that Rust is just as fast as C++, and both Rust and C++ are much faster
than GC'ed languages such as Java, Haskell, and Go.

Edit: I would even say that if Rust's performance is comparable to GC'ed
languages, there's no point in using Rust in the first place. Rust is paying a
lot of complexity to achieve memory safety without relying on garbage
collection.

[1]
[https://news.ycombinator.com/item?id=9531822](https://news.ycombinator.com/item?id=9531822)

[2]
[https://www.reddit.com/r/cpp/comments/35pn6h/criticizing_the...](https://www.reddit.com/r/cpp/comments/35pn6h/criticizing_the_rust_language_and_why_cc_will/cr6o9tz)

[3] [http://benchmarksgame.alioth.debian.org/u64q/which-
programs-...](http://benchmarksgame.alioth.debian.org/u64q/which-programs-are-
fastest.html)

~~~
johncolanduoni
> Edit: I would even say that if Rust's performance is comparable to GC'ed
> languages, there's no point in using Rust in the first place. Rust is paying
> a lot of complexity to achieve memory safety without relying on garbage
> collection.

Rust has a lot of nice safety features not related to memory management that
I'd love to see even in a language with GC. On top of the obvious lack of data
races, linear types and borrowing are great for ensuring other kinds of sanity
like preventing you from mutating a collection while you iterate over it.

~~~
Gankro
Technically Rust doesn't have proper linear typing, only affine typing.
Destructors give you "basically" linear typing, but there's ways to bypass
destructors both explicitly and accidentally (though if memory safety isn't at
stake, this isn't a worth worrying about IMO):

[https://doc.rust-lang.org/nomicon/leaking.html](https://doc.rust-
lang.org/nomicon/leaking.html)

------
callumlocke
Can someone tell me what it means to have "no unsafe code"? (I'm a JavaScript
developer with very little experience of languages like Rust and C++.)

~~~
nbaksalyar
To understand unsafe code you need to understand what's safe code and pointers
first.

Basically, safe code is automatically managed to get rid of memory leaks [0],
dangling pointers [1], null pointer dereferencing [2], race conditions [3],
and many other memory management bugs.

You don't encounter any of these in JavaScript because it's a managed
language, meaning there's a garbage collector [4] that looks after all your
memory allocations.

Contrary to the managed languages, C & C++ are unsafe and "native" (meaning
that they're very close to the hardware level) - it's a wild land where you
manage memory manually yourself. If you miss a single deallocation, you're
left with a memory leak. If you deallocate a memory region twice, you have a
double free situation [5]. So you have to be very cautious when writing code
in C & C++. There are many techniques to make it easier (e.g. smart pointers
[6]), but not all developers use them.

Rust takes the middle ground: it combines safety with unsafety by using a
know-how affine type system with a borrow checker, which allows
values/variables to have only one owner. This system has properties of both
managed and unmanaged code. "Unsafe" code in the context of Rust means that
you consciously turn off the borrow checker, leaving on your own and managing
memory deallocations manually, as in C. That makes it possible to interface
your Rust code with the native code, at the cost of making you prone to all
errors and bugs that are listed above. So it's a good thing to minimize usage
of unsafe code, to allow the Rust compiler to check your code for safety.

[0]
[https://en.wikipedia.org/wiki/Memory_leak](https://en.wikipedia.org/wiki/Memory_leak)

[1]
[https://en.wikipedia.org/wiki/Dangling_pointer](https://en.wikipedia.org/wiki/Dangling_pointer)

[2]
[https://en.wikipedia.org/wiki/Null_pointer#Dereferencing](https://en.wikipedia.org/wiki/Null_pointer#Dereferencing)

[3]
[https://en.wikipedia.org/wiki/Race_condition](https://en.wikipedia.org/wiki/Race_condition)

[4]
[https://en.wikipedia.org/wiki/Garbage_collection_(computer_s...](https://en.wikipedia.org/wiki/Garbage_collection_\(computer_science\))

[5] [http://stackoverflow.com/questions/21057393/what-does-
double...](http://stackoverflow.com/questions/21057393/what-does-double-free-
mean)

[6]
[https://en.wikipedia.org/wiki/Smart_pointer](https://en.wikipedia.org/wiki/Smart_pointer)

~~~
easytiger
> . So you have to be very cautious when writing code in C & C++. There are
> many techniques to make it easier (e.g. smart pointers [6]), but not all
> developers use them.

Not everyone has security as a requirement. Some people jsut want to write
something that is both fast, predicable. Most banks don't make any security
demands of internal applications because they are not accessible to the
internet. At which point safety is just a way to slow you do.

~~~
smtddr
_> >Most banks don't make any security demands of internal applications
because they are not accessible to the internet. At which point safety is just
a way to slow you do._

This is a bad way of doing things. That means as soon as someone finds a way
to get inside the network, the bank is wrecked. You need to look at security
from the point of assuming the attacker somehow got inside because it'll
happen one day.

[http://digg.com/2015/ashley-madison-hack](http://digg.com/2015/ashley-
madison-hack)

 _" "" MOTHERBOARD: How did you hack Avid Life Media? Was it hard?

The Impact Team: We worked hard to make fully undetectable attack, then got in
and found nothing to bypass.

MOTHERBOARD: What was their security like?

The Impact Team: Bad. Nobody was watching. No security. Only thing was
segmented network. You could use Pass1234 from the internet to VPN to root on
all servers. """_

------
ChuckMcM
This is awesome. Now to go dig up my WAD files. To add to the list of
languages where bringing up Doom was helpful in vetting the language, Java.
Patrick Naughton built a BSP rendering platform in Oak using the Doom WAD
files and found a number of places where the JVM needed tweaks.

------
Animats
Nice. Someone previously ported Doom to Rust, but they kept the general form
of the C data structures and had to use lots of unsafe code.

~~~
cristicbz
It's the same project, I just been keeping it up to date and removed all the
unsafe code. It never _needed_ unsafe code, but it was my first Rust project
and I didn't know what the hell I was doing---it's now much cleaner, safer and
faster than the incarnation you saw last year :)

~~~
krisdol
That's awesome! I'm just learning rust and I'm really enjoying it, though it
was more challenging getting into the right mindset after working on GCed
languages for most of the last 4-5 years. Certainly wrestled with the
ownership system for a while but it's all making a lot more sense now, and I'd
much rather have the compiler telling me about these problems than incorrectly
dereferencing memory in C code.

How long have you worked on only this project?

~~~
cristicbz
> How long have you worked on only this project?

It's hard to quantify how much time _this_ project took, since when I started
a year ago I knew nothing about Doom or Rust. If I started writing it now from
scratch, I could probably hammer it out in a working week. A better programmer
could probably do it in a weekend. It's neither very big nor very hard.

But that's not how programming works, is it? In fairness, you'd need to count
some of the time I spent working on a lot of other random Rust side projects
and reading blog posts over the last year, while only spending a couple of
hours ever other week or so on rust-doom.

> Certainly wrestled with the ownership system for a while

I think my background in modern C++ helped me a lot with this, since the "one
owner per thing, move semantics" model is how you're supposed to write C++
too.

That said, figuring out the cleanest design is not easy and I'm still
wrestling with it today. The code was an absolute mess last year and now it's
better, but still needs plenty of work: just yesterday I decoupled WAD parsing
from the rest of the code properly ([https://github.com/cristicbz/rust-
doom/pull/53](https://github.com/cristicbz/rust-doom/pull/53)).

I'm still learning a lot a year after dedicating all my free-time programming
to Rust.

------
somesaba
This is great. I've wanted to start a project in Rust but I'm hesitant since I
haven't found any profiling tools akin to VisualVM. I'd feel a bit blind
writing multi-threaded code where I can't see what's going on. What do people
use to sanity check this sort of thing?

~~~
steveklabnik
One nice aspect is that Rust gives you many kinds of threading errors at
compile time, so that helps. :)

Any profiling tool that works for C or C++ should work just fine for Rust. For
example, people often use perf for performance work.

------
cjdrake
What a great project! The author should do a talk about his experiences. I
searched for something like this on YouTube, and only found this:
[https://www.youtube.com/watch?v=0_-TRvbo54Y](https://www.youtube.com/watch?v=0_-TRvbo54Y).

~~~
cristicbz
Thanks! Uh, I'm not good at writing/saying things that are not checked by a
compiler. But I'll try to write a blogpost about it.

------
deevus
I love stuff like this. I and some other students made a Quake 3 engine in C#
using OpenTK (OpenGL 4) in about 6 weeks. None of us had ever done real game
development before. It was a great learning experience and overall we're
pretty happy with what we accomplished.

It's still very preliminary and not optimised, but I might tinker away at it
now that my degree is all but done. At this point it can load and render any
Q3 (or OpenArena) BSP map, but most all other things are missing.

[https://github.com/aggregates/tk-quake](https://github.com/aggregates/tk-
quake)

------
loaaa
Rust will push C++ becoming much better!

------
kellros
I have a sinking feeling: [https://github.com/cristicbz/rust-
doom/blob/master/src/game/...](https://github.com/cristicbz/rust-
doom/blob/master/src/game/camera.rs#L33)

~~~
acqq
Can you please elaborate?

~~~
pauljz
It's a joke - the comment references a song [0] from the movie Titanic, which
prominently features a sinking ship.

[0]
[https://en.wikipedia.org/wiki/My_Heart_Will_Go_On](https://en.wikipedia.org/wiki/My_Heart_Will_Go_On)

