# Advanced Class Methods in EK9

Some examples of the advanced class methods have already been show in other examples. This section will cover those ideas in more detail and highlight some of the compromises you will have to make to use them.

Really the advanced methods revolve around the **dispatcher** concept. This simple idea promotes the use of
the Object Oriented approach - specifically polymorphism. It removes the need for __casting__ and detection of
types through __instanceof__. It also removes the need for __switch__ on **types**.

#### Why no **casting** or **instanceof**

The converse question is - why does a developer ever need to 'know' what type they are dealing with? If an API
returns a **type**; be it a *class, record, trait* or even a *dynamic function* - that's the only thing
the developer of that API wanted you to know. The details of what that **type** actually is should be hidden as
that was the developers intent.

Adding casting and instanceof makes code brittle and goes against the general concept of information hiding
and polymorphism. So when using
API's it's best to avoid any attempt to get the actual **type** involved, where possible.

### Designing your own API's

But there are times when you want to design an API's and use **types** in specific ways.

#### Double Dispatch

To avoid casting and instanceof a double dispatch approach can be taken.

**Dispatcher** keyword on methods

There are times when it is necessary to be able to process information where a more detailed knowledge of
a **type** is required, as with the __double dispatch__ approach. EK9 as a **dispatcher** keyword
and concept just for this.
There is an example used with *Exceptions* this includes a short
discussion of how this is used. The key part in this example is the method
**'private handleException() as dispatcher'**.

A second example what also has a short
discussion shows a similar approach but this time not using Exceptions.
See **'build() as dispatcher'** specifically in the example.

### Relating two types

While the **'double dispatch'** design pattern and the **dispatcher** keyword for **types** is really useful, the main power of the
**dispatcher** keyword really comes into its own when there a need to relate two **types** together.

The following example is quite long and has two uses of **dispatcher**. The first is just a simple
decorator type method, but the second is more interesting; it is aimed at demonstrating how it is possible
to calculate the intersection between two shapes.

Given a number of Shapes; Ellipse, Circle, Square, Rectangle and Triangle - obtain the intersection between
any two! Clearly to be able to calculate the intersection it is important to know the exact **type** of
the two shapes involved.

This is where **'double dispatch'** would come in handy, the EK9 language also supports **dispatcher**
on methods with one or two parameters. But importantly it can also detect any ambiguities at compile time,
it does this by looking at the class hierarchies and and traits used.

### Example of Dispatcher

#!ek9 defines module introduction defines type List of Shape defines trait T1 allow only Square specialMessage() as pure <- rtn as String: "T1" T2 simpleMessage() as pure <- rtn as String: "T2" defines function intersectSquares() as pure -> s1 as Square s2 as Square <- intersection as Intersection: LinesIntersection("Line Intersection two squares (by function)") intersectSquareAndRectangle() as pure -> s1 as Square s2 as Rectangle <- intersection as Intersection: LinesIntersection("Line Intersection of a Square and Rectangle (by function)") defines class Coordinate x Float? y Float? //Constructor Coordinate() as pure this(0.0, 0.0) //Constructor Coordinate() as pure -> initialX as Float initialY as Float assert initialX? and initialY? x: Float(initialX) y: Float(initialY) x() as pure <- rtn as Float: Float(x) y() as pure <- rtn as Float: Float(y) operator $ as pure <- rtn as String: $x + ", " + $y operator #^ as pure <- rtn as String: $this //Used for different types of intersection Intersection as open message as String? stdout as Stdout: Stdout() startPoint Coordinate: Coordinate(0.0, 0.0) Intersection() as pure -> message as String this.message: String(message) render() stdout.println(message) //... Other methods ArcIntersection is Intersection endPoint Coordinate: Coordinate() centrePoint Coordinate: Coordinate() ArcIntersection() -> message as String super(message) //... Other methods LinesIntersection is Intersection endPoint Coordinate: Coordinate() end2Point Coordinate: Coordinate() LinesIntersection -> message as String super(message) //... Other methods Shape as abstract stdout as Stdout: Stdout() draw() as abstract protected draw() -> message as String stdout.println("DRAW: " + message) Ellipse extends Shape as open override draw() draw("Ellipse") Circle is Ellipse override draw() draw("Circle") Rectangle is Shape override draw() draw("Rectangle") Triangle is Shape override draw() draw("Triangle") Square is Shape with trait of T1, T2 override draw() draw("Square " + T1.specialMessage() + " " + T2.simpleMessage()) BaseIntersector as abstract intersect() as pure abstract -> s1 as Shape s2 as Shape <- intersection as Intersection intersect() as pure -> s1 as Circle s2 as Circle <- intersection as Intersection: ArcIntersection("Arc Intersection two circles") intersect() as pure -> s1 as Circle s2 as Ellipse <- intersection as Intersection: ArcIntersection("Arc Intersection circle and ellipse") intersect() as pure -> s1 as Ellipse s2 as Circle <- intersection as Intersection: ArcIntersection("Arc Intersection ellipse and circle") intersect() as pure -> s1 as Circle s2 as Rectangle <- intersection as Intersection: ArcIntersection("Arc Intersection circle and rectangle") intersect() as pure -> s1 as Rectangle s2 as Circle <- intersection as Intersection: ArcIntersection("Arc Intersection rectangle and circle") intersect() as pure -> s1 as Circle s2 as Square <- intersection as Intersection: ArcIntersection("Arc Intersection circle and square") intersect() as pure -> s1 as Square s2 as Circle <- intersection as Intersection: ArcIntersection("Arc Intersection squares and circle") intersect() as pure -> s1 as Rectangle s2 as Rectangle <- intersection as Intersection: LinesIntersection("Line Intersection two rectangles") SpecialIntersector extends BaseIntersector as abstract //Adding another method with additional types of shapes //But still this is an abstract class intersect() as pure -> s1 as Ellipse s2 as Triangle <- intersection as Intersection: LinesIntersection("Line Intersection ellipse and rectangle") intersect() as pure -> s1 as Circle s2 as Triangle <- intersection as Intersection: LinesIntersection("Line Intersection circle and triangle") intersect() as pure -> s1 as Triangle s2 as Triangle <- intersection as Intersection: LinesIntersection("Line Intersection two triangles") //Methods that just delegate to functions for the calculations. intersect() as pure -> s1 as Square s2 as Square <- intersection as Intersection: intersectSquares(s1, s2) intersect() as pure -> s1 as Square s2 as Rectangle <- intersection as Intersection: intersectSquareAndRectangle(s1, s2) intersect() as pure -> s1 as Rectangle s2 as Square <- intersection as Intersection: intersectSquareAndRectangle(s2, s1) //Finally make a concrete one - override the base intersect method that was abstract and mark it as a dispatcher Intersector extends SpecialIntersector override intersect() as pure dispatcher -> s1 as Shape s2 as Shape <- intersection as Intersection: Intersection("Intersection just two shapes!") Renderer //entry point for rendering via defining the dispatcher - this will find all sub type methods can call render render() as dispatcher -> s as Shape s.draw() //Just use default method for Circle and Ellipse, but others does something slight different render() -> s as Triangle s.draw() Stdout().println("Did draw triangle") render() -> s as Rectangle Stdout().println("Will Draw Rectangle") s.draw() render() -> s as T1 Stdout().println("Drawing: " + s.specialMessage()) render() -> s as T2 Stdout().println("Drawing: " + s.simpleMessage()) //With Square also implementing T1 and T2 you have to add this in. Which is correct else ambiguous. render() -> s as Square Stdout().println("Before Square") s.draw() Stdout().println("After Square") render() -> i as Intersection i.render() defines program testShapes() //Would really need actual details of what the circles and triangles were. //But this is just to show how dispatcher would work. firstShapes <- [ Circle(), Ellipse(), Rectangle(), Square(), Triangle() ] secondShapes <- [ Circle(), Ellipse(), Rectangle(), Square(), Triangle() ] intersector <- Intersector() renderer <- Renderer() //Simple imperative loop this time rather than stream pipeline. for s1 in firstShapes for s2 in secondShapes renderer.render(s1) renderer.render(s2) intersection <- intersector.intersect(s1, s2) renderer.render(intersection) //EOF

The output of the program above would be as follows:

DRAW: Circle DRAW: Circle Arc Intersection two circles DRAW: Circle DRAW: Ellipse Arc Intersection circle and ellipse DRAW: Circle Will Draw Rectangle DRAW: Rectangle Arc Intersection circle and rectangle DRAW: Circle Before Square DRAW: Square T1 T2 After Square Arc Intersection circle and square DRAW: Circle DRAW: Triangle Did draw triangle Line Intersection circle and triangle DRAW: Ellipse DRAW: Circle Arc Intersection ellipse and circle DRAW: Ellipse DRAW: Ellipse Intersection just two shapes! DRAW: Ellipse Will Draw Rectangle DRAW: Rectangle Intersection just two shapes! DRAW: Ellipse Before Square DRAW: Square T1 T2 After Square Intersection just two shapes! DRAW: Ellipse DRAW: Triangle Did draw triangle Line Intersection ellipse and rectangle Will Draw Rectangle DRAW: Rectangle DRAW: Circle Arc Intersection rectangle and circle Will Draw Rectangle DRAW: Rectangle DRAW: Ellipse Intersection just two shapes! Will Draw Rectangle DRAW: Rectangle Will Draw Rectangle DRAW: Rectangle Line Intersection two rectangles Will Draw Rectangle DRAW: Rectangle Before Square DRAW: Square T1 T2 After Square Line Intersection of a Square and Rectangle (by function) Will Draw Rectangle DRAW: Rectangle DRAW: Triangle Did draw triangle Intersection just two shapes! Before Square DRAW: Square T1 T2 After Square DRAW: Circle Arc Intersection squares and circle Before Square DRAW: Square T1 T2 After Square DRAW: Ellipse Intersection just two shapes! Before Square DRAW: Square T1 T2 After Square Will Draw Rectangle DRAW: Rectangle Line Intersection of a Square and Rectangle (by function) Before Square DRAW: Square T1 T2 After Square Before Square DRAW: Square T1 T2 After Square Line Intersection two squares (by function) Before Square DRAW: Square T1 T2 After Square DRAW: Triangle Did draw triangle Intersection just two shapes! DRAW: Triangle Did draw triangle DRAW: Circle Intersection just two shapes! DRAW: Triangle Did draw triangle DRAW: Ellipse Intersection just two shapes! DRAW: Triangle Did draw triangle Will Draw Rectangle DRAW: Rectangle Intersection just two shapes! DRAW: Triangle Did draw triangle Before Square DRAW: Square T1 T2 After Square Intersection just two shapes! DRAW: Triangle Did draw triangle DRAW: Triangle Did draw triangle Line Intersection two triangles

### Summary

While the example code and the output is __long__, it is aimed at highlighting the EK9 feature to be able to provide the developer with
details of what actual classes are involved without the need for **casting** or **instanceof**. But is also highlights how *methods*
can and should delegate process to *functions* where possible. This is because the *function* is really the smallest most isolated
element to encapsulate functionality.

There are actually two example of **dispatcher** in the sample above; the first is just a simple single parameter **dispatcher** on the
*Renderer*. In general these **dispatcher** methods do a little processing and the delegate through to the actual shape to trigger
normal processing.

But the second example (on the *Intersector*) deals with the thorny issue of relating two *classes* by their actual type together.
In general it is necessary deal with this **N ^{2}** problem of relating two type together in a very methodical manner. This is what
the EK9 language provides the framework for.

For __Shapes__ this would involve trying to workout common denominators in intersections, then creating either a common set of *methods*
or better *functions* that solve the intersection problem and reusing by altering the order of parameters passed in to each of the
**dispatcher** *methods*.

### Next Steps

Generics/Templates is covered in the next section, this is much more advanced.