#!/usr/bin/env python3

import math

#
# a nested function, 
#
def outer(x):
  print("# in outer", x)
# x += 10
  def inner(y):
    print("# in inner", x, y)
    return x + y
  return inner                # outer returns inner

add_five = outer(5)
result = add_five(6)
print("# in main ", result)
print(add_five) 
print() 
print("#==========================") 
print() 

#
# functions as objects
#
def add(x, y):
    return x + y

def times(x, y):
    return x * y

def calculate(func, x, y):
    return func(x, y)

print("# adding         ", calculate(add  , 4, 6))
print("# multiplication ", calculate(times, 4, 6))
print() 
print("#==========================") 
print() 

#
# decorators
#
def addSomething(anyFunc):
  def inner(x):
    print("# inner, doing something ")
#   x += 1
    return anyFunc(x)
#   return 10.0*anyFunc(x)
  return inner

@addSomething           # decorating the following function
def newExp(x):
 return math.exp(x)

print("# calling newExp ", newExp(0.0))
