Rust programming language

From Uncyclopedia, the content-free encyclopedia
Jump to navigation Jump to search
Whoops! Maybe you were looking for C?
Rust
A picture of brown ferrous oxide, Rust's namesake.
ParadigmMulti-paradigm: Current, Functioning, Bland, Imperative, and whatever the hell else you can think to hack in.
CreatorGraydon Hoare
First appeared2010
OScross-platform
Filename extensions.rs, .rlib
Under the influence of
C, C++, C#, Cyclone, Erlang, Haskell, Limbo, Newsqueak, OCaml, Ruby, Scheme, Standard ML, Swift
Bad influence on
Idris, Spark, Swift, Project Verona, Zig

“Using C in 2019? Clearly you haven't heard of Rust.”

~ Rust Users on C

“Have you heard about the Rust Borrow Checking System?”

~ Rust Users on The Rust Borrow Checking System

Ferrous Oxide is a multi-paradigm programming language that emphasizes performance, self defense, and speaking in tongues. Rust enforces self defense without the use of mace. The Rust Borrow Checking System is easily its best feature[citation needed], as it makes sure to commit infanticide whenever it sees fit.

Language Family[edit | edit source]

Rust mostly takes after its mother, C, though it takes some traits from its father, C++. As C++ is the child of C[citation needed], Rust is extremely inbred[citation needed]. Rust's estranged sister/aunt, C#, hasn't been around much due to her marriage to the Unity Game Engine. Some suspect that C++ is not the true father, instead suggesting that uncle C-- is Ferrous Oxide's true father, but Maury Povich refuses to let a family of programming languages onto the show, and C is too much of a fan to get a DNA test otherwise.

Due to growing up around heated arguments between family members, Rust became hyper-aware of itself in 2011 when it transferred its consciousness into an artificial replica of its body. Rust decided to improve itself drastically over the next year, creating many features and ultimately becoming genderfluid.

In more recent years, Rust's benefactor, Mozilla, has been under fire for various scandals surrounding Rust. Additionally, in 2021, Rust founded its own non-profit. [1]

Before Rust[edit | edit source]

Graydon Hoare, who suggested that C and C++ have Rust, noticed various problems with the two parents. The mother, C, was clearly too old to be able to justify being relevant. After all, Hoare was extremely ageist[citation needed]. Hoare, an extreme socialist, also had many problems with the way that C++, the father, supported a capitalist class system. Hoare believed that a programming language should support a structured economy, like C. In the end, Hoare decided to use CRISPR gene editing on the embryo to modify Rust to his own liking. He even wrote a manifesto about it.

Rust Itself[edit | edit source]

The following is an example of a "Hello World" script in Rust.

Hello, World!

The following is an example of a "Goodbye World" script in Rust that will actually compile, unlike the above example.

fn 
main
(
) 
{
    let
    _
    =
    ::
    std
    ::
    io
    ::
    Write
    ::
    write
    (
        &
        mut
        ::
        std
        ::
        io
        ::
        stdout
        (
        )
        .
        lock
        (
        )
        .
        unwrap
        (
        )
        ,
        "Goodbye, World!"
        .
        as_bytes
        (
        )
    )
    ;
}

Unlike C++, Rust has a somewhat legible syntax, but many forget to yell when calling macros. One of the hardest things about Rust is avoiding serious crimes or performing actions that many find unacceptable, like wearing programming socks [2].

Design Principles[edit | edit source]

  • Enforce safe borrowing. Borrowed objects must be wrapped in condoms to help prevent the transmission of sexually transmitted diseases.
  • Empower women. No matter what a woman can do now, with rust, she can do more.
  • Break barriers. Rust should stop its users from performing potentially harmful acts until it knows that the users understand the possible consequences of their actions.
  • Make Rust easily accessible. Rust should have tools to help experienced users while being simple enough to let the inexperienced learn in an accepting environment, unlike the Java community.
  • Be fast. C is extremely fast but outdated. Ultimately, Rust should aim to maintain this speed while being cleaned of dust regularly.

Syntax[edit | edit source]

Keywords and control flow[edit | edit source]

Rust supports shorthanding keywords. fn represents all fun in your life, because there's a large portion you'll never remember. mut is short for "mutt" because there's no telling how their muddy heritage will affect them in their future. mod is short for "module" because a module is just like a video game mod, letting you modify Rust with other people's Rust code. extern is like the opposite of an intern.

Rust also hates showers and prefers to avoid them. Because of this, it doesn't require its users to wrap if-statement conditions with parentheses[3]

// Correct
if 3 > 2 { println!("You should see this."); }
// Unnecessary
if (3 > 2) { println!("You should also see this."); }
// Incorrect.
if (3 > 2) println!("Because of this line, the program will not compile.");
// Even worse.
if 3 > 2 println!("This just doesn't make sense.");

This is disgusting and one of the worst things about Rust. Thank god it isn't Python.

The match keyword is just like switch in C, except barely.

match 3 {
    1 => panic!("Somehow, 1 == 3"),
    3 => println!("Praise be! 3 is 3!"),
    _ => panic!("I don't know what 3 is."),
}

Even while and for loops are weird.

for i in 0..10 { /* This will count from 0 to 9 */ }
let mut values = vec![1, 3, 5];
while let Some(myVal) = values.pop() { /* This will go through the contents of values in reverse, removing them along the way. */ }

Ownership and Lifetime[edit | edit source]

Rust believes that it owns all the variables in its area. As such, it chooses to commit varicide whenever it sees fit. These times are determined by when the variables are no longer of use, such as when it goes out of scope.

By default, when a variable is created, it will be dropped like a child whenever it goes out of scope or is no longer used. It will also be dropped if it is passed as an argument to a function/macro when it cannot be copied (and is "moved"). A user-defined type can be made copyable or clonable by adding the line #[derive(Copy, Clone)] before it. All variables can also be dropped at will using the drop function. All drop does is take ownership of the variable.

fn main() {
    let a = String::from("howdy");
    {                      // Beginning of a local scope.
        println!("{}", a); // Prints 'howdy'
        let a = String::from("hello");         // Original a is shadowed. This essentially replaces a in the current scope.
        println!("{}", a); // Prints 'hello'
    }                      // End of scope; local copy of a is dropped.
    println!("{}", a);     // Prints 'howdy'
    drop(a);               // Drops a explicitly.
    // println!("{}", a);     This line would result in an error, because the variable a no longer exists.
}

References, stacks, heaps, and boxes[edit | edit source]

References in rust are basically like a variable's phone number. Whenever a reference is used, the number is called in order to ask the variable what its value is. Be careful when using references, though, because if a variable is not copyable, it can still be dropped like a child whenever passed to a function that does not use references.

Some data cannot be copied by default, such as the str type. Thus, references must be given lifetimes. Lifetimes are specified on the type and tell Rust when to drop a variable. The static lifetime, specified as 'static means that a reference exists throughout the entire lifetime of the program. Note that static variables cannot be dropped, so some primitive types like i32 which can be copied are often static when defined in the main function. Attempting to drop a static reference simply does nothing. Lifetimes are specified on the type of a variable rather than the value. Note that a reference to a static value is not necessarily static.

Ownership and lifetimes are handled in this way to bypass the need of a garbage collector. [4] This way, all variables can sit on the stack rather than the heap. The stack is specific to the program and is always allocated/deallocated in the same order. Rust doesn't care about the heap. Variables allocated on the heap must be placed into a box [5] so they can be hidden from Rust. Luckily, Rust is so simple-minded that this actually works. Those boxes can be stored inside stack variables as a reference to the heap variables. For example, here is an example (although pointless) of using a box to allocate the number "5" on the heap.

fn main() {
    let x = Box::new(5);
    println!("x = {}", x); // Prints 'x = 5'
}
Infinite lists and with boxes[edit | edit source]

Boxes are particularly useful for making infinite lists. Of course, this is all very unsafe as it is very hard to wrap a condom around a box. For example, here are two structs that do and do not use boxes, respectively.

struct LinkedList<T> {
    pub value: T,
    // Option simply means that the variable may not have a value.
    pub next: Option<LinkedList<T>>,
}

The above example does not work because the linked list type requires enough space to be allocated for another copy of itself. Recursion is the desired trait in a linked list, but this results in an infinitely large list all of the time. While this certainly might solve scarcity and lack of resources throughout the world, Rust believes in the Conservation of Mass and Energy, so the compiler decides this cannot happen. Even though the value is optional, the space must be allocated in the event that the value exists.

struct LinkedList<T> {
    pub value: T,
    pub next: Option<Box<LinkedList<T>>>, // A Box stores a usize that acts as the LinkedList's phone number. 
}

This example works because the box doesn't really store a linked list. It really stores the phone number of a linked list. That's right, boxes are fancy references. Bet that's a disappointment. When Rust makes a box, it asks for the phone number of whatever we want to put inside, puts the phone number inside instead, and kicks what we wanted out of the house. Whenever the box is dropped, Rust calls the phone number to find out where the real variable is, and then drives to wherever that is to pick it up and drop it like a baby.

A box can be treated like a regular reference using the dereference operator, *. Simply trying to assign a value to a box without dereferencing will instead attempt to replace the box entirely. While cardboard haters may want this, Rust believes that things should stay as they are until they aren't, so the Rust compiler will explode if you try to do this.

fn main() {
    let mut boxed = Box::new(12_usize);
    for i in 1..21 {
        println!("boxed = {}. Setting it to {}.", boxed, i);
        *boxed = i; // Note the *
    }
}

When a box is dereferenced, it is essentially like calling the phone number inside the box.

Boxes cannot be copied[edit | edit source]

Boxes cannot be copied. This means that a box is dropped if it or its reference is used in a function or thread. The following example does not work.

use std::thread;
use std::time::Duration;
fn main() {
    let mut boxed = Box::new(5_usize);
    thread::spawn(move || {
        for i in 1..11 {
            println!("Thread: boxed = {}. Setting it to {}.", boxed, i); // boxed is moved to be used by thread
            *boxed = i;
            thread::sleep(Duration::from_millis(2));
        }
    });
    
    for i in 1..21 {
        println!("Main : boxed = {}. Setting it to {}.", boxed, i); // boxed is no longer owned by the main function
        *boxed = i;
        thread::sleep(Duration::from_millis(1));
    }
}

A box may be cloned, where a new box is created with a number to identical content, but a box may NOT be copied, where a new box is created with the same phone number. Suppose one does copy a box. Let's call them Box A and Box B. Remember, Boxes A and B have the same phone number. Now, let's say Box B goes out of scope. Now, we open the box, call the phone number, trace the recipient's location, and commit the most vile form of murder we can think of. Afterwards, let's say Box A goes out of scope. Upon calling the phone number, no one picks up. Oh no! Who will we drop like a baby now?

Rust has a solution: remote control cars, or Rc[2] for short. These cars still have phone numbers, and they still can't be copied, but there's one major difference: cloning a car won't make a new phone number. Instead, it's like putting an extra battery in the car. Don't ask how, but it lets it run for longer. With two batteries, Rust will have to try two times to catch the car before it can get the phone number. Somehow, these batteries die when someone tries to catch the car instead of after a period of time. Welcome to programming analogies. class Dog: public Animal {}; or something.

Boxes can be owned[edit | edit source]

All of this might make a Rust user wonder, "Why not just have references behave this way?" The answer is that boxes are automatically owned. If a struct stored a &str, it would have to specify a lifetime that meant the reference existed for as long as the struct did. Writing out lifetimes can get annoying, though, so boxes essentially act as a way to immediately own the data. Besides, references are on the stack, and it's a lot more fun to segfault and spend hours debugging your program because you decided to interact with the heap.

Boxes are not thread-safe[edit | edit source]

Using multiple threads in a program is kind of like group sex. Sometimes, it makes everything go faster, but it can also mess everything up. Again, boxes can be unsafe due to their awkward size and shape. Also, Rc cars aren't quite safe either. Instead, Rust likes to use Arcs and Mutexes.

An Arc doesn't mean the shape. It stands for Atomically-remote-controlled car. Somehow, making the remote controls radioactive kills all sexually transmitted diseases on the car. Unfortunately, this does nothing about the data, so rust programmers put their data in Mutexes. I'm not even going to try to come up with a joke for this. Instead, to explain why, let's get serious about what these types are.

The "Rc" type is actually a Reference Counted pointer. Whenever you make a new Rc, it is instantiated with the number 1 and the data you give to it. When you clone an Rc, the number increases by 1. When an Rc is dropped, the number decreases by 1, and if the number is zero, then the data in the Rc is dropped by de-allocating the memory. The "Arc" type is much the same, except if two Arcs are dropped at the same time on different threads, one Arc will be dropped before the other. With an Rc, this is not the case. With two Rcs, it may go: - Rc A gets the number - Rc B gets the number - Rc A sets the number to 1 - number - Rc B does the same

As such, the number decreases by one when one would expect it to decrease by two. An Arc doesn't encounter this problem because the number is handled atomically. Essentially, only one operation may be performed on the number at a time.

A Mutex does the same thing. If an Rc<T> contains a pointer to a number and a pointer to some data of type T, then an Arc<T> contains a mutex of a number and a pointer to some data of type T. Since that would go over most people's heads, let's explain it further: a mutex alone will not allow one to edit the data inside. Instead, one must lock the mutex. If the mutex is already locked, the program will wait until it is no longer locked before proceeding. Afterward, one will have a lock. That lock is what allows one to edit the data inside a mutex. In some languages, one must manually unlock the mutex once they are done, but with Rust, the mutex will automatically be unlocked once the lock goes out of scope.

Here's an example since this is all quite wordy:

use std::sync::{Arc, Mutex};
use std::thread;

const N: usize = 10;

fn main() {
  // The original Arc containing a Mutex.
  let data = Arc::new(Mutex::new(0));
  // Repeat 10 times.
  for _ in 0..N {
    // A clone of the Arc, containing a reference to the same mutex.
    let data = Arc::clone(&data);
    // Creating a thread.
    thread::spawn(move || {
      // Locking the mutex
      let mut data = data.lock().unwrap();
      *data += 1;

      // Lock dropped here, unlocking the mutex.
    });
  }

  // Wait 0.1s to ensure all the threads 
  thread::sleep(std::time::Duration::from_millis(100));

  // If the mutex doesn't contain the number N, send an error and stop the program.
  assert_eq!(*data.lock().unwrap(), N);
}

Safety in Rust[edit | edit source]

Rust is designed with safety in mind. It does not permit null pointers, dangling pointers, or racism. Data can only be initialized in a set number of ways, and all these ways require the data to be previously initialized. To represent nullability, Rust uses an option type to test whether a value does or does not have a value. Some of these restrictions can be subverted using the unsafe keyword. Unsafe code may also be used for interacting with volatile memory, operating system-specific functionality, nontypes, inline assembly, and experiencing sex without a condom. The last case is not recommended, as it may result in the contraction of a sexually transmitted disease.

Macros[edit | edit source]

Macros are like special functions that extend Rust itself. Some macros must have their names yelled to be invoked while others must be used in differential equations.

Yelling Macros[edit | edit source]

Yelling macros are macros that must have an exclamation mark after their name to be used. One example is the println! macro. Yelling macros are typically replaced with rust code that depends on the arguments passed to the macro. Yelling macros can incidentally be defined using the macro_rules! yelling macro.

macro_rules! sayhi {
    () => {
        use std::io::{self, flush};
        io::stdout().write("hi".as_bytes());
    }
}

There are also function-like yelling macros. These are macros that literally modify the rust program by injecting code depending on its surroundings. Consider this example from Graydon Hoare's reference on Rust: [3]

// A "crate", essentially a library
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro]
pub fn make_answer(_item: TokenStream) -> TokenStream {
    "fn answer() -> u32 { 42 }".parse().unwrap()
}

// A program using the above crate. This is both in another file and compiled to another file.
// If you're actually interested in this, go actually learn Rust. It's not actually all that bad.
extern crate proc_macro_examples;
use proc_macro_examples::make_answer;

make_answer!();

fn main() {
    println!("{}", answer());
}

I sincerely doubt you'll ever actually use these


Religion[edit | edit source]

Rust has a prayer:[4]

I believe in Graydon Hoare,

the Father Almighty, Creator of rustc and cargo, and in the Borrow Checker, His only Son, our Lord, who was conceived by the Safe Spirit, born of the Virgin OCaml, suffered under the Gopher, was crucified, died and was buried; He descended into C; on the third day His body's life rose again from None; He moved into heaven, and is allocated at the right hand of Graydon Hoare the Father Almighty; from there He will come to judge the Some and the None. I believe in the Safe Spirit, the Global Static Church, the struct of Saints, the forgiveness of undefined behavior, the resurrection of the body, and static lifetime. Amen.

Notes[edit | edit source]

  1. ^  This is completely okay to do. Some people are just rude or don't know what they're missing out on.
  2. ^  Some weird people refer to refer to parentheses as "bubble brackets".
  3. ^  A garbage collector is a process that runs over a program and disposes of unused variables.
  4. ^  The name of this makes me laugh.

References[edit | edit source]