I recently landed a full-time Software Engineer role working with C# and .NET, and so far, it’s been fantastic! Transitioning from Ruby and Rails is a learning curve, but I’m really enjoying the deliberate, statically-typed nature of compile-time coding. Who would’ve thought?!
As you might guess, in the same way that Ruby has gems, .NET has a package manager called NuGet and provides the same tools & libraries you need for development. However, where the process starts to differ a bit from Ruby is what C# is capable of in terms of class structure and design. All of this, of course, is new to me.
I want to walk through a simple Class declaration to show the similarities between the language syntax. Also, I'm definitely planning on writing a separate post that discusses the depths of class design specific to C# too, which I'll link here eventually. Fortunately, it’s very easy to get started with C# & .NET with a powerful sandbox IDE called LINQPad compatible with both Windows & MacOS! You will also need to install .NET, LINQPad will detect .NET installs but doesn’t install it automatically.
Type Safety
I am a big fan of quantifying topics when learning and before anything, it’s important to touch on the realm of type safety since that’s the first difference we find between Ruby & C#.
In C#, type safety is enforced at compile time. This means that when you declare a variable (say, as basic as an int
), the compiler checks that you only assign values of that type, catching errors before the program even runs. For example, if you try to assign a string to an int, the code won’t compile:
int number = 5; // The type 'int' is set at compile time and cannot change.
number = "hello"; // CS0029: Cannot implicitly convert type 'int' to 'string'
In contrast, Ruby checks types at runtime and while Ruby is also strongly typed (meaning you can’t seamlessly mix incompatible types) it only raises errors when the problematic code is executed. Another example is how syntax errors are handled. For instance, many syntax errors in C# are caught before compilation, preventing the program from running until you fix them, whereas in Ruby those same errors only appear when the affected code is executed, hitting ya with a runtime stack trace.
Class on Classes
I want to start with the basic class structure that we can compare between Ruby & C#. The exciting realization is that this basic structure in Ruby is the same in C# with some different semantics! Below is an example of a basic class in C# & Ruby that achieves the same goal: “Playing” and album
Basic C# Class
public class Album
{
public string Title { get; set; }
public string Artist { get; set; }
public Album(string title, string artist)
{
Title = title;
Artist = artist;
}
public void Play()
{
Console.WriteLine($"Now playing: {Title} by {Artist}");
}
}
// Test
void Main()
{
var album = new Album(title: "Grace", artist: "Jeff Buckley");
album.Play();
}
Basic Ruby Class
class Album
attr_accessor :title, :artist
def initialize(title, artist)
@title = title
@artist = artist
end
def play
puts "Now playing: #{@title} by #{@artist}"
end
end
# Test
album = Album.new("Grace", "Jeff Buckley")
album.play
You can start to draw lines between the two and honestly, in my opinion, Ruby wins out here. There are a couple differences I’d like to specifically note!

Property Accessors (Getters and Setters)
C#
In C#, we have properties that encapsulate data by combining a field-like syntax with the benefits of method calls. Properties are conventionally like attributes in Ruby. The syntax below defines two public properties with automatic getters and setters:
public string Title { get; set; }
public string Artist { get; set; }
These properties are public and define both the automatic getter and setter. But just like in Ruby, you can customize a bit further if needed by defining a setter as private: public string Title { get; private set; }
or even define a read-only property: public bool IsReleased { get; }
. You can also expand the property definition for more control with the get
or set
.
Ruby
Ruby takes a more concise approach with property access using the attr_accessor
method
attr_accessor :title, :artist
This one line automatically creates both getter and setter methods for the specified symbols (:title
and :artist
). It’s simple and straightforward! You can also use attr_reader
or attr_writer
for read-only or write-only attributes respectively, or define custom methods for additional control.
Constructor Syntax
C#
Constructors in C# are special methods used to initialize new instances of a class just the same as in Ruby. They share the class name and may accept parameters to set up object state at creation:
public Album(string title, string artist)
{
Title = title;
Artist = artist;
}
This example shows a parameterized constructor for the Album
class, where incoming values are assigned to the class properties. Remember that read-only property I mentioned above? This is where we would set it: IsReleased = true
.
Ruby
Ruby uses the initialize
method as its constructor, which is automatically invoked when a new instance is created using the .new
method. Looks very similar!
def initialize(title, artist)
@title = title
@artist = artist
end
Here, the initialize
method assigns its parameters to instance variables (denoted with the @
symbol). Again, it definitely feels more straightforward and intuitive than the C# constructor.
Entry Point
C#
Every C# application requires a clearly defined entry point, something I’m getting used to. Usually, the method where execution begins is called Main
.
void Main()
{
var album = new Album(title: "Grace", artist: "Jeff Buckley");
album.Play();
}
Here you can see the Main
method instantiates the Album
class and then calls its Play
method.
Ruby
Ruby does not require a formal entry point like C#. When a Ruby script is executed, the interpreter processes the file sequentially from top to bottom.
album = Album.new("Grace", "Jeff Buckley")
album.play
Whatever is called at the bottom (or last) in your file is the de facto entry point. There is no special method required to kick off the program. This is great for smaller applications or scripts where a rigid structure is unnecessary.
Wrapping up
There are obvious pros and cons to both C# & Ruby and like with any programming language or framework, you use what best suits your situation. In my current role, I’m working with some extremely sophisticated tools built entirely in C#. They require a much more explicit, verbose approach and don’t necessarily need the MVC structure you’d typically find in a web framework like Rails.
It’s really awesome to get a chance to build in a language like C# and learn about this approach. Ruby is on the back burner for now, reserved for side projects (like this blog! 🤩), but I will always appreciate the simplicity it carries that allowed me to learn OOP incredibly quickly! I definitely wouldn’t have been able to dive headfirst into C# & .NET without the strong foundation I received from learning Ruby first.