SBN

Are You Checking Types?

The dominoes game is simple,
there are 28 tiles (standard version),
each one with a unique combination
of two numbers of pips between 0 and 6.
The game’s objective is to be the first player
to place all the own tiles on the table.
For this,
each player takes turns to place a tile
adjacent to those already on the table
as long as the number of pips matches.
Most people believe
that dominoes is more a game of luck
than anything else.
In fact,
it’s a game of strategy.
A good player checks the tiles on the table,
counting how many pieces
of a certain number of pips
are already placed
and which ones the opponents have.
By knowing this,
they can choose the best tile to place
and force the opponents
to play in a certain way.
So,
if you always bite the dust in the dominoes,
maybe it’s because you’re not checking enough.

Ludopathy

We can relate the coding in Python
with a game of dominoes.
The script is the tiles on the table,
so the players are the developers.
The tiles would be small pieces of code.
Again,
developers take turns to place tiles.
However,
the goal now is that all players win!
So,
they can put in a single script
all the code tiles they have.
The final result would be a perfectly coupled script
specially assembled to do a certain task.
But if everyone can win,
then everyone can lose.
And if your developers’ team is already used
to constantly losing games,
then,
just like in dominoes,
you’re not checking enough!

Family playing dominoes

Figure 1. Dominoes can be compared with the development activity.

Bankruptcy

There are many reasons
why you can lose in the coding-in-Python game,
but not checking well is one of the most common.
Specifically,
I’m talking about checking the type of variables
or data structures in your code.

For example:

Add integers method in Python.

def add_integers(a, b):
  return a + b

add_integers(2, 3) # 5

At first sight,
the function seems fine.
It works as expected,
but it has a huge problem.
In the following example,
we’ll use the same \add_integers\ method,
but we’ll make a change.

Adding strings.

add_integers('2', '3')  #  '23'

The code still works as it should be,
but it’s not the result we expected;
we managed to “cheat” the function
to add strings instead of integers.

I know this doesn’t say much,
but I’ll show you the destructive potential of this feature
with another example using the same
add_integers function:

A more complex application with no variable typing.

def taxes_calculation(apple_price, taxes_rate):
  return apple_price * taxes_rate

def apples_sale(n_apples, apple_price):
  initial_price = n_apples * apple_price
  taxes = taxes_calculation(initial_price, 0.16)
  result = add_integers(initial_price, taxes)
  return result

apples_sale(3, 20) # 69.6

# Nothing bad until here, but what if we…

apples_sale('3','20') # TypeError: can't multiply
sequence by non-int of type 'str'

Now you can cry.
Your apple sales business went bankrupt
by simply changing the type of input variables.

Oh, the irony!

Dear reader,
if you’re a pythonista who doesn’t allow
yourself to be surprised so easily,
you may be saying:
“Wait, what?
Python is a program with dynamic typing;
that’s its point,
I don’t have to define the type of variables
because the interpreter can understand what the type is.”

Yes,
that’s true,
but the interpreter is not guilty of having an entanglement
of thousands of methods
that depend on each other.
The interpreter is not guilty
that any method can modify the state,
including the variable type.

I’ll give you the solution now:
Go functional and set the type of your variables!
If you want to know how to do that,
keep reading.

Canard à l’orange

Many scholars call the typing in Python “duck typing.”
The name comes from this premise:
“If it goes like a duck
and it quacks like a duck,
then it must be a duck.”
In this way,
we understood that Python knows
what the type is
by analyzing the behavior
and attributes of a variable.
Honestly, in Fluid Attacks,
we prefer the Canard à l’orange
(“duck with orange” in French)
instead of living with it in our code.

How to pluck a duck?

We already know why
we shouldn’t let the interpreter choose what type
of variable we’re working with.
It may sound a little laborious
to have to type each variable,
but this task is easy in Python 3:

Add integers method with typed variables.

def add_integers (a: int , b: int) -> int:
   return a +  b

add_integers(2 , 3) # 5

Let’s see if this solves the problem:

The cruel reality.

add_integers('2', '3') # '23'

I lied to you again.
Typing variables in Python doesn’t do anything
to how the code is executed.
Python is like a child
who believes everything you tell him;
no matter if you set the type or not,
it’ll continue to obey.

Mypy to the rescue

Setting variable types is useful
when we use a tool that has become popular
among the pythonistas: mypy.
Mypy is a static type checker.
It uses the type hints defined in the
code to validate that these hints are met
in the parts of the code
where the variables are used.
This tool runs separately from the execution of the code.

You can use the following command to install mypy in Python 3:

Mypy installation.

python3 -m pip install mypy

Now,
we just have to make sure
that the code we want to check
is saved in a script
and then run the following command:

Command to use mypy.

python3 -m mypy name_of_my_file.py

Let’s go back to the example of <<\adding-integers\>>
and save it in a script called add_integer_method.py.
Now we use mypy:

Using mypy in a known script.

python3 -m mypy  add_integer_method.py
#... No output

If there’s no output when running the command,
the code is correct
and can be executed.
Now we add the <<\adding-strings, adding strings example\>>
to the file
and run mypy again:

Warnings.

$ python3 -m mypy  add_integer_method.py

# add_integer_method.py:4: error: Argument 1 to "add_integers"
has incompatible type "str"; expected "int"
# add_integer_method.py:4: error: Argument 2 to "add_integers"
has incompatible type "str"; expected "int"

Eureka!
Mypy was able to discover that we set a string
into a method that was defined with integer type inputs.
Here we use a very small and maybe obvious example,
but imagine applications of thousands of code lines.
Now,
with a single command,
we can check the variable types.

Conclusions

We demonstrated the importance of setting the variables’ types
that we’ll use
and showed how fatal it’s to not check them.
Mypy is a useful tool in any development activity,
but it’s especially powerful in projects
where more than one developer contributes.
With mypy, we can debug easier
or ensure that code with the wrong types
is not deployed to production.
Of course,
Mypy is not a straitjacket;
this library doesn’t impose anything on us;
we decide to ignore or solve the warnings it shows us.
Finally,
we make the recommendation to implement
functional code in your programs;
this will make your code more durable,
cleaner and easier to debug.
This programming paradigm takes on more versatility
when merged with tools like mypy,
which turns very tedious processes into a matter of seconds.
If you still don’t know much
about functional programming in general
or functional programming in Python,
we invite you to read the posts
“Why We Go Functional?”
and “Road to Functional Python”.
You already have the knowledge,
so will you check types?

*** This is a Security Bloggers Network syndicated blog from Fluid Attacks RSS Feed authored by Oswaldo Parada. Read the original post at: https://fluidattacks.com/blog/are-you-checking-types/