The day came when I met Infinity. She was from the central resistance base,
called 'Wonderland'. Every month, Ritchie had been sending the 10 best
programmers from his base to Wonderland, for participation in the Rust
project.
"Wait!" - I realised I had just said 'best programmers'. "Does this mean
that I'm one of the top 10 best programmers that Ritchie has?! Cool!" - I
hadn't even thought about that until now.
"Are you listening to me Teo?" Infinity stopped my thoughts, asking a
question.
"Sure, sorry... please continue." I replied.
"This is gonna be hard. You'll be in the central base with the best
programmers we have. Your mission in the Rust project will be top secret;
you will not be able to talk about it to your friends."
Friends? She said
friends
?! Does she know that I have literally nobody on my own here?! That I'm
completely alone?! That my best friend is a machine that I still don't
trust?! She must be kidding!
"I looked through your code Teo... And I was surprised at how quickly you've
improved! Take your first and last programs for example; this is
astonishing! But at the same time, I've realized that whoever was training
you, is only choosing data types that match each other. You have never used
the
type conversion
technique."
"Type conversion?!" I hadn't heard of that before.
"Let's take some time Teo, and I'll go through this topic with you right
now." she replied.
Infinity began, "Here is a table of built-in types in C#. Some of them you already know, but others could be new for you":
Data Type | Size (bytes) | Range |
---|---|---|
|
1 | 0..255 |
|
1 | -128..127 |
|
2 | -32,768 .. 32,767 |
|
2 | 0 .. 65,535 |
|
4 | -2,147,483,648 .. 2,147,483,647 |
|
4 | 0 .. 4,294,967,295 |
|
8 | -9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807 |
|
8 | 0 .. 18,446,744,073,709,551,615 |
|
4 | -3.402823e38 .. 3.402823e38 |
|
8 | -1.79769313486232e308 .. 1.79769313486232e308 |
|
16 | -79,228,162,514,264,337,593,543,950,335 .. 79,228,162,514,264,337,593,543,950,335 |
|
1 | True or False |
|
2 | A unicode character (0 .. 65,535) |
"My God! Do C# programmers remember all these types, their sizes and ranges
off by heart?!" I wondered.
"Most of them... not. What you need to know, is when to use each of those."
"Yeah, for example,
byte
,
short
,
int
- they're almost the same, so why can't I just use
int
all the time?" I naively asked.
"Well... you can! It depends on the constraints that you have. If you have
50 000 small integers that you need to send over the network, then a
byte
array can be preferable over an
int
array, as it will save memory space and increase the speed." she explained.
"For now, let's make a deal, that if you have no special requirements for
the task, then
use
int
for integer numbers and
double
for fractional numbers.
"
"OK, I will do. I've already been doing this so far..." I replied, "Wait -
can you please tell me, what does that 'u' mean at the beginning of some of
the types?"
"
u originates from 'unsigned'
. If you look carefully, you'll notice that types that start with
u
, do not have negative values. In general, you can use
int
,
uint
,
short
,
ushort
,
long
and
ulong
in a very similar way - look at this code example and solve the task after
it":
byte byteVariable = 12;
short shortVariable = 12;
int intVariable = 12;
long longVariable = 12;
// Use short.Parse long.Parse byte.Parse same as int.Parse
short anotherShort = short.Parse(Console.ReadLine());
var yetAnotherShort = short.Parse(Console.ReadLine());
Console.WriteLine(byteVariable); // Outputs 12
Console.WriteLine(shortVariable); // Outputs 12
Console.WriteLine(intVariable); // Outputs 12
Console.WriteLine(longVariable); // Outputs 12
Infinity continued, "As you know,
in C# every variable has a type. It's impossible to change the type of a
variable, but you can convert a value from one type to another and then
store it into a new variable.
There are two kinds of type conversion:
implicit
and
explicit
.
Implicit conversions happen without us as programmers even noticing it
! Here is an example of implicit type conversion":
short shortNumber = 23;
// Implicit conversions
int intNumber = shortNumber;
float someFloat = shortNumber;
double firstDouble = intNumber;
double secondDouble = shortNumber;
// Wrong, no implicit conversion
intNumber = firstDouble;
"As you'll see, I've created a
short
variable and assigned it to
int
,
float
and
double
. Everything is fine; implicit conversion happens, and you store the value
from a variable of one type, into a variable of another one." Infinity
explained.
"This is a bit confusing!" I exclaimed. "How would I know that implicit
conversion between two types exists?"
"Good question Teo! There is a general rule:
implicit conversion exists from 'small' types, to 'bigger' ones, counted
by the amount of bytes the type takes
. For example, there is an implicit conversion from
byte
to
int
, but not vice versa; from
int
to
byte
."
"It makes some sense now... So, if inside an
int
variable, I have a big number - let's say 1000, and I try to store it inside
a
byte
variable, it won't fit into the range [0-255]?" I shared my thoughts.
"Yes, that's exactly the reason Teo. If I have an
int
that takes 4 bytes, it's impossible to fit it into a
byte
type that is only 1 byte big. Here is a complete
C# Implicit Numeric Conversions Table
, or you can just use a subset that I've picked for you":
From Type | To Types |
---|---|
|
|
|
|
|
|
|
|
I started to like her. She was smart, wasn't aggressive and explained things
really well. Perhaps I wouldn't be so disappointed about working with her if
I had no backup plan (like returning home with Noname's help).
"Good job Teo! There is one more type conversion technique —
the explicit conversion
. It is also called a
cast
.
A cast is a way of explicitly informing the compiler that you
intend
to make the type conversion, and that you are aware that data loss may
occur. To perform a cast, specify the type that you are casting to in
parentheses(), in front of the value or variable to be converted.
Here is an example where we cast
double
to
int
":
double a = 123.95;
int b = (int)a; // Explicit cast
Console.WriteLine(b); // Outputs 123
"This looks powerful!" I proclaimed. "Could you please show me some more
cast examples?"
"No problem, here you go! Oh, and don't forget about the exercise after
below the example!":
double someDouble = 123.95;
float someFloat = (float)someDouble; // No data loss, someFloat == 123.95
double anotherDouble = 123.456789098765;
float anotherFloat = (float)anotherDouble; // Data loss, anotherFloat == 123.4568
long someLong = 123;
int someInt = (int)someLong; // No data loss, someInt == 123
long anotherLong = 112233445566;
int anotherInt = (int)anotherLong; // Data loss, anotherInt == 564295870
int yetAnotherInt = 123;
byte someByte = (byte)yetAnotherInt; // No data loss, someByte == 123
int intToConvert = 1234;
byte resultAsByte = (byte)intToConvert; // Data loss, intToConvert is too big to fit into byte
// Multiple conversions in expression are also fine
int intResult = (int)someLong + (int)anotherDouble; // Data Loss, intResult == 246
float floatResult = (float)anotherDouble + (float)someDouble; // Data loss, floatResult == 247.406784
// Conversion of the operation's result is fine as well
int anotherIntResult = (int)(someLong + anotherDouble); // Data Loss, anotherIntResult == 246
float floatResult2 = (float)(anotherDouble + someDouble); // Data loss, floatResult2 == 247.406784
"So, take this very simple task. You have some cupcakes and some people that
all want one! You need to share among people fairly, so that everyone gets
an equal amount of cupcakes. Your program should read an
int
(amount of cupcakes), and another
int
(amount of people). Then, it should output "Every person should get {amount}
cupcakes"
"This seems simple; you just need to divide 2 numbers... do you want me to
write the code?" I asked.
"Go ahead!" she said, a little too positively.
It was clear that something wasn't quite right. She was smiling and staring
straight at me.
"But... I'll write the code." I uneasily thought to myself.
int cupcakesCount = int.Parse(Console.ReadLine());
int peopleCount = int.Parse(Console.ReadLine());
double result = cupcakesCount / peopleCount;
Console.WriteLine($"Every person should get {result} cupcakes.");
"Okay, let's run this code with 3 people and 6 cupcakes" she said.
The code ran fine; the result was - "Every person should get 2 cupcakes"
She continued, "But, what if we have only 1 cupcake and 4 people?"
When we tried my code with these parameters, the output was - "Every person
should get 0 cupcakes"
"Why is it 0? It should be a quarter (0.25) of a cupcake for everyone!" I
firmly yelled, frustrated.
"Well, it's because of the type conversion.
When you perform an arithmetic operation with integers, you'll always get
an integer as a result. This works for
short
,
byte
,
float
and all other primitive types that we've used.
"What does this mean Infinity?!" I asked.
"This means, that you should be careful when dividing
int
types. C# compiler isn't able to understand that you want a
float
or
double
as a result, unless you specifically tell it this. Otherwise,
it will disregard the fractional part
. Here, I've prepared some examples":
int a = 9;
int b = 4;
double firstAttempt = a / b;
double secondAttempt = (double)a / b;
double thirdAttempt = a / (double)b;
double nextAttempt = (double)a / (double)b;
double lastAttempt = (double)(a / b);
Console.WriteLine(firstAttempt); // Outputs 2
Console.WriteLine(secondAttempt); // Outputs 2.25
Console.WriteLine(thirdAttempt); // Outputs 2.25
Console.WriteLine(nextAttempt); // Outputs 2.25
Console.WriteLine(lastAttempt); // Outputs 2
Console.WriteLine( (int)2.25 ); // Outputs 2
Console.WriteLine( (int)secondAttempt ); // Outputs 2
"As you'll see Teo, there are a lot of ways to cast types. The main rule here is ' if there are several operands in the expression, then the type of the result is the largest of the operand types'. For example, if you divide int and double , the result is double . If you multiply byte and int , the result is int . In tasks that you are going to solve in the future, make sure you don't forget to cast to double or float during int division. If you forget, you'll lose the fractional part, just like in the cupcakes example!"