# Primitive vs Complex Types

You’ve heard me talk all quarter about types and how important they are, and I’ve kept promising how we’ll talk about the differences between primitive and non-primitive types “later”. Well, at long last, “later” is now.

As a brief review, what are the “primitive” types?

• Boolean
• String
• Integer
• Floating point
• NoneType

What are the non-primitive types? So far, we’ve only seen two.

• List
• Function

So let’s start this experiment with a puzzle. Guess the output of the code.

``````def amurrica(some_parameter):
some_parameter = 5

some_nice_parameter = 3

a = 7
print a
amurrica(a)
print a
print a
``````

So what is the output of this? If you guessed

``````7
7
7
``````

You’d be right! So what gives? Obviously, functions `amurrica` and `canada` are trying to change `a`, but why don’t they? This goes back to how parameters work in functions.

Parameters are copied, left to right, from the actual parameter to the formal parameter; this is called call by value. Wow, that’s a lot of terminology, so let’s break that down.

What’s an actual parameter? An actual parameter is the value being put inside the parentheses when the function is being called. So in this code, `a` is the actual parameter.

The formal parameter, on the other hand, is what is inside the `def` statement. It’s what the function calls whatever is being passed to it. So for the function `amurrica`, `some_parameter` is the formal parameter. Naturally, `some_parameter`’s scope is limited to inside of the function `amurrica`.

So call by value copies the value from the actual parameter to the formal one. Which means that `some_parameter` is a completely different variable that has a copy of whatever value `a` has. So when `amurrica` and `canada` try and change the formal parameters, they’re not changing `a`; they’re just changing the some copy of `a`.

Make sense? That’s call by value.

Now let’s take a look at this code instead.

``````def amurrica(some_parameter):
some_parameter.append("EVERYTHING CUZ USA BE AWESOME, SON")

some_parameter.append("We have awesome Hockey, and stuff")

freedom = []
print freedom
amurrica(freedom)
print freedom
freedom = []
print freedom
``````

Now what’s the output? You guessed it.

``````[]
["EVERYTHING CUZ USA BE AWESOME, SON"]
["We have awesome Hockey, and stuff"]
``````

What!? This time the parameter changed? Before you drown your computer in a lake for fear of witchcraft, let’s look at the types of the parameters being passed. As you see, the first time we passed a primitive type. This time, we’re passing a non-primitive type. So what happens when you pass a parameter that’s non-primitive?

Here, a reference for the actual parameter is given to the formal parameter. What’s a reference? A reference is the location in your computer’s memory where the actual variable exists. This is called call by reference.

In this case, `some_parameter` holds the actual address of `freedom`; so when `some_parameter` makes changes, it makes changes to `freedom`.

Here’s the essence of the difference between primitive and complex types: primitive types are call by value, while complex types are call by reference.

But what if we wanted to change the value of a primitive type? Why not pack it in a list? Next week we’ll talk about a better way to do this, but for now this is a good enough.