Functions as arguments

Dr Andy Evans

[Fullscreen]

Declarative Languages

  • Declarative Languages usually describe the end point first and the program works to get there.
  • One subset of these are Functional Languages where one passes one procedure to another in ever more complex nesting in order to calculate some end result defined by the first layer of nesting.
  • Generally stateful elements like variables are discouraged; the code is constructed from expressions rather than full statements.

  • Imperative:
    text = input("Type a number to add to four")
    value = int(text)
    answer = 4 + value
    print (answer)
  • Functional:
    print (
        4 + int(
            input(
                "Type a number to add to four"
            )
        )
    )
  • Generally stateful elements like variables are discouraged; the code is constructed from expressions rather than full statements.

Method chaining

  • In some languages (like JavaScript) altered objects are commonly returned from method calls.
    a = b.method()
  • This means you can then call methods inside those objects, and start to create chains:
    a = b.method()
    c = a.method2()
  • Becomes:
    c = b.method().method2()
  • This saves making unnessary labels, so is more efficient, but sometimes needs pulling appart to debug.
  • Python tends not to return such objects, so this is less common, but it is still worth knowing just incase you see it.

Python

  • Functional languages are increasingly popular as everything is contained within the nesting; this means it can be split up easily so different nests run on different processors on machines with more than one processor (which is usual now).
  • Python is a third generation imperative language, but with functional bits.
  • Such hybrids are generally the direction of travel.

Functional programming

Functions as objects

  • In Python, pretty much everything is an object, including functions.
  • This means you can do this:
    def f():
        pass

    a = f
    a()
    print(a)

Efficiency

  • Indeed, it is more efficient. If we do:
    a = B()
    a.c()
    a.c()
    This needs to construct a new reference to the function c each it is called. If we do this:
    a = B()
    d = a.c # Note lack of parentheses when talk about the name.
    d()
    d()
    We just use the old call.
  • Function calls are amongst the most processor intensive standard language elements, so this can make considerable savings.

Function 'fun'

  • This means it is possible to assign functions to objects.
    (With the types library it is also possible to assign them to classes currently being used)
    class A():
        def prt(self):
            print("hi")

    def prrrt():
        print("changed")
    a = A()
    a.prt()
    a.prt = prrrt
    a.prt()

  • Now I am become Death, the destroyer of prints:
    >>> print = 0
    >>> print()
    TypeError: 'int' object not callable.