FI-Info
FI-Info

Reputation: 705

Understanding first class functions

I am trying to understand first class functions and how they may be used in a practical example. The example that I came up with is for authentication before calling specific functions for a logged-in user. For example:

def authenticate(user_id):
    if user_id != 1: return None
    def call_func(func_name):
        print(f"{user_id} is logged in! ==> Calling function '{func_name}'")
    return call_func

user0 = authenticate(user_id=0)
if user0: user0(func_name='xyz')
user1 = authenticate(user_id=1)
if user1: user1(func_name='xyz')

Which prints:

1 is logged in! ==> Calling function 'xyz'

Is this a proper understanding of first-class functions? The above seems more like the concept of a wrapper or decorator. Are these basically the same thing, or what's the difference between these three concepts?

Upvotes: 0

Views: 276

Answers (1)

Pedro Rodrigues
Pedro Rodrigues

Reputation: 2658

First class simply means it can exist on its own. It is not required to be accompanied by no one.

Methods

Where in languages like Java and C#, you create classes to shove methods into.

class Logger {
    public Logger(string name) {
        this.name = name;
    }

    public void Log(string msg) {
        System.out.print(name + msg);
    }
}

And then you use instances of those classes to call the methods.

Logger logger = new Logger("a name");
logger.Log("a message");

A function can only exist as a method of a class. The class is the first class citizen.

Functions

In languages like python you can just have a function.

def log(name, msg):
    print(name, msg)

And just call that function.

log('a name', 'a message')

A function can simply exist.

Notes on Python

Python has classes has well. So if you still want to avoid typing 'a name' all the time, you can use them.

class Logger:
    def __init__(self, name):
        self.name = name

    def log(self, msg):
        print(self.name, msg)

logger = Logger('a name')
logger.log('a message')

And since functions are first class citizens, closures are a thing as well and the same can be achieved, again, with just functions.

def logger(name):
    def log(msg):
        print(name, msg)
    return log

log = logger('a name')
log('a message')

Decorators

Decorators are simply functions that make use other function.Take the previous log function for example. If we have a fuzz decorator, and decorate the log function with it, it essentially replaces our log function by its own (that happens to call ours).

def fuzz(func):
    def fuzzed_func(*args, **kwargs):
        print('fuzz')
        func(*args, **kwargs)
        print('fuzz')
    return fuzzed_func

@fuzz
def log(name, msg):
    print(name, msg)

fuzz

a name a message

fuzz


Note 1. data types are first class citizens as well, in all example given here. The string is by itself in Java. As 'a name' is a str by itself, as well, in Python. So, not only functions and classes apply to the first class.

Note 2. Also consider in the case of a class, you can have methods that do not act on self or this, they are referenced as static methods. Essentially a function in a class.

Extras

There is a fantastic satire about exactly this, you may want to read at some point.

Execution in the Kingdom of Nouns by Steve Yegge

David Beazley, just recently at PyCon 2019, gave an outstanding talk, loosely on this topic, that demonstrates quite brilliantly the power of a function.

Lambda Calculus from the Ground Up

Upvotes: 2

Related Questions