49 Days of Ruby: Day 23 - Type Checking

Ben Greenberg - Apr 19 '21 - - Dev Community

Welcome to day 23 of the 49 Days of Ruby! 🎉

Yesterday, we discussed duck typing in Ruby. If duck typing is the idea that what an Object is doesn't really matter as long as it responds to a method, then types and type checking is the opposite.

Traditionally, Ruby is not a language concerned with types. Ruby is part of a family of languages that do not need a type to be defined in the code. Those languages include PHP, JavaScript, Python, and others.

There are other languages that do require types to be defined as part of writing the code. Those languages include Java, C#, TypeScript, and others.

However, there has been a movement recently to introduce types to these non-typed languages. Each of the example languages above that do not have types now have their own implementations. (TypeScript is the language offshoot of JavaScript for types.)

Before we look at Ruby's implementation, let's ask the first question: What is a type?

What is a type?

Let's say I had the following in my code:

"Hi there! This is some text."
Enter fullscreen mode Exit fullscreen mode

What would you instinctively say its type is?

If you said a String you would be right!

The type of the above text is indeed a String.

That's what we mean when we talk about types. How about this:

5
Enter fullscreen mode Exit fullscreen mode

That number is an Integer. Another example:

5.4
Enter fullscreen mode Exit fullscreen mode

That number with a decimal point is a Float.

When we say we are enforcing types, what we mean is we are defining during the time we write the code what data type the object or method is, and once it is defined, it cannot be changed. In other words, ducks from the land of duck typing need to exit the room.

Defining Types in Ruby

The most recent major release of Ruby, version 3.0, includes support at the language level for types.

What does it look like? This is an example from the README for RBS the gem used for static typing in Ruby:

class User
  attr_reader login: String
  attr_reader email: String
end
Enter fullscreen mode Exit fullscreen mode

By now, the code above will mostly look familiar. We have a class instantiation of User, followed by two attr_reader declarations.

Did you notice the addition of the : and the String in each attr_reader?

That's the syntax for declaring the type of those attributes. In this example, they are being declared as strings.

You can also declare types for a method, more from the example:

def initialize: (login: String, email: String) -> void
Enter fullscreen mode Exit fullscreen mode

Here we have the #initialize method for the User class. We see that it accepts two parameters: login and email. They match what we declared in the attr_reader declarations before.

What about the -> syntax? That's how one declares the type of the return value of the method. Every method returns something. By stating void we are saying that the value can be nil and we ought not to care about it.

There is so much more we can say about types in Ruby, but we're going to end it here today! For further exploration check out:

See you tomorrow!

Come back tomorrow for the next installment of 49 Days of Ruby! You can join the conversation on Twitter with the hashtag #49daysofruby.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .