The Beginner's Guide to Type Coercion: A Practical Example

Throughout this series of articles, we've been talking about type coercion, how it differs from type conversion, and how it performs in dynamically typed languages.

If you're just joining the series, check out the earlier articles to make sure you're up to speed with where we are right now:

  1. Data Types
  2. What is Type Coercion? 

Whereas the other article focused on weakly typed languages and data types at a high level, we're going to be looking at some specific examples of type coercion in a weakly typed language, and the pitfalls that we may experience without knowing how type coercion works and how it can backfire.

Specifically, we're going to be looking at several examples using JavaScript, and though the outcomes you may see through the use of the examples won't necessarily translate 1:1 in other languages, it will still provide a set of tests that you can performing in whatever you're using in your day-to-day or in your side projects and evaluate the results that you're seeing.

The Rules of Comparison

Arguably, one of the most common problems that occurs in weakly typed languages comes whenever we're making comparisons. Sure, there are other times that expecting a variable to be one type when it's really another can negatively affect us, but the most common problems occur whenever we're performing some type of comparison.

These comparisons can come in the form of equality operations, conditional operations, bitwise operations, or during switch/case operations. 

As mentioned in previous articles in this series, different languages have different ways in which they go about coercing data types so the examples that we're looking at in this article may differ a little bit in the work that you do. 

That is, we're going to be looking at these examples using JavaScript since it's such a widely used language, but the rules are still applicable in other languages - it's just that other languages may place a different priority on one data type over another so the results of coercion may be a bit different.

So with that said, let's get started at looking at how JavaScript handles comparisons between data types using the equality operator (==), the strict equality operator (===), and when using values such as undefined and null.

Null and Undefined

Before looking at comparisons among different data types, let's take a moment to note that, in JavaScript, undefined and null are two different types of values. As if that's not enough, it can get even more confusing when comparing the two values.

First, note the following:

  • If you were to execute typeof( undefined ) in the console, then the result would be undefined.
  • If you were to executed typeof( null ) in the console, then the result would be object.

Next, if you were to declare a variable without actually assigning it a value, and you were to evaluate its type, then you'd see undefined.

Next, let's say that we opt to initialize the variable with an null value. If you were to evaluate the variable using typeof you'd be given an object result.

Confusing? Recall from earlier that that in JavaScript, null is an object where undefined is its own type - undefined

With that said, now we can actually look at why comparisons can become difficult whenever we perform comparisons on values without explicitly knowing their type.

Comparisons

Throughout this section, we're going to take a look at the results of comparing values that are of different types, but see how they are evaluated against one another using both equality comparisons and strict equality comparisons.

Note that all of the examples that we're listing below should be able to be executed within a browser's console such as Firebug or Chrome's Developer Tools. 

For starters, we'll begin with undefined and null.

Notice that in the first case, the equality operator is returning a value of the comparison after performing type coercion. That is, the interpreter is making its best guess as to what we mean when performing this comparison.

In the second case, we're using the strict equality operator. In this case, no type coercion occurs. Instead, it's taking the values exactly as they are and comparing them.

Next, let's take a look at declaring a variable, not assigning it a value, and then running a comparison.

As you can see, thing's start to get a little more complicated when we begin to declare and compare variables with or without values.

Once we start introducing strings, numbers, and boolean values it can get even more complicated. First, let's start with strings and numbers. We'll begin by declaring a variable with a string value of 42 and a number with the 42 and then we'll perform our comparisons. 

Again, notice in the first case, the interpreter attempts to coerce the values from the variables and then compare them. In the first case, it works - we're comparing a string value of 42 to a number value of 42, but when we use the strict equality comparison and get false.

The second case is technically more accurate because the first value is a string and the second is a number. Comparing two values of different types should always yield false.

Though we've taken a look at this in a previous article, what about the case of numbers and booleans?

At this point, you should begin noticing a pattern: whenever you're comparing values of different types, JavaScript may correctly coerce values, but it yields the most accurate result when you use the strict equality operator.

Finally, let's look at an example that combines strings, numbers, and booleans.

Note that these are basic comparisons; however, when done in the context of an if/else or if/else if/else you see how it can disrupt the flow of control through the conditional.

Anything Else?

Note that when performing logical operations such as && and || as well as bitwise operators such as & and | that the coercion rules still apply. To that end, you want to make sure that when you're performing those operations, use values of exactly the same type to get the most accurate results.

Otherwise, coercion may result in a false positive or a false negative.

Conclusion

This completes our cursory, beginner's look at data types and type coercion in a dynamically typed languages. Ultimately, the rules of thumb are to always use strict equality operators and to make sure that the variables with which you're working are of the same type. If you're not sure, you can always explicitly convert them using strategies that we outlined earlier in the series.

Throughout this series, we've taken a look at how types vary and behave from strongly typed languages to weakly typed languages. We've looked at how casting and coercion differ, and we've looked some of the potential pitfalls that this may result in relying too much on the interpreter or the compiler when performing comparisons.

Finally, we took a look at some strategies for how to write more defensive code by making sure that we have the data type that we need, and how to use strict comparison operators to ensure that we get the results that we need.

As mentioned previously, we've used JavaScript for the purposes of our examples in this serious of articles, but other weakly typed languages are subject to the same pitfalls. How they prioritize their coercions vary, but the strategies outlined in this series should help with writing more resilient code when working in weakly typed languages.  

Tags:

Comments

Related Articles