QuantStack

Functional programming in C++

Update your repo

Open a terminal (or git bash), cd to your repo and type the following


    git checkout master
    git pull upstream master
    git push origin master
    git branch -d my_branch
    git checkout -b functional
                        

Check your build setup - OSX

In the terminal, cd to functional/cpp/single_file


    mkdir build
    cd build
    cmake ..
    make
                        

Check your build setup - Windows

In git-bash, cd to functional/cpp/single_file


    mkdir build
    cd build
                        

Open "Invite de commandes des outils natifs x64 de VS2015

(just type "natifs" in the search bar of Windows)

cd to C:\Users\your_name\cpp_dauphine\functional\cpp\single_file\build


    cmake -G "NMake Makefiles" ..
    nmake
                        

Function definition


    double discount_factor(double rate, double maturity)
    {
        double res = std::exp(-rate * maturity);
        return res;
    }

    void print_discount_factor(double rate, double maturity)
    {
        double df = discount_factor(rate, maturity);
        std::cout << "DF(" << maturity << "," << rate << ") = " << df << std::endl;
        // No return statement here
    }
                        

Arguments

The semantic of argument passing is the same as the semantic of initialization


    double discount_factor(double rate, double maturity)
    {
        return std::exp(-rate * maturity);
    }

    double df = discount_factor(0.04, 2);
                            

is equivalent to


    double rate = 0.04;
    double maturity = 2.5;
    // jump to discount_factor code in memory
        return std::exp(-rate * maturity);
                            

Arguments

Type checking


double discount_factor(double rate, double maturity) { ... }
int main(int argc, char* argv[])
{
    const char* rate = "0.04";
    double r = 0.04;
    double m = 2.5;
    discount_factor(rate, m); // Error
    discount_factor(r, m);    // Ok
    return 0;
}
                        

Arguments

Arguments conversion


double discount_factor(double rate, double maturity) { ... }
int main(int argc, char* argv[])
{
    const char* rate = "0.04";
    double r = 0.04;
    int m = 2;
    discount_factor(rate, m); // Error
    discount_factor(r, m);    // Ok
    return 0;
}
                        

Arguments

Default argument


    double discount_factor(double rate, double maturity) { ... }
    double d = discount_factor(0.04); // Error
                            

    double discount_factor(double rate, double maturity = 1.) { ... }
    double d = discount_factor(0.04); // OK - Equivalent to discount_factor(0.04, 1.)
    double d = discount_factor(0.04, 2.5) // OK, does not use the default argument
                            

    double discount_factor(double rate = 0.01, double maturity) { ... } // Illegal
    double my_function(double a1, double a2 = 0., double a3) { ... }    // Illegal
                            

Return value


    double f1() { }             // Error: no return value
    void   f2() { }             // OK
    double f3() { return 1.2; } // OK
    void   f4() { return 1.2; } // Error: void function
    double f5() { return; }     // Error: missing return value
    void   f6() { return; }     // OK
    double f7() { return "7"; } // Error: wrong return type
    double f8() { return 1; }   // OK: conversion from int to double
                        

Reference


    void inc(int i1, int i2)
    {
        ++i1;
        ++i2;
    }

    void client()
    {
        int i = 4;
        int j = 5;
        inc(i, j);
        std::cout << "i = " << i << std::endl;
        std::cout << "j = " << j << std::endl;
    }
                        

Reference


    int i = 4;
    int& j = i;
    ++j;
    std::cout << i << std::endl;
                        

    int& j; // Error: reference must be initialized
    int i = 4;
    int j& = i;
    int k = 8;
    j = k;
    ++j;
    std::cout << i << std::endl;
    std::cout << k << std::endl;
                            

Reference


    void inc(int& i1, int& i2)
    {
        ++i1;
        ++i2;
    }

    void client()
    {
        int i = 4;
        int j = 5;
        inc(i, j);
        std::cout << "i = " << i << std::endl;
        std::cout << "j = " << j << std::endl;
    }
                        

const reference


    std::vector<double> discount_factor(std::vector<double> rate, std::vector<double> maturity)
    {
        std::size_t size = rate.size();
        std::vector<double> res(size);
        for(size_t i = 0; i < size; ++i)
        {
            res[i] = std::exp(-rate[i] * maturity[i]);
            rate[i] = 0.; // No effect, rate is a copy of the passed argument
        }
        return res;
    }
                        

const reference


    std::vector<double> discount_factor(std::vector<double>& rate, std::vector<double>& maturity)
    {
        std::size_t size = rate.size();
        std::vector<double> res(size);
        for(size_t i = 0; i < size; ++i)
        {
            res[i] = std::exp(-rate[i] * maturity[i]);
            rate[i] = 0.; // Side-effect, the passed argument is changed!
        }
        return res;
    }
                        

const reference


std::vector<double> discount_factor(const std::vector<double>& rate, const std::vector<double>& maturity)
{
    std::size_t size = rate.size();
    std::vector<double> res(size);
    for(size_t i = 0; i < size; ++i)
    {
        res[i] = std::exp(-rate[i] * maturity[i]);
        rate[i] = 0.; // Error, cannot modify a const object
    }
    return res;
}
                        

const reference


void discount_factor(const std::vector<double>& rate, const std::vector<double>& maturity,
                     std::vector<double>& res)
{
    std::size_t size = rate.size();
    res.resize(size);
    for(size_t i = 0; i < size; ++i)
    {
        res[i] = std::exp(-rate[i] * maturity[i]);
    }
}
                        

Function overloading


std::vector<double> discount_factor(const std::vector<double>& rate, const std::vector<double>& maturity);

int main(int argc, char* argv[])
{
    double df = discount_factor(0.04, 1.5); // error, cannot convert parameter 1 ...
    return 0;
}
                        

int main(int argc, char* argv[])
{
    std::vector<double> res = discount_factor(std::vector<double>(1, 0.04), std::vector<double>(1, 1.5));
    double df = res[0];
    return 0;
}
                            

Function overloading


std::vector<double> discount_factor(const std::vector<double>& rate, const std::vector<double>& maturity);
double discount_factor(double rate, double maturity);

int main(int argc, char* argv[])
{
    std::vector<double> r(3, 0.04);
    std::vector<double> m(3, 1.5);
    std::vector<double> df_vec = discount_factor(r, m);
    double df = discount_factor(0.04, 1.5);
    return 0;
}
                        

Function overloading


    void print(long);
    void print(double);

    void client()
    {
        long l = 1L;
        double d = 1.5;
        int i = 1;
        print(l);         // Ok, calls print(long)
        print(d);         // Ok, calls print(double)
        print(i);         // Error, ambiguous
        print(long(i));   // Ok, calls print(long)
        print(double(i)); // Ok, calls print(double)
    }
                        

Function overloading


    int    f(int, int);
    void   f(int, int); // Illegal, overloaded function cannot differ only by return type
    double f(double, double); // Ok
                        

    int f(int, int);
    // f's type     : int (int, int)
    // f's signature: (int, int)
                            

Code organization

In the terminal, cd to ../multi_files

Open discount_factor.cpp and follow the instruction

Open main.cpp and follow the instruction

Code organization


// discount_factor.cpp
double discount_factor(double rate, double maturity)
{
    // ...
}
std::vector<double> discount_factor(const std::vector<double> r, const std::vector<double> m)
{
    // ...
}
void print_discount_factor(double rate, double maturity)
{
    // ...
}
                        

// main.cpp
int main(int argc, char* argv[])
{
    double df = discount_factor(0.04, 1.5);
    return 0;
}
                        

Code organization - OSX

Try to build the program


    mkdir build
    cd build
    cmake ..
    make
                        

Code organization - Windows

Try to build the program


    mkdir build
                        

    cd build
    cmake -G "NMake Makefiles" ..
    nmake
                        

Function declaration


    double discount_factor(double rate, double maturity);
    std::vector<double> discount_factor(const std::vector<double> r, const std::vector<double> m);
    void print_discount_factor(double rate, double maturity);
    
    // Syntax of a function declaration:
    return_type function_name(arg_type1 arg1, arg_type2 arg2);
                        

Default arguments


    // Declaration
    double discount_factor(double rate, double maturity = 1.);
    // Definition
    double discount_factor(double rate, double maturity = 1.) // Illegal
    {
        return srd::exp(-rate * maturity);
    }
                        

    // Declaration
    double discount_factor(double rate, double maturity = 1.);
    // Definition
    double discount_factor(double rate, double maturity) // Ok
    {
        return srd::exp(-rate * maturity);
    }
                            

Code organization


    // discount_factor.hpp
    double discount_factor(double rate, double maturity);
    std::vector<double> discount_factor(const std::vector<double> r, const std::vector<double> m);
    void print_discount_factor(double rate, double maturity);
                        

    // main.cpp
    // Add the following before the main function
    #include "discount_factor.hpp"
    
    // discount_factor.cpp
    // Add the following before the functions definition
    #include "discount_factor.hpp"
                        

Compilation

compilation

Link

link

One definition rule (ODR)

  • For every C++ primitive (variable, function, class)
  • Many declarations allowed
  • Only ONE definition

One definition rule (ODR)

Replace the declaration of discount_factor with its definitions


// discount_factor.hpp
double discount_factor(double rate, double maturity)
{
    // ...
}

// discount_factor.cpp
// Remove the function double discount_factor(double rate, double maturity)
                        

Try to compile

inline


// discount_factor.hpp
inline double discount_factor(double rate, double maturity)
{
    // ...
}
                        

One definition rule (ODR)

Open "bond_pricer.hpp" and uncomment its content

Include "bond_pricer.hpp" in "main.cpp"

Try to build the program

Inclusion guard


    // discount_factor.hpp
    #ifndef DISCOUNT_FACTOR_HPP // Inclusion Guard
    #define DISCOUNT_FACTOR_HPP

    inline double discount_factor(double rate, double maturity) { ... }
    std::vector<double> discount_factor(const std::vector<double> r, const std::vector<double> m);
    void print_discount_factor(double rate, double maturity);
    #endif // DISCOUNT_FACTOR_HPP
                        

static


// discount_factor.cpp
int check = 7;

// main.cpp
int check = 4;
                        

// discount_factor.cpp
static int check = 7;

// main.cpp
static int check = 4;
                            

static


int func()
{
    int res = 0;
    return ++res;
}

int func_mem()
{
    static int res = 0;
    return ++res;
}
                        

Namespace


// bon_pricer.hpp
inilne double discount_factor(double rate, double maturity) { ... }

// main.cpp
#include "discount_factor.hpp"
#include "bond_pricer.hpp"

int main(int argc, char* argv[])
{
    double df = discount_factor(0.04, 1.5);
    return 0;
}
                        

Namespace


// discount_factor.hpp
namespace ds1
{
    inline double discount_factor(double rate, double maturity) { ... }
}

// bond_pricer.hpp
namespace ds2
{
    inline double discount_factor(double rate, double maturity) { ... }
}
                        

Namespace


// discount_factor.cpp
namespace ds1
{
    double discount_factor(double rate, double maturity)
    {
        // ... same as before
    }
}

// main.cpp
int main(int argc, char* argv[])
{
    double df = ds1::discount_factor(rate, maturity);
}
                        

Namespace


namespace my_lib
{
    namespace my_module
    {
        void my_func();
    }
}

my_lib::my_module::my_func();
                        

using


namespace mlm = my_lib::my_module; // namespace alias
mlm::my_func();
                        

using my_lib::my_module::my_func; // using directive
my_func();
                            

using namespace my_lib::my_module; // Evil!
my_func();
                            

using namespace std; // Ultimate Evil!
                            

Anonymous namespace


// discount_factor.cpp
static int check = 7;

// main.cpp
static int check = 4;
                            

// discount_factor.cpp
namespace // Anonymous namespace
{
    int check = 7;
}
// check is accessible in discount_factor.cpp only