Code Monkey home page Code Monkey logo

patterns's People

Contributors

ben-ph avatar cbreeden avatar dependabot[bot] avatar diwic avatar fade2black avatar imbolc avatar jhwgh1968 avatar joelmon avatar kriomant avatar lambda-fairy avatar llogiq avatar manishearth avatar marcoieni avatar max-heller avatar mokurin000 avatar nrc avatar otterpohl avatar partim avatar pedzed avatar pickfire avatar sassman avatar simonsan avatar stephendavidmarsh avatar stevegury avatar takashiidobe avatar tburko avatar tesuji avatar tkaitchuck avatar tmandry avatar wookietreiber avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

patterns's Issues

Use categories for `patterns` subfolder

It could make sense to structure/sort some of the patterns into a subfolder named after corresponding categories as mentioned in Design patterns (by Gamma, Helm, Johnson, Vlissides).

  • patterns/structural
  • patterns/behavioural
  • patterns/creational

Patterns not fitting into any of the categories could stay in patterns. When we merged all the older PRs we could start with that process to avoid merge conflicts.

Thoughts?

Collecting into a Result or Option

The .collect() instance for Result and Option is pretty useful, but is often overlooked by newcomers. I'd like to see an article that describes it.

Lazy allocation (in collection types)

If you create a collection type, avoid allocating until the first element is inserted. This has the nice property of being able to avoid allocation altogether if the collection stays empty (which, as it turns out, in the lifetime of the average program many do).

Add contribution guide to the repository

I think it could be nice to add a small contribution guide to the repository stating what to take care about

  • when making PRs
    • no force-pushing to keep commit history for easier review of changes
    • maybe even including a small PR template for this repo(?)
    • include new chapters into the SUMMARY.md for the book generation
    • allow edits of maintainers so we can actually work together with people on things
  • when writing new articles
    • including and explaining the template
    • encourage people to make PRs to raise code/content quality of articles
    • write idiomatic Rust in their examples that builds (for playground examples in mdbook)

tbc

Observer

Could we get an example of how to implement the Observer pattern, or an alternative solution if that pattern is not a good fit in Rust? Thanks.

anti pattern: #![deny(warnings)]

Through my work with clippy, I've probably had more exposure to the negative consequences than others, so I'm going to write up something in the next few days.

PhantomData and ZSTs as an anti-pattern

I'm a little wiped to write a full PR, and wanted to see if people agree here or not. We make extensive use of ZSTs in Diesel, which has sometimes led to the use of PhantomData, even if the type we're wrapping with it is also zero sized.

As time has gone on though, I've realized that any use of PhantomData is ultimately a sign that how you're going about implementing your hierarchy might be impossible to make object safe, which is a good thing to retain when you can. It's hard enough changing all of the fn foo<T: Foo>(foo: T) to fn foo(foo: &Foo), adding additional work on yourself is painful.

As such, I've ultimately come to the conclusion that PhantomData is a smell (maybe not an anti-pattern, but there's generally little value in distinguishing between the two)

Anti-Pattern: Intermediate `collect()`ion

I sometimes see this in code from iterative-minded folks, they iterate over something, collecting the result in a Vec. Then they iterate over the Vec, producing yet another Vec.

In most cases, the intermediate storage can be avoided. However, there are two exceptions:

  • When start()ing a number of threads one intends to join() later, the intermediate storage is needed to allow the threads to run concurrently.
  • Sometimes the intermediate storage can help the LLVM optimizer autovectorize some calculations that it would bail on were the iterations fused. In such cases, specific measurements should guide the implementation.

Idiom: Prefer Guard Clause over Nested Conditionals

Guard Clause

I'm taking my inspiration from Ruby for this one.

Avoid use of nested conditionals for flow of control. Prefer a guard clause when you can assert invalid data. A guard clause is a conditional statement at the top of a function that bails out as soon as it can. - Ruby Style Guide @ No Nested Conditionals

First I'll provide three examples of the wrong way to do it. These are overly nested and trying to follow the paths or guess with else belongs to what can be confusing at a glance. These examples are a simple file config parse

Wrong (A)

fn read_config1() -> Result<Config, Error> {
  let file = File::open("program.cfg");
  if let Ok(f) = file {
    let mut buf_reader = BufReader::new(f);
    let mut contents = String::new();

    if buf_reader.read_to_string(&mut contents).is_ok() {
      let mut data: Vec<u8> = vec![];

      for item in contents.
          split("\n").
          map(|s| s.to_string()).
          filter(|s| !s.is_empty()).
          collect::<Vec<String>>() {

        let num = item.parse::<u8>();

        if let Ok(conf) = num {
          data.push(conf);
        } else {
          return Err(Error::ConfigParseFail);
        }
      }

      Ok( Config { data: data } )
    } else {
      Err(Error::ConfigLoadFail)
    }
  } else {
    Err(Error::ConfigLoadFail)
  }
}

Wrong (B)

fn read_config2() -> Result<Config, Error> {
  let file = File::open("program.cfg");
  match file {
    Ok(f) => {
      let mut buf_reader = BufReader::new(f);
      let mut contents = String::new();

      match buf_reader.read_to_string(&mut contents) {
        Ok(_) => {
          let mut data: Vec<u8> = vec![];

          for item in contents.
              split("\n").
              map(|s| s.to_string()).
              filter(|s| !s.is_empty()).
              collect::<Vec<String>>() {

            let num = item.parse::<u8>();

            match num {
              Ok(conf) => data.push(conf),
              _ => { return Err(Error::ConfigParseFail); },
            }
          }

          Ok( Config { data: data } )
        },
        _ => { Err(Error::ConfigLoadFail) }
      }
    },
    _ => { Err(Error::ConfigLoadFail) }
  }
}

Wrong (C)

fn read_config3() -> Result<Config, Error> {
  let file = File::open("program.cfg");

  if let Ok(f) = file {
    let mut buf_reader = BufReader::new(f);
    let mut contents = String::new();

    if buf_reader.read_to_string(&mut contents).is_ok() {
      let mut data: Vec<u8> = vec![];

      for item in contents.
          split("\n").
          map(|s| s.to_string()).
          filter(|s| !s.is_empty()).
          collect::<Vec<String>>() {

        let num = item.parse::<u8>();

        if let Ok(conf) = num {
          data.push(conf);
        } else {
          return Err(Error::ConfigParseFail);
        }
      }

      return Ok( Config { data: data } );
    }
  }

  Err(Error::ConfigLoadFail)
}

And here is the correct usage of a Guard Clause which allows us to avoid deeply nested logic.

Correct

fn read_config4() -> Result<Config, Error> {
  let file = File::open("program.cfg");

  // Correct use of Guard Clause
  if let Err(_) = file { return Err(Error::ConfigLoadFail); }
  
  let f = file.unwrap();

  let mut buf_reader = BufReader::new(f);
  let mut contents = String::new();

  // Correct use of Guard Clause
  if let Err(_) = buf_reader.read_to_string(&mut contents) {
    return Err(Error::ConfigLoadFail);
  }
  
  let mut data: Vec<u8> = vec![];

  for item in contents.
      split("\n").
      map(|s| s.to_string()).
      filter(|s| !s.is_empty()).
      collect::<Vec<String>>() {

    let num = item.parse::<u8>();

    match num {
      Ok(conf) => data.push(conf),
      Err(_) => { return Err(Error::ConfigParseFail); }
    }
  }

  Ok( Config { data: data } )
}

If you'd like to test the examples above I have a working gist here: danielpclark/guard_clause_rfc.rs … you just need to create the config file with the contents of "1\n2\n3\n" .

Having your code implemented with guard clauses adds a huge benefit for code clarity and avoids having your conditionals carry your code too far and deep to the right.

Improvements for Guard Clause is currently in Pre-RFC as I would like to avoid using unwrap() after a Guard Clause.

The guard clause doesn't have to be strictly for an Error alternate return type. I believe it can apply for any time when there are two conditional paths and one of those paths is nothing but a return type.

`Small<T>` optimizations

I believe it may be useful to have some discussion about Small<T> optimizations; ie SmallVec, SmallHashMap, etc. This thought started from a users.rust-lang post.

What do you all think?

Constructor example rewrite

I'm used to use Self for the class type inside impl

from:

// A Rust vector, see liballoc/vec.rs
pub struct Vec<T> {
    buf: RawVec<T>,
    len: usize,
}

impl<T> Vec<T> {
    // Constructs a new, empty `Vec<T>`.
    // Note this is a static method - no self.
    // This constructor doesn't take any arguments, but some might in order to
    // properly initialise an object
    pub fn new() -> Vec<T> {
        // Create a new Vec with fields properly initialised.
        Vec {
            // Note that here we are calling RawVec's constructor.
            buf: RawVec::new(),
            len: 0,
        }
    }
}

to:

// A Rust vector, see liballoc/vec.rs
pub struct Vec<T> {
    buf: RawVec<T>,
    len: usize,
}

impl<T> Vec<T> {
    // Constructs a new, empty `Vec<T>`.
    // Note this is a static method - no self.
    // This constructor doesn't take any arguments, but some might in order to
    // properly initialise an object
    pub fn new() -> Self {
        // Create a new Vec with fields properly initialised.
        Self {
            // Note that here we are calling RawVec's constructor.
            buf: RawVec::new(),
            len: 0,
        }
    }
}

this makes it easier in case of renaming etc., what do you think?

Discussion about Visitor pattern

Maybe there is something I'm missing because the lack of Rust syntax/concepts understanding (I'm still learning, sorry) but the goal of the Visitor pattern is not only to "allow multiple different algorithms to be written over the same data". The main reason when visitor pattern is used is to allow dynamic double dispatch. Say you have a pair of abstract Visitor and Data and you don't know at compile time what the actual type of Data and Visitor is, you can just say data.accept(visitor) and let the magic happen.
Just look at https://en.wikipedia.org/wiki/Visitor_pattern#C.2B.2B_example
This is perfectly doable in any OO language.

Refering to the example, how can I have a
let d : Data = some of(Stmt, Name, Expr, ...);
let v : Visitor = some of(Interpreter, ...);
and say d.accept(v) without doing match on types anywhere.

Can this be done in Rust?

Maintainership/help proposal

Hi @lambda-fairy,

you stated here that this repo needs some help, how do you imagine helping with this repository?
MarcoIeni & me would like to help. We could start reviewing all past issues and merging/closing or give some feedback to all pending PRs.

Long-term, we would also like to turn this repo into a rust book that can be served with GitHub pages to the community.

Cheers,
Simonsan & MarcoIeni

rustdoc --test the examples

I have a local branch here that does this. Obviously some examples are not meant to run (e.g. partial copies from std), those can be marked with ignore.

Otherwise examples should run if it doesn't make them unreadable. I consider adding one or two lines of use declarations acceptable.

Thoughts?

Is the `Builder` pattern an anti-pattern in Rust due to the `Default` trait?

I claim that the builder pattern is more or less an anti-pattern and that you should use the Default trait instead. Here's why:

Let's say we have a struct:

pub struct Window {
    pub title: &'static str,
    pub width: usize,
    pub height: usize,
}
  1. The builder pattern produces way too much code on the creators side while not having a significant amount of code reduction on the users side. This is especially visible if the struct has more fields:

Creator:

// Builder pattern
pub struct WindowBuilder {
    __title: &'static str,
    __width: usize,
    __height: usize,
}

impl WindowBuilder {
    pub fn new() -> Self {
        Self {
            __title: "Default title",
            __width: 800,
            __title: 600,
        }
    }

    pub fn with_title(self, title: &'static str) -> Self {
        Self {
            __title: title,
            __width: self.width,
            __title: self.height,
        }
    }
    
    pub fn with_dimensions(self, width: usize, height: usize) -> Self {
        Self {
            __title: self.title,
            __width: width,
            __title: height,
        }
    }

    pub fn build(self) -> Window {
        Window {
            title: self.title,
            width: self.width,
            height: self.height,
        }
    }
}

// Default pattern: much less code!
impl Default for Window {
    fn default() -> Self {
        Self {
           title: "Default title",
           width: 800,
           height: 600,
        }
    }
}

See how much code we need to construct a window in comparison to the Default trait?

User:

// Default pattern
let window = Window {
     title: "Original title",
    .. Default::default()
};

// Builder pattern: not a significant reduction of usage code!
let window = WindowBuilder::new()
                     .with_title("Original title")
                     .build();
  1. The builder pattern doesn't protect against double-initialization:
let window = WindowBuilder::new()
                     .with_title("Original title")
                     .with_dimensions(800, 600)
                     .with_title("Oops, overwritten title!")
                     .build();

The Default trait protects against that, because you can't initialize the same field twice. The builder pattern simply overwrites the field and you don't get any warning.

  1. The Default trait eliminates the need for the SomethingBuilder struct. The SomethingBuilder struct is an intermediate struct that provides a certain kind of type safety so that you have to call SomethingBuilder.build() to construct a Something out of a SomethingBuilder. All of this is unnecessary if you use the Default trait - less code with essentially the same outcome. The SomethingBuilder has one appropriate use, in my opinion: When you need something to happen in the .build() function and it needs to happen once (although you can implement this in a default() function, too). For example, you need to tell the OS to create a window. This is where it's appropriate to use a builder. However, I've seen the builder pattern to be completely overused, which is why I'm writing this.

Often times when I'm having a struct with many fields that can have default values, it is easier to implement a default trait than to write ten or twenty builder functions. And that is why I claim that the builder pattern is actually an anti-pattern and that you should use the Default trait instead, wherever possible. It should at least be included somewhere in this repository.

Pattern: contain unsafety in small module

When dealing with unsafe code, the containing module has to ensure safety by upholding invariants. To make this feasible, the module should be as small as possible, only containing the unsafe functionality and the code necessary to uphold the guarantees, and embedding this in a larger module that can safely use the abstraction.

This keeps the code needed for an unsafe audit in manageable size.

More clear list of what lint warning are future/dependent safe to deny and which are not

Looks like we have to main source for lint attributes and warnings/errors:

In neither of these resources there's coverage for which of this these lint rules can get triggered depending on a compiler version, and which ones don't.

For example, unsafe-code cannot suddenly get triggered by a compiler update.

But, missing-docs, on the other hand, can get triggered whenever compiler supports docs for new language items.

I think not distinguishing these two types of lints is a common cause for denying/forbidding risky lints on the code.

Maybe there could be a Lint Group for these? Or some other way to tell them apart?

Discussion: Functions with many parameters

Requesting a design pattern for functions that take lots of parameters. For example this way:

fn foo(parameter_0: type, parameter_1: type, parameter_2: type, parameter_3: type, parameter_4: type, parameter_5: type, parameter_6: type) -> type {
    // function body
}

is a way that I think should be an anti-pattern because it's too wide. I prefer things to be less than 80 chars wide.

plug write! in format!?

The format! idiom notes:

It is possible to build up strings using the push and push_str methods on a mutable String, or using its + operator. However, it is often more convenient to use format!, especially where there is a mix of literal and non-literal strings.

Using write! on a String may not be quite as terse as the latter or as efficient as the former, but it's a pretty good (and generally more readable) alternative. It does require having std::fmt::Write in scope.

Fold pattern was confusing to me

The Fold pattern seemed confusing to me. The term "fold" in functional programming has a pretty clear definition (which includes a combining function), and it's not immediately clear from the example how it applies.

As used in the Rust compiler, it looks like their "Folders" are a general purpose map, reduce, or unfold operation on a tree, with the default operation of the base trait working as identity functions. Perhaps this is similar to Haskell's Traversable type class?

Anyways, I think it could be a little clearer. Perhaps in type theory or compiler circles using "Fold" in this context makes sense, but to me it seemed odd.

BTW, if you are curious, the term "fold" in a functional language sense was probably started by David Turner in the SASL language in the late 70's/early 80's.

Add markdown linter in CI

It would be nice to have something in CI that tells us if markdown is correct.
For example this markdown is not valid:

# section 1

### section 2

Or stuff like: avoid tabs or detect trailing whitespaces.

consume as valid alternative to mem-replace idiom?

Before finding the mem-replace idiom here, I implemented something like the following working alternative for a_to_b, which also doesn't (surprisingly to me at first) require MyEnum to be Copy.

Requires re-assignment on the calling side but avoids needing mem::replace or cloning the name. At where I am in learning rust, I'm probably not yet qualified, but would it be helpful to include this as an alternative and listing pros/cons or limitations?

Thanks for compiling these patterns!

#[derive(Debug, PartialEq)]
pub enum MyEnum {
    A { name: String, x: u8 },
    B { name: String }
}

pub fn a_to_b(e: MyEnum) -> MyEnum {
    if let MyEnum::A { name, x: 0 } = e {
        MyEnum::B { name }
    } else {
        e
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let mut e = MyEnum::A { name: "foo".to_owned(), x: 0 };

        e = a_to_b(e);
        assert_eq!(MyEnum::B { name: "foo".to_owned() }, e);

        e = a_to_b(e);
        assert_eq!(MyEnum::B { name: "foo".to_owned() }, e);
    }
}

Pattern for writing rustdoc examples without initialization

If you have a type Foo that has some complex initialization that you don't really want to inline into each example for every method on Foo, you can instead do:

/// bar is an important method on Foo. It does things.
/// #Example
/// ```
/// # fn call_bar(foo: &Foo) {
/// let value = foo.bar();
/// # }
/// ```
fn bar(&self) -> u32 {
//...
}

This avoids having to type several lines of logic to initialize foo in a concise way without having to jump to doing a "```ignore".

Umbrella: Repository Content (Scope)/ TODOs

Collection of design patterns and the corresponding issues if not contained in the repository already (in reference to Design patterns (by Gamma, Helm, Johnson, Vlissides)). Some patterns are probably not applicable to/realizable with Rust as they stem from OOP, but we'll sort that out on the way.

But in general I think it is also nice to have design patterns listed somewhere on a page that are not applicable to Rust and stated why and with an added workaround if any.

Checkmark = already existing in repository (link to file)
No checkmark = Link to corresponding issue
No checkmark and no link = Check if applicable for Rust

Coverage

Patterns

Creational Patterns

Structural Patterns

Behavioural Patterns

Still Uncategorized

Idioms

  • Trait to separate visibility of methods from visibility of data
  • Stability for extensibility
  • Leak amplification
    "Vec::drain sets the Vec's len to 0 prematurely so that mem::forgetting Drain "only" mem::forgets more stuff. instead of exposing uninitialized memory or having to update the len on every iteration"
  • Interior mutability - UnsafeCell, Cell, RefCell

Anti-patterns

Functional Programming

  • Currying (from #117)
  • Higher-order functions (from #117)
  • Collections (from #117)

Refactoring

  • Refactoring from unwrap to Result

General Unsorted

  • Public type aliases
  • Use conversion traits
  • Laziness: Use Iterators
  • Laziness: Take closures
  • Custom traits for input parameters
  • Extension traits

Notes

  • #35: I recently started collecting some API design patterns here. I'm not sure if these match what this repo is all about (or which ones you already cover), but I just wanted to say: Feel free to take anything you like from that post! :)
    The markdown source of that post is here and I hereby relicense the content as MPL2 (in addition to CC-BY) and allow you to use it in this repo.

From Reddit

Inspiration for more patterns

I recently started collecting some API design patterns here. I'm not sure if these match what this repo is all about (or which ones you already cover), but I just wanted to say: Feel free to take anything you like from that post! :)

  • Public type aliases
  • Use conversion traits
  • Laziness: Use Iterators
  • Laziness: Take closures
  • Custom traits for input parameters
  • Extension traits
  • Builder pattern
  • Session types

(The markdown source of that post is here and I hereby relicense the content as MPL2 (in addition to CC-BY) and allow you to use it in this repo.)

Rreturning a guard, c.f. `JoinGuard` and `MutexGuard`

Just an idea, would "Guard" count as a pattern?

Although sys::thread::scoped is unstable, sys::sync::MutexGuard is alive and well. Returning a guard object seems like an interesting way to make sure that an object can outlive past the curreny scope, by allowing the guard to be dropped and acting upon the referent (e.g. unlocking the Mutex).

A fairly terse description: Returning a proxy type with an inner reference to the original, that incorporates #[must_use] attribute and a probably reference to poison::Guard. Returning the guard can allow referents to outlive the calling scope and yet can still be acted upon when the scope changes.

(Apologies if this is already written up or doesn't count! Maybe it's too narrow if it's only used for implementing concurrency primitives?)

Use index in Container-Node relationship

Borrowing lifetimes always becomes tricky whenever there's a container-node relationship. We can always use indexes to reference the nodes or allow the nodes to reference each other.

New maintainer

Hi @nrc

It appears that there hasn't been much activity for this effort recently. I think this kind of information is quite valuable, and we should pass the torch to a new maintainer. I would gladly take responsibility for maintaining this project -- recently I was working on what I wanted to call the Rust Cookbook, and this seems to be right up the same ally. Also, I'm sure there are others who are perfectly capable and may be willing; @lfairy comes to mind.

Let me know!

Add examples for each pattern

In my opinion, it would be usueful to include at least one concrete example of each pattern at the end of the file. It shouldn't be anything complicated, just something that gives the "feel" of the practical usage.

Generic type constructors

I don't have a good name for this, but it's a pattern that Servo uses to sever linear dependencies between crates.

Before:
Crate A

pub struct FluxCapacitor;
impl FluxCapacitor {
    pub fn new() -> FluxCapacitor {
        FluxCapacitor
    }
}

Crate B

extern crate a;
pub fn instantiate_flux_capacitor() {
    let capacitor = a::FluxCapacitor::new();
    //...
}

Crate C

extern crate b;
fn start() {
    b::instantiate_flux_capacitor();
}

After:
Crate A_Shared

pub trait FluxCapacitorCreator {
    fn create() -> Self;
}

Crate A

extern crate a_shared;
pub struct FluxCapacitor;
impl FluxCapacitor {
    fn new() -> FluxCapacitor {
        FluxCapacitor
    }
}
impl FluxCapacitorCreator for FluxCapacitor {
    fn create() -> FluxCapacitor {
        FluxCapacitor::new()
    }
}

Crate B

extern crate a_shared;
pub fn instantiate_flux_capacitor<T: a_shared::FluxCapacitorCreator>() {
    let capacitor = T::create();
    //...
}

Crate C

extern crate a;
extern crate b;
fn start() {
    b::instantiate_flux_capacitor::<FluxCapacitor>();
}

Add github pages integration and mdbook for easy publishing and viewing

I've got a personal project which does something pretty similar to this. It's essentially a git repository full of markdown pages.

What I did is use something called mdbook which will take all the markdown files and turn them into structured html. I then added a travis.yml which will rebuild the html every time I commit some work and then automatically push to the ghpages branch.

I was wondering if you wanted to do something similar to make it easier for people to read and navigate all the useful documents here. It shouldn't require much effort, you just put all the *.md source files in a src directory and write a short SUMMARY.md file to tell mdbook where everything goes.

here's my SUMMARY.md:

# Summary

- [Using this Document](./using-the-wiki.md)
- [JavaScript](./JavaScript/javascript.md)
- [Docker](./docker-images.md)
- [Python](./Python/index.md)
    - [SqlAlchemy](./Python/sqlalchemy.md)
- [Basic Server Setup](./basic-server-setup.md)
- [Rust](./Rust/index.md)
    - [Using Rust outside Rust](./Rust/rust_interop.md)
    - [Emails and Templates](./Rust/emails_and_templates.md)
- [Testing In C](./testing_in_c.md)
- [LaTeX Snippets](./latex.md)

And the generated documents are viewable here.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.