# Conditionals and booleans
## More Functions Practice: Cost of pens
Imagine that you are trying to compute the total cost of an order of pens with slogans (or messages) printed on them. Each pen costs 25 cents plus an additional 2 cents per character in the message (count spaces as characters for now).
First, let’s write two expressions that do this computation, just to make sure we understand how it should work:
```python
# if ordering 3 pens that say "wow"
> 3 * (0.25 + (string-length("wow") * 0.02))
# if ordering 10 pens that say "smile"
> 10 * (0.25 + (string-length("smile") * 0.02))
```
Having a clear idea of the computation you want to do makes it much easier to write a function to do it. How do we figure out a function that would correspond to these two expressions? We find the places where the two functions are different, circle them, and label each of them with a different unique name. These names become the parameters of the function.
```python
fun pen-cost(num-pens :: Number, message :: String) -> Number:
doc: "cost of ordering pens with slogans"
num-pens * (0.25 + (string-length(message) * 0.02))
end
```
The initial expressions we developed give rise to our examples:
```python
fun pen-cost(num-pens :: Number, message :: String) -> Number:
doc: "cost of ordering pens with slogans"
num-pens * (0.25 + (string-length(message) * 0.02))
where:
pen-cost(3, "wow") is 3 * (0.25 + (string-length("wow") * 0.02))
pen-cost(10, "smile") is 10 * (0.25 + (string-length("smile") * 0.02))
end
```
What are other good examples to check here? Ordering 0 pens and pens with empty messages are both good examples. You don’t have to check negative numbers of pens or messages that aren’t strings, though – those fall outside the expected “contract” of the function (we’ll discuss how to properly handle the negatives later).
Once you are comfortable with the idea of writing functions, you would skip the circle-and-label step, and just jump directly to writing the expression with the parameters in place. Use the circle-and-label technique as needed to get yourself to that point.
## Pen costs, revisited
### Shipping costs
We’ve got a function now that computes the cost of pens, but our pen company has to account for another cost: shipping! It turns out that shipping costs $10 for orders of $50 or less, and $20 for orders of more than $50. So we’re going to write a function that takes the subtotal (i.e. the cost of the pens on their own) and adds on the shipping.
```python
fun add-shipping(subtotal :: Number) -> Number:
...
end
```
Before we write the function, we can write some examples and a docstring.
```python
fun add-shipping(subtotal :: Number) -> Number:
doc: "add shipping amount to subtotal"
...
where:
add-shipping(1) is 1 + 10
add-shipping(50) is 50 + 10
add-shipping(50.01) is 50.01 + 20
add-shipping(100) is 100 + 20
end
```
`add-shipping` adds a different amount depending on its input. In order to do that, we’ll need a feature we haven’t seen before: *conditionals*. We’ll use a conditional like this:
```python
fun add-shipping(subtotal :: Number) -> Number:
doc: "add shipping amount to subtotal"
if ...: # subtotal is $50 or less
subtotal + 10
else:
subtotal + 20
end
where:
add-shipping(1) is 1 + 10
add-shipping(50) is 50 + 10
add-shipping(50.01) is 50.01 + 20
add-shipping(100) is 100 + 20
end
```
### Boolean expressions
What’s an expression that says “the subtotal is $50 or less?” Expressions that answer yes-or-no questions belong to a new type that we haven’t seen before: `Boolean`. There are two `Boolean` values: `true` and `false`. We can compare numbers and get `Booleans`:
```python
> 30 <= 50
> 100 <= 50
> 100 > 50
```
Let’s say we have a number, `subtotal`. What are some questions we might ask about it?
```python
> subtotal = 70
> 50 <= subtotal
> subtotal < 100
> (50 <= subtotal) and (subtotal < 100) # what happens if we leave off the parentheses?
> (subtotal <= 50) or (subtotal >= 70)
```
So in order to complete `add-shipping`, we can use these comparison operators.
```python
fun add-shipping(subtotal :: Number) -> Number:
doc: "add shipping amount to subtotal"
if subtotal <= 50:
subtotal + 10
else:
subtotal + 20
end
where:
add-shipping(1) is 1 + 10
add-shipping(50) is 50 + 10
add-shipping(50.01) is 50.01 + 20
add-shipping(100) is 100 + 20
end
```
### Conditionals with multiple branches
What if shipping is more complicated? For instance, let’s say that shipping is still $20 orders between $50 and $100 (inclusive) but is $30 for orders over $100. We should first add some new examples:
```python
fun add-shipping(subtotal :: Number) -> Number:
doc: "add shipping amount to subtotal"
if subtotal <= 50:
subtotal + 10
else:
subtotal + 20
end
where:
add-shipping(1) is 1 + 10
add-shipping(50) is 50 + 10
add-shipping(50.01) is 50.01 + 20
add-shipping(100) is 100 + 20
add-shipping(100.01) is 100.01 + 30
add-shipping(200) is 200 + 30
end
```
How can we modify our function to do the right thing? A conditional expression can have any number of `else if` branches:
```python
fun add-shipping(subtotal :: Number) -> Number:
doc: "add shipping amount to subtotal"
if subtotal <= 50:
subtotal + 10
else if (subtotal > 50) and (subtotal <= 100):
subtotal + 20
else:
subtotal + 30
end
where:
add-shipping(1) is 1 + 10
add-shipping(50) is 50 + 10
add-shipping(50.01) is 50.01 + 20
add-shipping(100) is 100 + 20
add-shipping(100.01) is 100.01 + 30
add-shipping(200) is 200 + 30
end
```
###### tags: `conditionals`