I've been developing almost exclusively in Python for the past six years, primarily focusing on data engineering and machine learning tasks. While I'm confident in my ability to write effective and reliable Python code, my knowledge tends to be practical and focused on solving specific problems. However, I recognize an opportunity to deepen my theoretical understanding of Python's internals and foundational concepts, particularly when it comes to articulating details about the language's underlying mechanics.
Part of this stems from my practical, rather than theoretical, approach to Python—I haven't yet invested significant time into mastering its deeper structures and nuances. And a big component of that is I don't have anything to compare Python against. I don't know how Go, Rust, or another language would read in data, transform it, and output a result. I want to change that.
So for the next few weeks I'm going to look at how Python, Go, Rust, and JavaScript would all solve the same programming tasks. I'll first write that task in each language, make some notes about the syntax used, and then compare the differences between them.
The first programming task I'm going to examine is class instantiation. Class instantiation is simply the creation of an object. That object will almost certainly have attributes and will usually be instantiated multiple times to handle different versions of the same class.
We're going to create a class called, "Person". This class will have two attributes, name and age. We'll then instantiate an instance of this class for a 30 year old person named Alice. We'll also give this class a method called Greet which will return, "Hello, I'm Alice".
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
return f"Hello, I'm {self.name}"
person = Person("Alice", 30)
print(person.greet())
struct Person {
name: String,
age: u32,
}
impl Person {
fn new(name: String, age: u32) -> Person {
Person { name, age }
}
fn greet(&self) -> String {
format!("Hello, I'm {}", self.name)
}
}
let person = Person::new("Alice".to_string(), 30);
println!("{}", person.greet());
package main
import "fmt"
type Person struct {
Name string
Age int
}
func NewPerson(name string, age int) *Person {
return &Person{
Name: name,
Age: age,
}
}
func (p *Person) Greet() string {
return fmt.Sprintf("Hello, I'm %s", p.Name)
}
person := NewPerson("Alice", 30)
fmt.Println(person.Greet())
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Hello, I'm ${this.name}`;
}
}
const person = new Person("Alice", 30);
console.log(person.greet());
Takeaways
Python and Rust are my favorite. Python is easy to read and write. We can also include some aspects of Rust and Go (like data structure/method separation and type checking) that result in extensible and reliable code.
Rust appears pretty intuitive once you understand the structure/method separation concept and I appreciate the requirement for data types when defining a structure without being super verbose as it appears Go requires.