Swift for Ruby Devs: Type Systems

When embarking on your journey to learn Swift, one of the major things you'll first notice is the difference in type systems between Swift and Ruby. Having a clear understanding of these differences will help you better understand how to write Swift and why we must do things a little differently.

Differences: Dynamically typed Vs Statically typed



If you're a Ruby developer, you live in a dynamically typed world, free to write expressive code without having to specify the type of object a variable will contain or the type of object a method will take in as an argument. You're probably not used to thinking in terms of types when designing your interfaces; this is because Ruby doesn't really care about the types of your objects as long as they respond to the method (or message) being sent to them. Technically, an object's type is defined by it's messages not by the class of the object. Dynamic typing means that the type of a thing can change through the course of a program because the type isn't determined until the thing is used. This allows us, for example, to define a variable as a string and later redefine that variable as any other type of object.

Example:

my_variable = "Here's my string"  
  => "Here's my string"

my_variable = SomeClass.new  
  => #<Class:0x007fcdac4ab470>



Swift, on the other hand, is a statically typed language. This means we must declare the types of our objects in our code so that the complier can use these type declarations to check for type errors when compiling our program. In Swift, though, you don't have to explicitly declare an object's type if you set an initial value for your variable. The compiler will then infer the type of the object at compile time (more on this later). Here, the type of a thing must be determined when designing your software as opposed to during runtime like in Ruby. This means that once a type is declared, it cannot later change.

Example:

var myVariable = "Here's my string"  
  => "Here's my string"

myVariable = 123  
  => error: cannot assign value of type 'Int' to type 'String'


Differences: Type Safety



Type safety refers to the extent to which a programming language enforces which operations can be performed on certain types. A language is type-safe if the only operations that can be performed on a type are those that are accepted by that type. Swift is a type-safe language, Ruby is not. In a type-safe language, you have to be clear about the types of values your code can work with. For example, you have to be clear about the type of object a variable will contain or about the types of objects a method will take in as arguments. You must also be clear about the type of object a method will return. Therefore, if you declare a variable to be of type String, you can't later change it to an Integer. If a method expects to receive arguments of type Float, you can't pass in arguments of type Double. If you attempt to do so, the compiler will catch these mismatches in types and flag them as errors.

In Ruby, you've never had to declare the type of object a variable will contain, the types of objects a method will accept, or the type of object a method will return. As discussed earlier, Ruby doesn't really care about the type of an object as long as it responds to the message being sent to it. Here, objects are defined by their messages, not necessarily by their type. Every class defines a contract, it's public interface. Thinking of it this way, the only operations that can be performed on a class are those that are part of it's public interface. But unlike a type-safe language like Swift, we don't have to be explicit about the types of values our code can work with.


Similarities: Strongly typed and Type Inference



Two things to note about these languages is that they're both strongly typed languages and use type inference to infer the type of an object so that we don't have to explicitly declare it. A strongly typed language means that it'll error out at runtime or during compile time if an argument passed to a method isn't the expected type.

Example:

my_number = "3"  
  => "3"

my_number + 4  
  => TypeError: no implicit conversion of Fixnum into String
var myNumber = "3"  
  => "3"

myNumber + 4  
  => error: binary operator '+' cannot be applied to operands of type 'String' and 'Int'



As you can see from the examples above, we get an error when the + method implemented by String is passed an integer rather than another string. Also note that we are using type inference in both of these examples. When declaring our my_number or myNumber variables, we don't have to explicitly declare the type of object that'll be contained in these variables. Type inference refers to the ability to automatically deduce the type of a variable or type signature of a method, either at compile time or at runtime, by examining the object stored inside the variable or the objects that are passed to a method as arguments.

Side Note: In Swift, we can explicitly declare a type if we want to but it isn't required.

Example:

var myNumber: String = "3"  


Similarities: Object Oriented Programming



Another similarity about Swift and Ruby is that they're both object oriented programming languages. Concepts like inheritance, subtyping, classes, and objects, are all present in Swift. You can transfer your knowledge of object oriented design principles such as single responsibility, open-closed, liskov substitution, interface segregation, and dependency inversion (SOLID), to help you design Swift applications that are straight-forward to change and maintain.


Summary



Making the jump from Ruby to Swift can be relatively easy if you understand the major differences between both programming languages. Swift, being a statically typed and type-safe programming language, forces you to be more clear about the types of objects your program will work with and to think more deliberately about these types as you're designing your interfaces. Static typing has it's benefits and shouldn't be immediately disregarded due to the fact that we must declare types or due to the immutability of types. The benefits of static typing, such as having a compiler check for type errors, will become more clear as we start to learn Swift. Coming from a dynamically typed world, this will also help you become a better programmer as you'll be exposed to different programming concepts. Allowing you to draw comparisons between the two and choose the right tool for the job at hand.

One of the most notable similarities of these languages is that they're both object oriented, so the philosophies in designing your interfaces are the same. Equipped with this knowledge, we can now start digging into Swift's syntax, drawing comparisons between it's similarities with Ruby and understanding it's differences. In a later post, we'll dive into Swift's syntax and discuss the basics such as variables, constants, operators, collections, and much more.