Encapsulation in Rust and Python
Tags: rust, python, programming, beginners
Published: 2024-04-05 10:00:48

###Disclaimer
_I am sure that there are inaccuracies, and maybe even mistakes in this text. I am always happy to receive objective criticism in an acceptable form._

#Introduction

Encapsulation is a fundamental concept in object-oriented programming that allows for the bundling of data with the methods that operate on that data. Rust and Python both support encapsulation, which means you can control the access to the attributes and methods of a class or a trait using public, private, and protected modifiers. This concept is implemented in different ways in Rust and Python due to languages design and paradigms. In Rust, we use `pub` to make methods and structs accessible outside their module because default they are private. In Python, we use double underscores `__` to public by default attributes and methods private. Both languages provide mechanisms to control access to the data, ensuring encapsulation.

#Encapsulation in Rust
In Rust, encapsulation is achieved through the use of `struct` and `impl` blocks. A `struct` is used to define a data type with named fields, and an `impl` block is used to define methods associated with the struct. In Rust, encapsulation is achieved through the use of `pub` and `pub(crate)` (protected) modifiers. Here's a simple example:
src/employee.rs
```Rust
// Define a struct with field (it is private by default)
pub struct Account {
    // Private fields
    balance: f64,
}

impl Account {
    // Public method to create a new Account
    pub fn new(initial_balance: f64) -> Account {
        Account {
            balance: initial_balance,
        }
    }

    // Public method to get the balance
    pub fn get_balance(&self) -> f64 {
        self.balance
    }

    // Public method to deposit money
    pub fn deposit(&mut self, amount: f64) {
        self.balance += amount;
    }

    // Private method to apply fees
    fn apply_fees(&mut self) {
        const FEE: f64 = 2.5;
        self.balance -= FEE;
    }
}
```
src/main.rs
```Rust
mod employee;
use employee::Account;

fn main() {
    let mut account = Account::new(100.0);
    account.deposit(50.0);
    println!("Balance: {}", account.get_balance());
    // This line will not compile because apply_fees is private
    account.apply_fees();
}
```
Attempting to call the `apply_fees` method will result in an error:
```
error[E0624]: method `apply_fees` is private
  --> src/main.rs:9:13
   |
9  |     account.apply_fees();
   |             ^^^^^^^^^^ private method
   |
  ::: src/employee.rs:26:5
   |
26 |     fn apply_fees(&mut self) {
   |     ------------------------ private method defined here
```

###In this Rust example:
In the Rust example, we have a simple Account `struct` with a private field called balance. Here’s how it works:
1. Struct Definition: We define the `pub struct` Account in the src/employee.rs file. The `balance` field is private by default (not exposed outside the module). 
2. Public Methods: We provide public methods `new`, `get_balance`, `deposit`. These methods allow controlled access to the balance field. 
3. Private Method: The `apply_fees` method is marked as private (not accessible outside the `struct`). It deducts a fixed fee from the account balance. 
4. Usage in main.rs: In the main function, we create an Account instance, deposit money, and print the balance. Attempting to call `apply_fees` results in a compilation error since it’s private. 

#Python Example
Python uses a different approach to encapsulation, primarily through the use of underscores to denote private attributes and methods. However, it's important to note that Python's privacy is more of a convention than a strict enforcement. In Python, all attributes and methods are public by default. To make an attribute or method private, you prefix its name with double underscores (`__`). This does not make the attribute or method truly private, but it signals to other developers that it is intended for internal use within the class. The provided Python example demonstrates encapsulation by defining a class with a private attribute (`__balance`) and public methods (`__init__`, `get_balance`, `deposit`). The `__apply_fees` method is intended to be private, but due to Python's lack of strict access control, it can still be accessed from outside the class, although it is not recommended. 

```python
# Define a class with private attributes
class Account:
    def __init__(self, initial_balance):
        self.__balance = initial_balance  # Private attribute

    def get_balance(self):
        return self.__balance

    def deposit(self, amount):
        self.__balance += amount

    def __apply_fees(self):  # Private method
        FEE = 2.5
        self.__balance -= FEE

# Create an instance of Account
account = Account(100)
account.deposit(50)
print("Balance:", account.get_balance())
# This line will raise an AttributeError because __apply_fees is private
account.__apply_fees()
```
Attempting to call the `apply_fees` method will result in an error:
```
AttributeError: 'Account' object has no attribute '__apply_fees'
```

##In this Python example:
1. Constructor and Private Attribute: The `__init__` method initializes an Account instance with an initial balance. The `__balance` attribute is marked as private. 
2. Public Methods: We define public methods: `get_balance` and `deposit` (to add funds). These methods allow controlled access to the private `__balance`. 
3. Private Method: The `__apply_fees` method is marked as private. It deducts a fixed fee from the account balance. 
4. Usage: We create an account instance, deposit money, and print the balance. Attempting to call `__apply_fees` raises an `AttributeError` due to its private status. 

#Summary
Both examples demonstrate encapsulation by hiding implementation details and providing controlled access to data and methods. Rust achieves encapsulation through module visibility, while Python uses name mangling and access modifiers
Both Rust and Python support encapsulation, but they implement it in ways that reflect their language design principles and paradigms. Rust's approach is more explicit and enforced by the language, while Python's approach is more flexible but relies on convention and name mangling.
It's important to remember that Python's approach to encapsulation is more about convention and best practices rather than strict language enforcement.

##Useful articles:
###Encapsulation in Rust
[Rust Is Beyond Object-Oriented, Part 1: Intro and Encapsulation](https://www.thecodedmessage.com/posts/oop-1-encapsulation/), Jimmy Hartzell, 2022-12-12
[Object-Orientation in Rust](https://stevedonovan.github.io/rust-gentle-intro/object-orientation.html) 
[How to Implement Object-Oriented Programming Concepts in Rust](https://www.makeuseof.com/rust-object-oriented-programming-concepts-how-to-implement), 2023-04-02
[How to write properly encapsulation?](https://users.rust-lang.org/t/oop-how-to-write-properly-encapsulation/15554), Harry Ying, February 2018
###Encapsulation in Python
[Encapsulation in Python](https://pynative.com/python-encapsulation), Updated on: 2021-08-28
[Embedding Python in Rust with WebAssembly](https://wasmlabs.dev/articles/python-wasm-rust), Asen Alexandrov, June 2023
[Encapsulation in Python](https://www.geeksforgeeks.org/encapsulation-in-python)
[Python Private Attributes](https://www.pythontutorial.net/python-oop/python-private-attributes) 
[Characteristics of Object-Oriented Languages](https://doc.rust-lang.org/book/ch17-01-what-is-oo.html), doc.rust-lang.org
###Rust + Python:
[Integrating Rust into Python](https://medium.com/vortechsa/integrating-rust-into-python-1515a752fdb3), Edward Wright, 2021-04-12
[Examples for making rustpython run actual python code](https://github.com/janluak/rustpython_example) 
[Calling Rust from Python using PyO3](http://saidvandeklundert.net/learn/2021-11-18-calling-rust-from-python-using-pyo3) 
[Writing Python inside your Rust code — Part 1](https://blog.m-ou.se/writing-python-inside-rust-1), 2020-04-17
[RustPython](https://github.com/RustPython/RustPython), [RustPython](https://rustpython.github.io) 
[Rust for Python developers: Using Rust to optimize your Python code](https://blog.parcio.de/posts/2022/07/rust-for-python) 
[PyO3](https://github.com/PyO3/pyo3) (Rust bindings for Python)
[Musing About Pythonic Design Patterns In Rust](https://medium.com/@teddy.rendahl/musing-about-pythonic-design-patterns-in-rust-7e0466ba5709), Teddy Rendahl, 2023-07-14

Image created by Bing and edited by me

## Other articles about the similarities and differences between Rust and Python

1. [Python Classes vs. Rust Traits](https://dev.to/antonov_mike/python-classes-vs-rust-traits-a-comparison-of-object-oriented-programming-features-5gbl)
2. [Python classes vs Rust structures](https://dev.to/antonov_mike/python-classes-vs-rust-structures-nod)
3. [Polymorphism in Rust and Python](https://dev.to/antonov_mike/polymorphism-in-rust-and-python-simple-examples-29co)
4. [Abstraction in Rust and Python](https://dev.to/antonov_mike/abstraction-in-rust-and-python-simple-examples-5dd8)
5. [Encapsulation in Rust and Python](https://dev.to/antonov_mike/how-rust-and-python-implement-encapsulation-4ick)
6. [Composition in Rust and Python](https://dev.to/antonov_mike/composition-in-rust-and-python-21c3)