In this part of the Ruby tutorial, we will talk about data types.
Computer programs work with data. Spreadsheets, text editors, calculators or chat clients. Tools to work with various data types are essential part of a modern computer language. A data type is a set of values, and the allowable operations on those values.
Ruby has several data types. All data types are based on classes. The following are the data types recognized in Ruby:
Happy parents are waiting a child to be born. They have chosen a name for both possibilities. If it is going to be a boy, they have chosen John. If it is going to be a girl, they have chosen Victoria.
A Ruby symbol cannot be changed at runtime. Ruby symbols are often used as hash keys, because we do not need full capabilities of a string objects for a key.
Symbols may be used as flags. Constants may be used in such situations as well. In C/C++ we would use enumerations.
Symbols are often used as keys in hash containers. They are more efficient that strings.
Ruby interpreter stores some refererences internally as symbols.
All symbols are stored in a symbol table. In the next example, we look at the table. The
In computer languages, integers are primitive data types. Computers can practically work only with a subset of integer values, because computers have finite capacity. Integers are used to count discrete entities. We can have 3, 4, 6 humans, but we cannot have 3.33 humans. We can have 3.33 kilograms.
Integers are instance objects of a
Integers can be specified in different notations in Ruby. Decimal, hexadecimal, octal and binary. Decimal numbers are used normally, as we know them. Hexadecimal numbers are preceded with 0x characters, octal with 0 character and binary with 0b characters.
If we work with integers, we deal with discrete entities. We would use integers to count apples.
Big numbers are difficult to read. If we have a number like 245342395423452, we find it difficult to read quickly. Outside computers, big numbers are separated by spaces or commas. Ruby allows to separate integers with an underscore, which is simply ignored by the Ruby interpreter.
We need to understand that decimal numbers are not precise. The official Ruby documentation says it clearly, Float objects represent inexact real numbers.
By default, a decimal number is shown with a maximum 16 numbers after the decimal point. We can control the format of floating point values with the
Ruby supports the scientific syntax of the floating point values. Also known as exponential notation, it is a way of writing numbers too large or small to be conveniently written in standard decimal notation.
As we have already stated, floating point values are slightly inaccurate. In many situations this precision is sufficient. It is not that important, if our weight is 60kg or 60.000023kg. On the other hand, there are computations in which the precision is paramount. Especially in science or engineering.
Ruby has a
Let's say a sprinter for 100m ran 9.87s. What is his speed in km/h?
A rational number is any number that can be expressed as a fraction of two integers a/b , where b!=0. Since b may be equal to 1, every integer is a rational number.
A string is a very important data type. It deserves a dedicated chapter. Here we just drop a small example.
Arrays are ordered collections of objects. Hashes are collections of key-value pairs. We will have a single chapter for both arrays and hashes. The following example just gives a quick look at both containers.
Ruby has built-in conversion methods like
The second example shows some string conversions.
The next small example shows array hash conversions.
In this part of the Ruby tutorial, we covered data types and their conversions.
Computer programs work with data. Spreadsheets, text editors, calculators or chat clients. Tools to work with various data types are essential part of a modern computer language. A data type is a set of values, and the allowable operations on those values.
Ruby has several data types. All data types are based on classes. The following are the data types recognized in Ruby:
- Booleans
- Symbols
- Numbers
- Strings
- Arrays
- Hashes
#!/usr/bin/rubyWe print their class names. A class is a template from each object is created.
h = { :name => "Jane", :age => 17 }
p true.class, false.class
p "Ruby".class
p 1.class
p 4.5.class
p 3_463_456_457.class
p :age.class
p [1, 2, 3].class
p h.class
p true.class, false.classThe boolean values are presented by true and false objects.
p "Ruby".classThis is the string.
p 1.classThese are the numbers.
p 4.5.class
p 3_463_456_457.class
p :age.classThis is a symbol, a data type specific to Ruby.
p [1, 2, 3].classThese are two containers, the array and the hash.
p h.class
$ ./types.rbThe program lists classes that belong to Ruby data types.
TrueClass
FalseClass
String
Fixnum
Float
Bignum
Symbol
Array
Hash
Boolean values
There is a duality built in our world. There is a Heaven and Earth, water and fire, jing and jang, man and woman, love and hatred. This is the 'boolean' nature of our existence. In Ruby the boolean data type can have one of the two values: true or false. It is a fundamental data type. Very common in computer programs.Happy parents are waiting a child to be born. They have chosen a name for both possibilities. If it is going to be a boy, they have chosen John. If it is going to be a girl, they have chosen Victoria.
#!/usr/bin/rubyThe program uses a random number generator to simulate our case.
# kid.rb
bool = [true, false]
male = bool[rand(2)]
if male
puts "We will use name John"
else
puts "We will use name Victoria"
end
bool = [true, false]We have a bool variable. It is an array of two boolean values. An array is created with square brackets.
male = bool[rand(2)]We use a
rand()
method to create a random number. The method returns either 0 or 1. The returned number is an index to the bool array. if maleDepending on the male variable, we print a message. If the male variable is set to true, we choose name John. Otherwise, we choose name Victoria. Control structures like if/else statements work with boolean values.
puts "We will use name John"
else
puts "We will use name Victoria"
end
$ ./kid.rbRunning the program several times.
We will use name Victoria
$ ./kid.rb
We will use name Victoria
$ ./kid.rb
We will use name John
$ ./kid.rb
We will use name John
$ ./kid.rb
We will use name John
Symbols
Symbols are used to represent other objects. Using symbols instead of strings may save some resources. A symbol is an instance object of aSymbol
class. Symbols are generated by using an colon before an identifier, like :name. Several objects also have to_sym
methods, that convert them to symbols. A Ruby symbol cannot be changed at runtime. Ruby symbols are often used as hash keys, because we do not need full capabilities of a string objects for a key.
#!/usr/bin/rubyIn the first example, we show some basic operations with Ruby symbols.
p :name
p :name.class
p :name.methods.size
p "Jane".methods.size
p :name.object_id
p :name.object_id
p "name".object_id
p "name".object_id
p :nameWe print a symbol and its class to the console. The class of the symbol is
p :name.class
Symbol
. p :name.methods.sizeWe compare the amount of methods that has a symbol and a string. A string has more than twice as many methods than symbol.
p "Jane".methods.size
p :name.object_idSame symbols have same id. Same strings have different ids.
p :name.object_id
p "name".object_id
p "name".object_id
$ ./symbols.rbSample output.
:name
Symbol
79
162
10328
10328
77344750
77344730
Symbols may be used as flags. Constants may be used in such situations as well. In C/C++ we would use enumerations.
#!/usr/bin/rubyA light may be in two states. On and off. For both states we might define symbols.
light = :on
if light == :on
puts "The light is on"
else
puts "The light is off"
end
light = :off
if light == :on
puts "The light is on"
else
puts "The light is off"
end
light = :onThe light is on.
if light == :onThe logic of the program depends on the state of the light variable.
puts "The light is on"
else
puts "The light is off"
end
Symbols are often used as keys in hash containers. They are more efficient that strings.
#!/usr/bin/rubyIn the script we have a domains hash. The keys in the hash are symbols.
domains = {:sk => "Slovakia", :no => "Norway", :hu => "Hungary"}
puts domains[:sk]
puts domains[:no]
puts domains[:hu]
puts domains[:sk]Keys are used to access values of a hash. Here we print three values of a hash.
puts domains[:no]
puts domains[:hu]
$ ./symbols3.rbOutput of the example.
Slovakia
Norway
Hungary
Ruby interpreter stores some refererences internally as symbols.
#!/usr/bin/rubyA Being class is defined. The class has a custom instance variable @is and a say method. These two entities are stored using symbols by Ruby.
class Being
def initialize
@is = true
end
def say
"I am being"
end
end
b = Being.new
p b.method :say
p b.instance_variable_get :@is
p b.method :sayThe
method
method looks up a receiver method with a given name in the b object. We look for a :say symbol. p b.instance_variable_get :@isWe check with a
instance_variable_get
method, if the @is variable is an instance variable of the b object. Internally the variable is stored as a :@is symbol. $ ./symbols4.rbGenerated output.
#<Method: Being#say>
true
All symbols are stored in a symbol table. In the next example, we look at the table. The
all_symbols
method of a Symbol
class returns a array of all symbols from the table. #!/usr/bin/rubyA method, an instance variable and a class variable are created in a Ruby script. We check, if these entities are stored in a symbol table.
def info
"info method"
end
@v = "Ruby"
@@n = "16"
p Symbol.all_symbols.include? :info
p Symbol.all_symbols.include? :@v
p Symbol.all_symbols.include? :@@n
p Symbol.all_symbols.include? :infoWe check, if the :info symbol is in the symbol table. The line returns true.
$ ./symbols5.rbAll three symbols are present in the Ruby symbol table.
true
true
true
Integers
Integers are a subset of the real numbers. They are written without a fraction or a decimal component. Integers fall within a set Z = {..., -2, -1, 0, 1, 2, ...} Integers are infinite.In computer languages, integers are primitive data types. Computers can practically work only with a subset of integer values, because computers have finite capacity. Integers are used to count discrete entities. We can have 3, 4, 6 humans, but we cannot have 3.33 humans. We can have 3.33 kilograms.
Integers are instance objects of a
Fixnum
or a Bignum
class in Ruby. Unlike in languages like Java or C, integers in Ruby are objects. The two classes differ in size. Fixnum numbers are integers up to a certain limit. The limite is machine dependent. Bignum values hold integers outside the range of the Fixnum. If any operation on a Fixnum exceeds its range, the value is automatically converted to a Bignum. The programmer usually does not need to care about the class type of the integers. #!/usr/bin/rubyIn this example, we deal with integers.
p -2
p 121
p 123265
p -34253464356
p 34867367893463476
p 1.class
p 23453246.class
p 234532423563456346.class
p 2345324235632363463456456346.class
p 5 / 2
p 5.div 2
p -2These are integer values of various size. Both positive and negative values.
p 121
p 123265
p -34253464356
p 34867367893463476
p 1.classWe print the classes of these integers. The first two integer are instances of a
p 23453246.class
p 234532423563456346.class
p 2345324235632363463456456346.class
Fixnum
class, the other two are instances of a Bignum
class. p 5 / 2The two lines show the integer division. When we divide two integers using the integer division operator/method, the result is an integer as well.
p 5.div 2
$ ./integers.rbOutput of the example.
-2
121
123265
-34253464356
34867367893463476
Fixnum
Fixnum
Bignum
Bignum
2
2
Integers can be specified in different notations in Ruby. Decimal, hexadecimal, octal and binary. Decimal numbers are used normally, as we know them. Hexadecimal numbers are preceded with 0x characters, octal with 0 character and binary with 0b characters.
#!/usr/bin/rubyIn the code example, we print decimal 122 in all these notation.
puts 122
puts 0x7a
puts 0172
puts 0b1111010
$ ./inotations.rbOuput of the example.
122
122
122
122
If we work with integers, we deal with discrete entities. We would use integers to count apples.
#!/usr/bin/rubyIn our program, we count the total amount of apples. We work with integers.
baskets = 16
apples_in_basket = 24
total = baskets * apples_in_basket
puts "There are total of #{total} apples"
$ ./apples.rbThe output of the program.
There are total of 384 apples
Big numbers are difficult to read. If we have a number like 245342395423452, we find it difficult to read quickly. Outside computers, big numbers are separated by spaces or commas. Ruby allows to separate integers with an underscore, which is simply ignored by the Ruby interpreter.
#!/usr/bin/rubyIn the example, we demonstrate the usage of the underscores.
p 23482345629
p 23_482_345_629
p 23482345629 == 23_482_345_629
p 23482345629 == 23_482_345_629This line shows that the two numbers are equal. It prints true.
$ ./underscore.rbExample output.
23482345629
23482345629
true
Floating point numbers
Floating point numbers represent real numbers in computing. Real numbers measure continuous quantities. Like weight, height or speed. In Ruby, decimal numbers are objects of theFloat
or a BigDecimal
class. The BigDecimal
class is part of the standard library, it is a Ruby core class. In addition, we can use Rational
objects too. We need to understand that decimal numbers are not precise. The official Ruby documentation says it clearly, Float objects represent inexact real numbers.
#!/usr/bin/rubyIn the above program, we work with floating point values.
p 15.4
p 0.3455
p -343.4563
p 12.5.class
p -12.5.class
p (5.0 / 2).class
p 5.fdiv 2
p 12.to_f
p 15.4Here we print three decimal values. Decimal numbers have a decimal point character.
p 0.3455
p -343.4563
p 12.5.classThe above code lines show the types of the numbers. All are floats. Integer division applied on at least one
p -12.5.class
p (5.0 / 2).class
Float
produces a Float
too. p 5.fdiv 2Here we create floating point values by using the floating point
p 12.to_f
fdiv
division method and the conversion to_f
method. $ ./decimals.rbOutput.
15.4
0.3455
-343.4563
Float
Float
Float
2.5
12.0
By default, a decimal number is shown with a maximum 16 numbers after the decimal point. We can control the format of floating point values with the
sprintf
or printf
methods. #!/usr/bin/rubyFormatting decimal numbers.
p 1/3.0
p 1.fdiv 2
puts sprintf "%.4f" % (1/3.0)
puts sprintf "%.7f" % (5/3.0)
p 1/3.0The first line prints a decimal with 16 places after the point. The second line prints two numbers after the point and the third one.
p 13.fdiv 4
p 1.fdiv 2
puts sprintf "%.4f" % (1/3.0)Here we control the number of values after the decimal point using the
puts sprintf "%.7f" % (5/3.0)
sprintf
method. There is a precision in the format specifier of the sprintf
method. It is a number following the % character. The f is a conversion specifier that says we are dealing with floating point values. $ ./formatfloat.rbOutput.
0.3333333333333333
3.25
0.5
0.3333
1.6666667
Ruby supports the scientific syntax of the floating point values. Also known as exponential notation, it is a way of writing numbers too large or small to be conveniently written in standard decimal notation.
#!/usr/bin/rubyThe example shows two decimal numbers written in scientific notation.
p 1.2e-3
p 0.0012
p 1.5E-4
p 0.00015
$ ./scientific.rbThis is the output of the above program.
0.0012
0.0012
0.00015
0.00015
As we have already stated, floating point values are slightly inaccurate. In many situations this precision is sufficient. It is not that important, if our weight is 60kg or 60.000023kg. On the other hand, there are computations in which the precision is paramount. Especially in science or engineering.
Ruby has a
BigDecimal
in the standard library. This class provides arbitrary precision for very large or very accurate floating point numbers. #!/usr/bin/rubyIn this simple example, we compare the precision of a
require 'bigdecimal'
sum = 0
1000.times do
sum = sum + 0.0001
end
p sum
sum = BigDecimal.new("0")
1000.times do
sum = sum + BigDecimal.new("0.0001")
end
puts sum.to_s('F')
puts sum.to_s('E')
Float
compared to a BigDecimal
. require 'bigdecimal'The
BigDecimal
class must be imported. sum = 0We form a loop, where we add a small floatig point value to a sum variable. In the end, there will be a small inaccuracy.
1000.times do
sum = sum + 0.0001
end
p sum
sum = BigDecimal.new("0")We do the same loop with the
1000.times do
sum = sum + BigDecimal.new("0.0001")
end
BigDecimal
values. puts sum.to_s('F')The sum is printed in floting point and engineering notation.
puts sum.to_s('E')
$ ./bigdecimal.rbThe output shows that the computing with
0.10000000000000184
0.1
0.1E0
BigDecimal
is more precise than with Floats
. Let's say a sprinter for 100m ran 9.87s. What is his speed in km/h?
#!/usr/bin/rubyIn this example, it is necessary to use floating point values.
distance = 0.1
time = 9.87 / 3600
speed = distance / time
puts "The average speed of a sprinter is #{speed} km/h"
distance = 0.1100m is 0.1 km.
time = 9.87 / 36009.87s is 9.87/60*60 h
speed = distance / timeTo get the speed, we divide the distance by the time.
$ ./speed.rbThis is the output of the speed.rb script.
The average speed of a sprinter is 36.4741641337386 km/h
Rational Numbers
Ruby supports rational numbers. A rational number is an exact number. Using rational numbers we avoid rounding errors. In Ruby, a rational number is an object of theRational
class. We can create rational numbers with a special to_r
method from some objects. A rational number is any number that can be expressed as a fraction of two integers a/b , where b!=0. Since b may be equal to 1, every integer is a rational number.
#!/usr/bin/rubyThis example shows a few rational numbers.
puts 2.to_r
puts "23".to_r
puts 2.6.to_r
p Rational 0
p Rational 1/5.0
p Rational 0.5
puts 2.to_rHere we convert a 2 integer to 2/1 rational number using the
to_r
method. p Rational 0.5We create a rational number with the
Rational
class. $ ./rational.rbOutput of the example.
2/1
23/1
5854679515581645/2251799813685248
(0/1)
(3602879701896397/18014398509481984)
(1/2)
The nil value
Ruby has a special valuenil
. It is an absence of a value. The nil
is a singleton object of a NilClass
. There is only one nil
; we cannot have more of it. #!/usr/bin/rubyAn example with the
puts nil
p nil
p $val
p [1, 2, 3][4]
p $val1 == $val2
nil
value. puts nilWe print the
p nil
nil
value to the console. The puts
method prints an empty string; the p
method prints 'nil' string. p $valWhen we refer to a global variable that was not set, we get the
nil
value. p [1, 2, 3][3]In this code line, we refer to the fourth element of a three-element array. We get
nil
. Many methods in Ruby return nil
for invalid values. p $val1 == $val2The line returns true. This is a consequence of the fact, that the
nil
value is a singleton object of a NilClass
. $ ./nilvalue.rbOutput.
nil
nil
nil
true
Strings
A string is a data type representing textual data in computer programs. A Ruby string is a sequence of unicode characters. A string is an instance of theString
. String literals are characters enclosed in double or single qoutes. A string is a very important data type. It deserves a dedicated chapter. Here we just drop a small example.
#!/usr/bin/rubyIn this program, we work with Ruby strings. We use the
p "Ruby"
p 'Python'
p "Ruby".size
p "Ruby".upcase
p 23.to_s
p
method for printing, because we see the data type on output. p "Ruby"We print two string literals to the terminal. The first literal is enclosed in double quotes, the second literal in single quotes.
p 'Python'
p "Ruby".sizeThese two lines call two string methods. The
p "Ruby".upcase
size
method returns the size of the string. 4 characters in our case. The upcase
returns the string in uppercase letters. p 23.to_sThe
to_s
method converts an integer to a string. $ ./strings.rbIn the output we see strings enclosed in quotes. This is the consequence of using the
"Ruby"
"Python"
4
"RUBY"
"23"
p
method. The print
and puts
methods don't do this. Arrays and hashes
Arrays and hashes are collections of objects. They group objects into one place.Arrays are ordered collections of objects. Hashes are collections of key-value pairs. We will have a single chapter for both arrays and hashes. The following example just gives a quick look at both containers.
#!/usr/bin/rubyThis is a quick example for a Ruby array and hash.
nums = [1, 2, 3, 4]
puts "There are #{nums.size} items in the array"
nums.each do |num|
puts num
end
domains = { :de => "Germany", :sk => "Slovakia",
:us => "United States", :no => "Norway" }
puts domains.keys
puts domains.values
nums = [1, 2, 3, 4]These lines create an array having 4 items. In the second line we count the items of the array and incorporate it in the message. Later we go through the array with the
puts "There are #{nums.size} items in the array"
nums.each do |num|
puts num
end
each
method and print each of the elements to the console. domains = { :de => "Germany", :sk => "Slovakia",Here we create a Ruby hash. Then we print its keys and values.
:us => "United States", :no => "Norway" }
puts domains.keys
puts domains.values
$ ./arrayshashes.rbExample output.
There are 4 items in the array
1
2
3
4
de
sk
us
no
Germany
Slovakia
United States
Norway
Conversions
We often work with multiple data types at once. Converting one data type to another one is a common job in programming. Type conversion or typecasting refers to changing an entity of one data type into another. There are two types of conversion. Implicit and explicit. Implicit type conversion, also known as coercion, is an automatic type conversion by the compiler. Ruby has only explicit conversion.Ruby has built-in conversion methods like
to_i
, to_s
or to_f
. The Kernel
module has a few public methods for doing conversions, like Integer
, String
or Float
. These methods should not be confused with Ruby classes. #!/usr/bin/rubyHere we show the
p Array(1..6)
p Complex 6
p Float 12
p Integer "34"
p Rational 6
p String 22
Kernel
conversion methods. $ ./convertmethods.rbOutput of the example.
[1, 2, 3, 4, 5, 6]
(6+0i)
12.0
34
(6/1)
"22"
#!/usr/bin/rubyIn the above example, we show some numerical conversions. Some Ruby objects have
p "12".to_i
p 12.5.to_i
p nil.to_i
p 12.to_f
p "11".to_f
p nil.to_f
to_i
and to_f
methods which convert objects to integers and floats, respectively. p "12".to_iIn this code we convert a string, decimal and nil to integer type.
p 12.5.to_i
p nil.to_i
p 12.to_fThese three lines convert an integer, string and nil to an object of decimal data type.
p "11".to_f
p nil.to_f
$ ./conversions.rbExample output.
12
12
0
12.0
11.0
0.0
The second example shows some string conversions.
#!/usr/bin/rubyIn the above example we convert strings to objects of different data types.
p "12".to_i
p "13".to_f
p "12".to_r
p "13".to_c
p "Jane".to_sym
v = "Ruby Python Tcl PHP Perl".split
p v.class
p "12".to_iHere strings are converted to integer, decimal, rational and complex numbers.
p "13".to_f
p "12".to_r
p "13".to_c
p "Jane".to_symA string becomes a symbol.
v = "Ruby Python Tcl PHP Perl".splitHere we use a
p v.class
split
method of the String
class to convert a string to an array. $ ./stringconv.rbAnd this is what we get.
12
13.0
(12/1)
(13+0i)
:Jane
Array
The next small example shows array hash conversions.
#!/usr/bin/rubyIn the example code, we create a hash and covert it to array. Then we create an array and convert it to a hash.
h = {:de => "Germany", :sk => "Slovakia"}
p h.to_a
a = [:de, "Germany", :sk, "Slovakia",
:hu, "Hungary", :no, "Norway"]
p Hash[*a]
h = {:de => "Germany", :sk => "Slovakia"}A hash is created and converted to an array using the
p h.to_a
to_a
method. a = [:de, "Germany", :sk, "Slovakia",An array is created and converted to a hash. The asterix in this context is a splat operator. It is one of a Ruby idioms taken from Perl. It splits an array into a few variables.
:hu, "Hungary", :no, "Norway"]
p Hash[*a]
$ ./h2a.rbOutput.
[[:de, "Germany"], [:sk, "Slovakia"]]
{:de=>"Germany", :sk=>"Slovakia", :hu=>"Hungary", :no=>"Norway"}
In this part of the Ruby tutorial, we covered data types and their conversions.
0 comments:
Post a Comment