Java method dispatch and visitor pattern

This page explains the concept of method dispatch and different types of dispatch. And also explain issues related with method dispatch in implementing Visitor Pattern. Full implementation of Visitor Pattern is not covered.

Programming language determines which method to call via method dispatch.
In Java, overloaded method calling is determined by static dispatch, what happens in compile phase.

class CarElement { }
class Engine extends CarElement { }
class Wheel extends CarElement { }
class CarElementVisitor {
    public void visit(CarElement element){
        System.out.println("CarElement visited");
    }

    public void visit(Engine element){
        System.out.println("Engine visited");
    }

    public void visit(Wheel element){
        System.out.println("Wheel visited");
    }
}
public class Test {
    public static void main(String[] args) {
        CarElement carElement = new Engine();
        //The dispatch based on static/apparent type, even it is Engine,
        //but "CarElement" is printed in the console
        new CarElementVisitor().visit(carElement);

        Engine engine = new Engine();
        new CarElementVisitor().visit(engine);
    }

}

output is:

CarElement visited
Engine visited

Overridden Method calling is determined by dynamic dispatch, what happens in run time. This is the traditional polymorphism.

public class Test {
    public static void main(String[] args) {
        CarElement wheel = new Wheel();
        //The dispatch based on actual type
        System.out.println(wheel.getClass());

        CarElement engine = new Engine();
        //The dispatch based on actual type
        System.out.println(engine.getClass());
    }
}

output is:

class Wheel
class Engine

In the above example of static dispatch, the dispatch cares the receiver only, don’t care the actual argument type. This sort of dispatch is single dispatch. Programing languages like C++, Java, Smalltalk Objective-C, JavasScript and Python are single dispatch.

There is another type of dispatch, that is double/multiple dispatch, double multiple dispatch is a special form of multiple dispatch.
Language like C# use double dispatch. In C#, variables declared as dynamic, type will not be checked at compile time, its type is determined at run time as well. Take above static dispatch example in Java, if it is in C#, the correct method will executed based on argument actual type.

Single and Double dispatch is a key issue in implementing the Visitor Pattern. Define Element(Node) and Visitor(NodeVisitor) interface,

interface CarElement {
    void accept(CarElementVisitor visitor);
}

interface CarElementVisitor {
    void visit(Body body);
    void visit(Car car);
    void visit(Engine engine);
    void visit(Wheel wheel);
}

There are 2 issues here,

  • Which concrete CarElement accept() will be dispatched?
  • Which concrete CarElementVisitor visit() will be dispatched?

The first dispatch is easy, because it is via method overridden, thus once the correct concrete CarElement is chosen, the correspond accept() will be executed.
The second issue is a little bit confused in Java, because it is overload. However, it is not a problem, see reason in inline comment,

class Engine implements CarElement {
    public void accept(final CarElementVisitor visitor) {
        //type of argument "this" is Engine,
        //so visit() will be dispatched to visit(Engine engine)
        //in the concrete CarElementVisitor
        visitor.visit(this);
    }
}

Basically, the double dispatched is implemented above.
This same issue not exist in C#, because the language itself support double dispatch.
Wikipedia gives a very helpful description of this topic at below articles,
Visitor Pattern, Double Dispatch.
And, Using Type dynamic in C# programming guide give helpful explanation of dynamic type.

Advertisements

Bubble Sorting Python3

import signal
import sys

def sort(input):
    total = 0
    isSorted = False
    ran = len(input) - 1
    while not isSorted:
        isSorted = True
        for j in range(0,ran):
            print(isSorted)
            total +=1
            if input[j] > input[j+1]:
                isSorted = False
                tmp = input[j]
                input[j] = input[j+1]
                input[j+1] = tmp
        ran -= 1
    print(input)
    print(total)

def signal_handler(signal, frame):
        print('You pressed Ctrl+C!')
        sys.exit(0)

def main():
    signal.signal(signal.SIGINT, signal_handler)
    print('Press Ctrl+C to stop, input the array split with space')
    for line in sys.stdin:
        print(line)
        arr = [int(elem) for elem in line.split()]
        sort(arr)

if __name__ == "__main__": main()

Linux cron job

This pages shows how to add a cron job for current user. And also shows how to send email in Amazon Linux through sSMPT.

There are 2 ways to add job,

  • There are cron folders under /etc, such as /etc/cron.hourly, /etc/cron.daily, /etc/corn.weekly and /etc/cron.monthly. Add shell script under these folders will run hourly/daily/weekly/monthly correspondingly.
  • Create a specific schedule for particular user, we will focus on this way.

First, exectue below command, will create a new cron file for current user under /var/spool/cron, the file name is same with current username

crontab -e

Second, edit generated cron file adding below line, the sendemail job will be executed every 5 minutes,

*/5 * * * * sh /root/report/sendemail.sh

In the sendemail.sh, which send email through sSMPTP.
First, install the sSMTP,

yum install sSMTP


Second, edit /etc/ssmtp/ssmtp.conf, add below,

mailhub=smtp.gmail.com:587
UseSTARTTLS=YES
AuthUser=yourusername@gmail.com
AuthPass=yourpassword

Third, the sendemail.sh looks like,

now=$(date +%m/%d/%Y)

dir=/root/report/

echo "From: OverriddenFrom<yourusername@gmail.com>" > $dir/email.txt
echo "Subject: email title $now" >> $dir/email.txt
echo >> $dir/email.txt
echo email content >> $dir/email.txt
echo >> $dir/email.txt
echo "Generated at $(date +'%m/%d/%Y %H:%M:%S')" >> $dir/email.txt

/usr/sbin/ssmtp recipient@gmail.com < $dir/email.txt

Note, the From: must be format as OverriddenFrom<yourusername@gmail.com>, if use OverriddenFrom only, gmail seems reject it, and override it to yourusername only.

Python source file vim editing indent

When editing Python source file in vim, we may want to use tab to add indent. Below shows how to use vim autocommand to add the indent automatically for*py, *pyw, *.c and *.h files.

Change the vim setting in .vimrc, add the content in  “vimrc file for following the coding standards specified in PEP 7 & 8” to the .vimrc file.

Once done, open vim to edit a new .py file, enter tab will add 8 spaces as the indent. Above Python vimrc file do more things actually, like show red when there is a invalid indent, etc.

The indent work done in the Python vimrc file is, below line of script will set tabstop=8 for new added and existing *py, *pyw, *.c and *.h file(it doesn’t touch other files other than these 4 files)

au BufRead,BufNewFile *py,*pyw,*.c,*.h set tabstop=8
au BufRead,BufNewFile *.py,*.pyw set expandtab

Details of autocommand can be found at,
autocommand tabstop
autocommand expandtab

And, there is another page show helpful info about Vi Improved, and the vim syntax config.

However, there is some confusions here, Python prefer 4 spaces for the indent, so the correct & convenient indent way is in the description here. Basically, if the tabstop is 8, set softtabstop and shiftwidth to 4, and set use noexpandtab.

tabstop is used for how to display tab(how many spaces counts for).
softtabstop is used for how many spaces will be perform when tab key entered in insert mode.
expandtab, when it is set, there will be no tab character in the insert mode, all are spaces, if softtabstop set, softtabstop spaces will be inserted, otherwise tabstop spaces will be inserted.