Classes¶

Classes allow to combine functions with data. To exemplify classes we will make a class that is used to hold geometries and calculates the area and circumference

In [1]:
import ROOT
In [2]:
import fortranmagic
%load_ext fortranmagic
import os
import sys

import numpy as np

if sys.platform.startswith("win"):
        # Depends of system, python builds, and compilers compatibility.
        # See below.
    f_config = "--fcompiler=gnu95 --compiler=mingw32"
else:
        # For Unix, compilers are usually more compatible.
    f_config = ""

    # Disable only deprecated NumPy API warning without disable any APIs.
f_config += " --extra '-DNPY_NO_DEPRECATED_API=0'"

%fortran_config {f_config}
New default arguments for %fortran:
	 --extra '-DNPY_NO_DEPRECATED_API=0'

Object oriented programming¶

c++¶

if you use a baseclass pointer as we want to do in 7.1 and 7.2. Then you need to use a default virtual destructor in the base class.

In [3]:
%%cpp -d
#include <iostream>
#include <memory>

using namespace std;
class Geometry {
public:
    Geometry() {}
    virtual ~Geometry() = default;//the default constructor for base class is needed
    virtual double getArea() = 0;
    virtual double getCircumference() = 0;
};

class Rectangle1 :public Geometry {
public:
    Rectangle1(double width, double height) :width(width), height(height) {//when exist c calles the standard constructor of the parent class
    }
    //virtual ~Rectangle() {}//destructor if not used leave it out
    virtual double getArea() override {
        return width * height;
    }
    virtual double getCircumference() override {
        return 2 * width + height;
    }
protected: //can be only accessed by this class and children

private: //can only be accessed by this class
    double width;
    double height;
};

class Square :public Rectangle1 {
public:
    Square(double l) :Rectangle1(l, l) {
    }
};

class Disc :public Geometry {
public:
    Disc(double r) :r(r) {
    }
    virtual double getArea() {
        return 3.1415926 * r * r;
    }
    virtual double getCircumference() {
        return 2 * 3.1415926 * r;
    }
protected:
    double r;
};
In [4]:
%%cpp
//void main()
{
    Rectangle1 r(2.1, 3.1);
    Square s(3.1);
    Disc d(2.1);

    cout << r.getArea() << endl;
    cout << r.getCircumference() << endl;
    cout << endl;

    cout << s.getArea() << endl;
    cout << s.getCircumference() << endl;
    cout << endl;

    cout << d.getArea() << endl;
    cout << d.getCircumference() << endl;
}
6.51
7.3

9.61
9.3

13.8544
13.1947

c¶

In [5]:
%%cpp -d

#include <math.h>

typedef struct {
    double width;
    double height;
} Rectangle2;

typedef struct{
    double r;
} Disc2;

void Rectangle_init(Rectangle2 *_this,double width, double height){
    _this->width=width;
    _this->height=height;
}

double Rectangle_getArea(Rectangle2 *_this){
    return _this->width*_this->height;
}
double Rectangle_getCircumference(Rectangle2 *_this){
    return 2*_this->width+_this->height;
}

void Square_init(Rectangle2 *_this,double r){
    _this->width=r;
    _this->height=r;
}

double Square_getArea(Rectangle2 *_this){
    return Rectangle_getArea(_this);
}
double Square_getCircumference(Rectangle2 *_this){
    return Rectangle_getCircumference(_this);
}

void Disc_init(Disc2 *_this,double r){
    _this->r=r;
}

double Disc_getArea(Disc2 *_this){
    return M_PI*_this->r*_this->r;
}
double Disc_getCircumference(Disc2 *_this){
    return 2*M_PI*_this->r;
}
In [6]:
%%cpp

//void main(){
Rectangle2 r;
Rectangle2 s;
Disc2 d;

Rectangle_init(&r,2.1,3.1);
Square_init(&s,3.1);
Disc_init(&d,2.1);

printf("%lf\n",Rectangle_getArea(&r));
printf("%lf\n",Rectangle_getCircumference(&r));
printf("\n");

printf("%lf\n",Square_getArea(&s));
printf("%lf\n",Square_getCircumference(&s));
printf("\n");

printf("%lf\n",Disc_getArea(&d));
printf("%lf\n",Disc_getCircumference(&d));

//}
6.510000
7.300000

9.610000
9.300000

13.854424
13.194689

javascript¶

In [7]:
%%js //the next line is only necessary in jupyter notebooks
element.setAttribute('style', 'white-space: pre;');console.log=function(text){element.textContent+=text+"\n"}

class Geometry{
    constructor() {
        if (this.constructor == Geometry) {
            throw new Error("Abstract classes can't be instantiated.");
        }
    }
    getArea(){
        throw new Error("Method 'getArea()' must be implemented.");
    }
    getCircumference(){
        throw new Error("Method 'getCircumference()' must be implemented.");
    }
}

class Rectangle extends Geometry{
    constructor(width, height){
        super();
        this.width=width
        this.height=height
    }
    getArea(){
        return this.width*this.height;
    }
    getCircumference(){
        return 2*this.width+this.height;
    }
}

class Square extends Rectangle{
     constructor(l){
        super(l,l);
    }
}

class Disc extends Geometry{
     constructor(r){
        super();
        this.r=r;
    }
    getArea(){
        return Math.PI*this.r*this.r;
    }
    getCircumference(){
        return 2*Math.PI*this.r;
    }
}

let r=new Rectangle(2.1,3.1)
let s=new Square(3.1)
let d=new Disc(2.1)

console.log(r.getArea())
console.log(r.getCircumference())
console.log("")

console.log(s.getArea())
console.log(s.getCircumference())
console.log("")

console.log(d.getArea())
console.log(d.getCircumference())
console.log("")

Python¶

In [8]:
from abc import ABC, abstractmethod
import math

class Geometry(ABC):
    @abstractmethod
    def getArea(self):
        pass
    def getCircumference(self):
        pass

class Rectangle(Geometry):
    def __init__(self,width, height):
        self.width=width
        self.height=height
        super().__init__()
    def getArea(self):
        return self.width*self.height
    def getCircumference(self):
        return 2*self.width+self.height

class Square(Rectangle):
    def __init__(self,l):
        super().__init__(l,l);

class Disc(Geometry):
    def __init__(self,r):
        self.r=r
        super().__init__();
    def getArea(self):
        return math.pi*self.r*self.r
    def getCircumference(self):
        return 2*math.pi*self.r;

r=Rectangle(2.1,3.1)
s=Square(3.1)
d=Disc(2.1)

print(r.getArea())
print(r.getCircumference())
print("")

print(s.getArea())
print(s.getCircumference())
print("")

print(d.getArea())
print(d.getCircumference())
print("")
6.510000000000001
7.300000000000001

9.610000000000001
9.3

13.854423602330987
13.194689145077131

Fortran 95¶

in Fortran 95 you can use structures. https://en.wikibooks.org/wiki/Fortran/structures Since Fortan 2003 you can use classes with polymorphism: https://annefou.github.io/Fortran/classes/classes.html

In [9]:
%%fortran 
module test_m
    implicit none
    private
    public test_type
    type test_type
        integer :: i
    contains
        procedure, nopass :: print_hello
        procedure         :: print_int
    end type
contains
    !> do not process type specific data => nopass
    subroutine print_hello
        print *, "hello"
    end subroutine

    !> process type specific data => first argument is "this" of type "class(test_type)"
    !! use class and not type below !!!!
    subroutine print_int(this)
        class(test_type), intent(in) :: this

        print *, "i", this%i
  end subroutine
end module

! program and subroutine exchanged due to jupyternotebook

! program main
subroutine main()
    use test_m
    implicit none
    type (test_type) :: obj

    obj%i = 1           ! is like obj.i in c++,c and javascript and python
    call obj%print_hello
    call obj%print_int
! end program
end subroutine main
In [10]:
main()
 hello
 i           1