Thursday, 31 May 2018

Visitor Pattern

In the last post (please check that out before reading this, as it shows the problem we are trying to solve here) we saw how C# uses single-dispatch to select the methods to call. The argument type is determined at compile time and that is used to select the method out of many.

Here is an implementation of visitor pattern to resolve that problem:

void Main()
{
 Employee employee = new Employee();
 Employee manager = new Manager();

 IVisitor visitor = new SalaryAlgoPerformanceVisitor();
 
 employee.Accept(visitor);
 manager.Accept(visitor);
 
 Console.WriteLine(visitor.Output);
}

interface IVisitor
{
 string Output {get;}
 void Visit(Employee e);
 void Visit(Manager e);
}

class SalaryAlgoPerformanceVisitor : IVisitor
{
 public string Output { get; private set;}
 public void Visit(Employee e)
 {
  Output += $"Calculating salary of {nameof(Employee)} based on {nameof(SalaryAlgoPerformanceVisitor)}\n";
 }
 public void Visit(Manager e)
 {
  Output += $"Calculating salary of {nameof(Manager)} based on {nameof(SalaryAlgoPerformanceVisitor)}\n";
 }
}

class Employee
{
 public virtual string GetEmployeeType()
 {
  return nameof(Employee);
 }
 
 public virtual void Accept(IVisitor visitor)
 {
  visitor.Visit(this);
 }
}

class Manager : Employee
{
 public override string GetEmployeeType()
 {
  return nameof(Manager);
 }
 
 public override void Accept(IVisitor visitor)
 {
  visitor.Visit(this);
 }
}

Output:

Calculating salary of Employee based on SalaryAlgoPerformanceVisitor
Calculating salary of Manager based on SalaryAlgoPerformanceVisitor

You will notice that Accept method is resolved using the run time type of Employee object - this is the first dispatch. Then in the Accept method we use (this) so that appropriate method is called on the visitor - this is the second dispatch.

Since Accept is inside the class, we use the type of (this) to call the visitor.

Double Dispatch in C#

First few tests to understand the basics:

What do you think about the GetEmployeeType() method that will be called - will it be on Employee class or Manager class?

void Main()
{
 Employee e = new Manager();
 Console.WriteLine(e.GetEmployeeType()); 
}

class Employee
{
 public virtual string GetEmployeeType() {
  return nameof(Employee);
 }
}

class Manager : Employee
{
 public override string GetEmployeeType() {
  return nameof(Manager);
 }
}


Output: Manager

Since Employee object 'e' points to Manager, it will call the GetEmployeeType of Manager class.

Another one:

void Main()
{
 Employee employee = new Manager();
 Console.WriteLine(CalculateSalary(employee));
}

string CalculateSalary(Employee e)
{
 return $"{nameof(CalculateSalary)} of {nameof(Employee)}";
}

string CalculateSalary(Manager e)
{
 return $"{nameof(CalculateSalary)} of {nameof(Manager)}";
}

class Employee ...

class Manager : Employee ...


Output: CalculateSalary of Employee

Since the object is of type Employee the CalculateSalary accepting Employee will be called.


Taking this further, let's move the CalculateSalary to a class.

void Main()
{
 Employee employee = new Employee();
 Employee manager = new Manager();

 SalaryAlgo algo = new SalaryAlgoBasedOnPerformance();
 Console.WriteLine(algo.CalculateSalary(employee));
 Console.WriteLine(algo.CalculateSalary(manager));
}

class SalaryAlgo
{
 public virtual string CalculateSalary(Employee e)
 {
  return $"{nameof(CalculateSalary)} of {nameof(Employee)} based on {nameof(SalaryAlgo)}";
 }

 public virtual string CalculateSalary(Manager e)
 {
  return $"{nameof(CalculateSalary)} of {nameof(Manager)} based on {nameof(SalaryAlgo)}";
 }
}

class SalaryAlgoBasedOnPerformance : SalaryAlgo
{
 public override string CalculateSalary(Employee e)
 {
  return $"{nameof(CalculateSalary)} of {nameof(Employee)} based on {nameof(SalaryAlgoBasedOnPerformance)}";
 }

 public override string CalculateSalary(Manager e)
 {
  return $"{nameof(CalculateSalary)} of {nameof(Manager)} based on {nameof(SalaryAlgoBasedOnPerformance)}";
 }
}

class Employee ...

class Manager : Employee ...

Output:

CalculateSalary of Employee based on SalaryAlgoBasedOnPerformance
CalculateSalary of Employee based on SalaryAlgoBasedOnPerformance

As you can see, CalculateSalary(Manager) is not at all called. This is because the method to call is decided at compile time and the declared type is used to identify the method not the runtime type.

A quick way to fix this is to use "dynamic" keyword:

 Console.WriteLine(algo.CalculateSalary((dynamic)manager));

Output:

CalculateSalary of Employee based on SalaryAlgoBasedOnPerformance
CalculateSalary of Manager based on SalaryAlgoBasedOnPerformance

Another way to resolve this is to use Visitor pattern.

Helpful links:

https://blogs.msdn.microsoft.com/curth/2008/11/15/c-dynamic-and-multiple-dispatch/

EDIT: Post that implements Visitor pattern to resolve this problem.

Thursday, 10 May 2018

Python: Certificate of Completion

Python:

I purchased Kindle book: "A smarter way to learn Python" and completed all its exercises.
Finally I got the certificate from the author: ye!


Friday, 4 May 2018

Python: Functions - Part 1

Quick post Python functions:


Define a function and call it:

def add(first_num, second_num):
    sum = first_num + second_num
    print(sum)

>> add(1, 2)
3

Two types of arguments: positional and keyword:
Positional - defined by order of parameters in the method
Keyword - use the parameter name when calling the function

You can forget what order to use when all of your arguments are keyword arguments:
add(second_num = 3, first_num = 1)

But when mixing keyword arguments with positional you need to take care that all keyword arguments are at the end:

add(second_num = 3, 3)
SyntaxError: positional argument follows keyword argument

In the call below, the first argument of value "1" is taken in as parameter "first_num" based on it's position, so defining it again as keyword Python will give error:

>>> add(1, first_num = 3)
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    add(1, first_num = 3)
TypeError: add() got multiple values for argument 'first_num'


>>> add(2, second_num = 3)
5

Default value:
Set a default value for a parameter in the method definition by using "=" sign.
In this example, the second_num parameter defaults to value of 5.
You can skip passing in second argument and the function will run fine.

>>> def add(first_num, second_num = 5):
 sum = first_num + second_num
 print(sum)

>>> add(3)
8

If you don't want to use default value of 5, then call the function the usual way.

>>> add(4, 5)
9

If you have many default parameters, you can use keyword to assign a different value to one of them and skip the rest. For example:

>>> def calc(a, b, c = 10, d = 20, e = 30):
 print(a + b + c + d + e)

# skip all default parameters
>>> calc(1, 2)
63

#when not using default val of 'e'
>>> calc(2, 3, e = 45)
80

Next post: Working with unknown number of parameters


Shorts - week 3, 2022

Post with links to what I am reading: 1. A very good post on different aspects of system architecture: https://lethain.com/introduction-to-a...