I arrived in Wonderland yesterday. I'm still not entirely sure that my decision to stay in the future was wise... In any event, I'm comfortable with where I'm at now. I carry more responsibility and have mostly stopped lamenting my hardships.
Infinity gave me a quick briefing about the situation here. Wonderland is the largest-known resistance base on Earth. It's surrounded by a shield that prevents machines from scanning the area. Instead of analyzing the surface for the base, the machines have resorted to brute-force tactics, namely digging, in hopes of hitting the jackpot. Because of this, the atmosphere here is tense: people are afraid that at any moment the machines may come up out of the ground and reveal Wonderland's location.
The primary objective for everyone here is a project codenamed
Rust
, which is a virus that provides full control over a machine to any chosen
server. In our case, of course, that would mean a resistance server. We want
to inject this virus in the handshake message that every device sends to one
another when they establish communication. So far, so good - prototypes of
virus already exist! But... they don't work. That's why I'm here, and why
Infinity gathers the best programmers from other resistance bases. She needs
this virus to work. As soon as possible.
While humanity still has some fight left in it.
There are a lot of small details that need to be sorted out in order for Rust to work; for example, if we can take control of a machine, how do we send commands to billions of machines at once? One server won't be able to control that amount of traffic, and if that server crashes, we immediately lose our advantage. The machines will quickly craft an antivirus. In addition, there are probably ten new machine prototypes produced every single week - how can Rust adapt to that kind of variety? I know, I know, not exactly positive thinking. But this is the best option we have for now, and we will; rather, we need ; to solve all of it.
The skill level of the programmers in Wonderland is astounding. I feel like a freshman again, and I will doubtless have studies every day as before. Let's get started!
The main instruction room was bigger and brighter than the one in Ritchie's
resistance base. Ten students were here with me. The teacher was a woman,
around 35-40 years old, with big glasses.
"Hello everyone! My name is Sintia, and we are going to have a brief
overview of
classes
today. Let's make a list of what you learned before you came to Wonderland,"
she said, picking up a marker.
We named some topics in C#, and everyone's answers were fairly similar.
Apparently, in all the resistance bases, people know the same subset of C#.
"Ok, that's a good start," Sintia said. "But these are only basics. Your
real education in C# starts today, now, in this room. Can anyone tell me
where the concept of
classes
came from?"
This time, no hands went up.
"Ok then, here's the origin story. A long time ago in a language called
C
, there were no classes or namespaces; people were writing functions, and
everything just worked. As software development grew, however, programs
became more and more complicated. Eventually, name clashes started to occur
when several functions with the same name were imported from different
programming modules. This made it impossible to compile the code. Imagine a
simple scenario where you have a game with a
Log(string message)
function to write something to a log file. And then a module gets imported
that
also
has its own
Log(string message)
function. As you all know, you can't have two functions with the name Log,
because they'll be indistinguishable from one another. That's why
programmers began to create prefixes, like
Internal_Log(...)
and
ExternalLibName_Log(...)
. The same was done with global data variables:
int
Internal_Timeout
,
int
ExternalLibName_Timeout
, etc. As a result, code became longer, less readable, and more difficult to
write. That's why smart people decided to bring into C the
concept of an object - an entity that stores data and the methods to work
with that data all in one place.
This entity will also determine a scope, which means methods and variables
with the same name can exist in different entities."
The paradigm of using objects is called
OOP - object-oriented programming.
Object-oriented programming (OOP) is a programming paradigm based on the
concept of "objects," which may contain data fields and code, in the form
of procedures, often known as methods.
"Can I ask you a question?" I said.
"You already did," Sintia answered with a light smile on a face.
"Why did you start talking about
classes
but then switch to
objects
? Are they the same thing?" I wondered.
"Good question, Teo! Nice catch!" she looked satisfied.
"
A class is a template for objects.
A class defines object properties including a valid range of values and a
default value. A class also describes object behavior.
An object is an "instance" of a class.
An object has a state in which all of its properties have values that you
define.
"
"Sorry, but I don't understand," said another student. "Can you show us an
example?"
"Fair enough. Look at this
class
definition:"
class Box
{
int Length;
int Width;
int Height;
bool IsOpened;
public void Open()
{
IsOpened = true;
}
public void Close()
{
IsOpened = false;
}
}
"Why didn't you use a
static
keyword for the methods? All the methods we worked with before now were
static
," another student asked.
"Yeah, this can be confusing," Sintia answered. "Please,
until you learn what
static
means, leave only the
Main
method as
static
; all other fields and methods should
not
have a
static
modifier."
Sintia continued:
"Can anyone tell me how much space in memory the
Box
class occupies now?"
"An integer is 4 bytes, which means we need three multiplied by four and
add..." one of the students began thinking out loud.
"Wrong. It takes 0 bytes. What you see is only a
template
of a box that
could be created
. But there are no boxes created in this code - what you see is a
class
. Remember, a
class is only a template for a real instance.
It shows you what an instance of that class will look like, but it does
not
create
an instance. Think of a class name as a new type like
int
or
string
. After you've created the Box class, you can create variables of type Box
and assign values to them,
" Sintia concluded.
"How can I create an instance of a box?" I asked.
"In a Main method, use the
new
operator, as you did for arrays."
Box boxObject = new Box();
"Now,
boxObject
will take some space in memory, because it is an
object
, not just a
class
."
"I think I understand now.
An object is something real, that is allocated in memory, and we can
control it during program runtime. A class is just a template for all
objects that are going to be created
," said one of the students.
"Yes, exactly!" Sintia looked satisfied.
She continued, "A
class
consists of
fields (members)
and
methods. Fields (or members) are for storing the typed data, the same as
local variables. Methods are functions that work with this data. You can
access all fields from within methods of the same class; again, the same
as you did with local variables.
Here's a figure that might make it a bit more clear."
"Any final questions before we delve into the practice of objects?" she
asked.
"What types can you use for fields?" asked someone in the back.
"Any type that you want. It can be a
string
,
array
,
double
,
Box
, or any other type. If you want a deeper dive into fields, you can read
this
article, which I'll post in the notes. Time for the first exercise!"
"Sintia, how do I assign a value to a field from
outside
of the
class
? For example, say I want to create a user with a name 'Bob'?" asked one of
the students.
"Good question! There are several ways of working with fields. I'll show you
the simplest one; you'll learn others along the way. First of all, you need
to modify fields in the User
class
to make them
public
. You'll learn more about access modifiers in the future, but for now, you
just need to know that
public
methods and fields are accessible from outside of the
class
, like this:"
class User
{
public string Name;
public int Age;
}
" To assign a value to a public field from outside of its class, you need to type an object name, then dot(.), and then the name of the field. Then assign a value to it like normal. Here is an example: "
class User
{
public string Name;
public int Age;
}
class ProgramWithMain
{
public static void Main()
{
// Classic approach
User bob = new User();
bob.Name = "Bob";
bob.Age = 38;
// And an "object initializer" version
User anotherBob = new User
{
Name = "Bob",
Age = 38
};
}
}
"Do I understand correctly that you've created two objects of the same
class
?" I asked.
"Yes, Teo," Sintia answered. "To be even more precise, I've created two
objects of type
User
inside the Main method.
Main
is located outside of the User class - that's why you can't use
Name
or
Age
directly. They belong to another entity. Thus, first, we create that entity.
Remember,
to create an object, first enter its type followed by your name for the
new instance, then 'equals', followed by the
new
keyword and then the type name again followed by a set of parentheses
."
User bob = new User(); // Created an object bob of type (class) User
User alice = new User(); // Created one more object of type (class) User
User sam = new User // Created an object of type User with object
initializer
{
Name = "Sam",
Age = 12
};
"What is an
object initializer
?" someone asked.
"Good eye!" Sintia replied. "It's another way of creating an object - more
'modern' or C-sharpish. You can also use
var
instead of the type name. In the following table, every code snippet does
absolutely the same thing:"
Classic Object Creation | Object Initializer |
---|---|
|
|
|
|
"Are you ready to use objects? Or is there maybe something you're still
missing?" Sintia asked.
"If you are asking, then we are still missing something," I said, smiling.
"You got it Teo. You'd be a good psychologist! But you're a programmer here;
turn on your logic.
What
are you missing?" Sintia sounded serious.
Logic turned on. "Well, I know how to
declare a class, create an object, set all fields of this object
... Wait, how do I access them?"
"Bingo! You need to access fields. To do it, just use the syntax of
assignment, but don't assign any values.
Type the object name, then a dot(.), followed by the name of a field. Be
aware that this only works for
public
fields.
"
var user = new User
{
Name = "Sam",
Age = 12
};
Console.WriteLine($"Hello, {user.Name}");
Console.WriteLine($"You are so young, only {user.Age} years old!");
user.Age++; // Work with fields like with local variables before
Console.WriteLine($"{user.Name}, now your age is changed to: {user.Age}.");
user.Age = 15; // Work with fields like with local variables before
Console.WriteLine($"{user.Name}, now you are {user.Age} years old.");
// Output:
// Hello, Sam
// You are so young, only 12 years old!
// Sam, now your age is changed to: 13.
// Sam, now you are 15 years old.
"To pass objects to methods as parameters, you can do the same as you did for arrays; i.e., pass the objects in by reference."
class User
{
public string Name;
public int Age;
}
class NamePrinter
{
public void PrintNameNicely(User user)
{
Console.WriteLine($"!!!### {user.Name} ###!!!");
}
}
class ClassWithMain
{
public static void Main()
{
var bob = new User // Created an object of type User
{
Name = "Bob",
Age = 12
};
// Created an object of type NamePrinter
var namePrinter = new NamePrinter();
// Passed an object bob to a method of another object
namePrinter.PrintNameNicely(bob);
}
}
We are prototyping a robot that refills glasses during dinner. Every glass
holds 200 milliliters. During dinner, people either drink water or juice,
and as soon as there is less than 100 ml left in the glass, the robot
refills it back to 200 ml.