Magic numbers are one of those bad practices in programming that have somewhat of a weird name. After all, folks generally like magic, so it’s unclear what’s so bad about them. Fortunately, today we’ll talk about what a magic number is and how to remove them from your programs.
Table of Contents
- Introducing Magic Numbers
- Removing Magic Numbers From Code
- Benefits of Eliminating Magic Numbers
- The Power of Best Practices
Introducing Magic Numbers
Chances are you’ve found yourself here because a nice static analysis tool like a linter told you your code contains a magic number. Without context, that term is pretty weird. After all, nothing about programming is magic, though it can feel like it sometimes, so what’s the big deal?
In short, a magic number is a numerical value (typically excluding 0 and 1) that has an unclear purpose. For example, we might be computing the area of a circle with an approximation of pi as follows:
def area_of_circle(radius: float) -> float: return 3.14 * radius * radius
In this example, our approximation of pi is what would be considered a magic number. It’s a problem because it’s not exactly clear what purpose 3.14 serves in our calculation. In other words, it seemingly spawned from nothing.
Surely, a lot of folks know the area formula for a circle or the value of pi, so they could probably figure it out from context. That said, given how bad our brains are at holding information in short term memory, we should really be trying to leave as little as possible to inference.
As a result, a magic number is considered bad practice because it makes code harder to reason about. Therefore, we should find ways to remove them from our code whenever possible.
Removing Magic Numbers From Code
In our previous example, we had a method which computed the area of a circle given some radius:
def area_of_circle(radius: float) -> float: return 3.14 * radius * radius
The problem as already discussed is that 3.14 is a magic number. To get rid of the magic number, we need to make a constant for it:
PI = 3.14 def area_of_circle(radius: float) -> float: return PI * radius * radius
The trick is to take the seemingly random value and give it some context by providing it a name. In this case, we stored the value of 3.14 in a constant named PI.
Benefits of Eliminating Magic Numbers
Given how trivial the examples were in this article, you might conclude that addressing magic numbers is a waste of time. Let me take a moment to try to convince you of the benefits.
First, as mentioned already, one of the major benefits of removing magic numbers from your code is readability. Numbers can have many meanings which can be cleared up with a simple name. This will save you time in the future when you inevitably have to make sense of your own code.
Second, another major benefit of removing magic numbers is inadvertently following the Don’t Repeat Yourself (DRY) principle. Under this principle, you try to limit duplication of code (e.g., by not using the same magic number multiple times). A nice consequence of following DRY is creating a single point of control where a magic number can be changed as needed. For example, imagine if we had both a circle area method and a circle circumference method:
def area_of_circle(radius: float) -> float: return 3.14 * radius * radius def circumference_of_circle(radius: float) -> float: return 2 * 3.14 * radius
If for some reason we decided we wanted pi to a few more decimal places, we would have to update it twice, once for each method. Alternatively, we could use our constant to update it once in both places:
PI = 3.14159 def area_of_circle(radius: float) -> float: return PI * radius * radius def circumference_of_circle(radius: float) -> float: return 2 * PI * radius
If neither of these benefits seem worth it to you, I recommend turning off that particular warning on your linter. What you absolutely should not do is find some creative workaround. For example, maybe you have a list where you know the exact indices of the contents:
cards = ["jack", "queen", "king", "ace"] ace = cards[3]
One thing you shouldn’t do is something like this:
cards = ["jack", "queen", "king", "ace"] ace = cards[1 + 1 + 1]
Sure, adding one three times sums to three, but I would argue this solution is even more confusing than using the magic number directly. Unless you’re trying to purposely obfuscate your code, this is moving in the wrong direction.
The Power of Best Practices
While best practices vary from language to language and team to team, they’re generally for the greater good. In this case, magic numbers are one of those warnings that actually hint at ways you can improve your code.
With all that said, I don’t recommend following rules for the sake of following rules. Very few rules in software development have been empirically studied, so use your best judgment and avoid falling prey to dogma.
Finally, I know many of the folks reading this will be my Java students, and I don’t want to leave you hanging, so here’s how you remove a magic number in Java:
public static double AreaOfCircle(double radius) { // Create a local constant using the final keyword final double pi = 3.14; return pi * radius * radius; }
Or alternatively:
// Create a global constant using the final keyword private static final double PI = 3.14; public static double AreaOfCircle(double radius) { return PI * radius * radius; }
With that said, that’s all I have for us today. If you found this article useful, I’d appreciate it if you gave it a share. Likewise, you can find other ways to support The Renegade Coder here.
If you’re looking for more to read, look no further than the following list:
- Can You Actually Return Multiple Values From a Function in Python?
- How to Get Better at Programming: Lessons from Blogging
- Understanding the Number Theory Behind RSA Encryption
Otherwise, thanks for stopping by! See you next time.
Recent Posts
VS Code is a wonderful IDE that I use everyday. Sometimes though, little issues crop up that require you to customize your installation. Today, we'll talk about one of your options for customization:...
It's 2025, and we're kicking off the year with some huge news! The Sample Programs repo has hit 1,000 code snippets. Let's talk about them.