Thursday, 3 December 2020

OOP - Recovering lost class types

 Normally casting is used to convert classes to other classes, however this operation can break the type system.

For example, a "List" may use the class "ListItem". And the "ListItem" is then inherited by the "Item" class. So we may store "Item" classes in the "List" class.

Using casting we could recover the "Item" class from the "ListItem" class like this:

 

ListItem* ptr = list.front();

Item* item = (ListItem*)ptr;

 

However here, we have over-ruled the type system to enforce the cast from ListItem to Item. We need a way to perform this operation without breaking the type system rules.

 

 

 

 

One method is to store the type information in the base class, to be used later to reconstruct the derived class is, for example:

class ListItem {

public:

    bool isItem = false; // stored type information

    bool isLinkedItem = false;

}

 

class Item : public ListItem {

public: 

    Item(ListItem* listItem) {

        // reconstruct this class using p_list_item details    

    }

 

    // new method declared not accessible in ListItem class.

    void Print() {

        printf("item");

    }

}


ListItem* listItem = list.front();

if (listItem->isItem) {                           // check type information

    Item* item = new Item(listItem);              // reconstruct

    list.pop();

    delete listItem;                                  // delete old object

} else if (ptr->isLinkedItem) {

    // .etc

}


This is more desirable since the type system is preserved, which means that our code can be statically verified by the compiler. Also, it has an effect on how the classes are designed. Since now our type information is being manually specified, we can potentially perform more complicated operations depending on the base types-type members, for example:

if (listItem->isItem && !listItem->isLinked && listItem->isBack) { // reconstruct // }


Friday, 13 November 2020

Abstraction function, representation invariant

Abstraction Function & Rep invariant

The abstraction functions map values in a class to the abstract concept's required values. The representation invariants are those values that satisfy the abstraction function. By asserting the abstraction function we create the link (abstraction) from ints and string to our concept. This can be seen as giving the class meaning.

The abstraction funtion is like a filter that only allows values past which correctly describe the abstract concept.

 

http://web.mit.edu/6.005/www/fa14/classes/09-af-ri-equality/
Figure 1 - RatNum ADT
 

Example

Below ZeroNumber is the concept we want to create. We represent it with a float however the concept requires that it only represents the number 0. Therefore we assert the abstraction function on the inValue and discard any values which are not rep invariants, this results in our classes concept (of being zero) being enforced.

class ZeroNumber {
public:
    ZeroNumber(float inValue) {
        assert(inValue == 0.0f);     (2. Assertion for rep invariants)
        value = inValue;
    }
private:
    float value;  (1. Representation)
}

The abstraction function here is that the ZeroNumber class must be a number that can only be 0.

The rep invariants here are all values of (inValue) that are 0.0f.  In order for abstration function to hold the assertion (2) must hold since only rep invariants are allowed.

References

  • http://web.mit.edu/6.005/www/fa14/classes/09-af-ri-equality/
  • Object-oriented Software Construction, 1st Edition Bertrand Meyer

Tuesday, 10 November 2020

Object interface design - telling it to do something vs doing something to it

 An object represents a concept otherwise known as a "thing" or noun. Traditionally, we're taught that you can create an object then tell it what to do, however, this design (coming from Alan Kay) actually results in a mess of global state (which is the usual complaint about OOP). A more appropriate view is a little more complicated, we can create an object but we must define what we can do TO it.

For example you can Squeeze an Orange, therefore the object Orange has the Squeeze method. Traditionally it would be modelled as Person.Squeeze(Orange) however, here you aren't actually doing something TO the person object you are telling the person to do SOMETHING.

Friday, 6 November 2020

Mixing DDD , OOP and Modularity


The world map is a model of the Earth, it tries to solve a specific problem of planning shipping routes. As you can see Greenland is much much bigger than it is in reality, but this is because the purpose of the map is to find angles to sail, not to display the relative sizes of parts of the world. This is the most important concept for DDD because when we write software (using OOP in particular, more on this later) we are actually solving a problem by creating a model (since OOP based upon concepts and 'real things')  

For example when creating a program that models an air conditioning fan (it could be anything, a network, architecture, command processor) we need to find out what problem exactly we are trying to solve with the model. You can try to model the fan taking into account everything such as its weight, colour, year of purchase.etc but if you place a problem ontop of the model, you can really simplify your model down to an elegant solution. This is very important since software complexity is the major battle we have when creating programs.

In software we aim to create highly modular programs. We do this because it makes the software easier to create and maintain since we only have to think about a small set of things at a time.

Using the OOP paradigm, objects are supposed replicate real-life things (as Bertrand Meyer puts) as a "cousin twice removed" from reality. So, to modularize our OOP programs into simplified models provides a perfect match. 

  1. OOP for modelling concepts as objects.
  2. Models made from objects for solving a problem.
  3. Models divided into contexts to modularize our software.

Some links

Here is the talk Eric gives that explains it: https://youtu.be/pMuiVlnGqjk?t=1789

It's very difficult to summarise such a large topic but here are some links that explain the concepts.

  1. https://www.win.tue.nl/~wstomv/edu/2ip30/references/criteria_for_modularization.pdf
  2. https://martinfowler.com/bliki/UbiquitousLanguage.html
  3. https://martinfowler.com/bliki/BoundedContext.html

 



Tuesday, 3 November 2020

OOP Tell dont ask and SRP

Background

Tell dont ask and SRP seem to be conflicting principles, one says to make the object do the work and the other says that each object should only change for one reason (meaning it must be responsible for 1 logical part). So how do we design our programs to conform to both of these principles when an object theoretically does more than one thing?

Protected state, released state

Tell don't ask is actually about querying the state an object, making a decision on that queries state, and then changing the state of that object. So its not saying that you can't query the objects, but just that state changes must happen from within. In relation to Commands and Queries, Queries cannot change the internal state or release write-access to any of the internal state which fits with the tell don't ask principle.

Creating tiny objects

The SRP is about making each object do one thing, it is self explanitory in that a single object must have a defined singular purpose. Often it requires a very high level of granularity which can be found by using very specific bounded contexts e.g. namespaces/nested classes.

Well formed objects, well formed designs

We can combine both together by recognizing that the Tell-Dont-Ask does not mean that you cannot query data from it. So we can create small, axiomatic objects that can be queried by other small objects for the information they need.

Shopping for an objects interface

One problem is that its hard to decide what should be exported by the object and what shouldn't. There are many opinions on how it should be done, but, i find that Bertrand Meyers explanation is most mathematically sound. https://richardbamford.blogspot.com/2020/10/commands-queries-and-side-effects.html . The subject is huge and there are hundreds of sources of information from everywhere!

Friday, 30 October 2020

OOP Object interfaces and decomposing the blob class

Introduction

The interface of the object should provide meaningful services to clients. A problem arises when too many jobs are assigned to one class of object for example a client object:

class Client {

public:

    void Authenticate();

    void SendMessageToChat();

    void JoinChatRoom();

    void LeaveChatRoom();

    void JoinGroup();

    // etc

}

Looks fine and useful but why does the client contain the information to manage groups and chat rooms?

Interface beauty and implementation blob

This object looks fine from the interface point of view and incredibly useful in that all the functions you need are in one place. But, it suggests a problem with the implementation behind the interface. The problem doesn't seem to be the interface semantically/syntactically but a problem in terms of information.

Since the Client's interface is the set of operations on the Client object, why does the client object contain the information to manage chat rooms, groups and all the other objects? The Client object holds way too much information about the rest of the system. This is known as a "God class" or "Blob".

Decomposing the blob

A solution for this would be to seperate the client object into further important concepts:

class Server;
class User;

class Client {

public:

    void Authenticate(Server& server);

}

class ChatRoom {

public:

    void Join(User& user);

    void Leave(User& user);

    void Post(User& user, string message);

}

class Group {

public:

    void Join(User& user);

    void Leave(User& user);

}

Here the information is spread across meaningful objects in the system which is more desireable since now each object can be thought of and maintained individually (for example assigning multiple people on each object instead of all on the client object).

Paraphrasing the collaboration, Subject not object

Additionally there error made in the design in the original client class is that the client object is not viewed as the subject of the methods calls. For example; the object method SendMessageToChat() could be paraphrased as "tell the client to send a message to the chat" or "the client can send a message to the chat" but in these phrases the subject is Chat not Client. This is a confusing notion however its simplifed if you remember that an object is the subject of its methods and wording the class collaboration appropriatly. The original client seems to be a functional decomposition instead of a data abstraction view.

Conclusion

When creating objects, always remember that the object is the subject and to carefully paraphrase the collaborations.

Tuesday, 20 October 2020

Commands, queries and side-effects (object interface design)

Commands and queries

"A machine has 2 types of buttons, command and query buttons. When a command button is pressed, the machine performs work and its state is modified. When a query button is pressed, the machine returns some information about it." - Bertrand Meyer

Command corresponds to procedures, they do not return any results. For example:

class MyMachine {

public:

    void SetName(const char * name); // is a command/procedu

}

Query corresponds to functions or attributes, for example:

class MyMachine {

public:

    void SetName(const char * name);     // command/procedure

    const char * GetName() const;        // query/function        

    bool ProcessingReady() const;        // query/attribute

private:

    const char * name;

}


Side effects

 "A side effect on an object is an operation that may change at least one attribute of the object."

The above command and query view is important with relation to side effects since  according to Bertrand Meyer in his book XXX (Chapter 7.7.2 "Commands and queries", Page 134)...

"The clean seperation between procedures and functions averts many of the pitfalls of traditional programming. Side-effect-producing functions, which have been elevated by some langauges (C seems to be the most extreme example) to the status of an institution, conflict with the classical notion of function in mathematics. A mathematical function will always give the same result when applied to the same argument."

Conclusion

From this information, we can create better class interfaces and keep them "more true" to the mathmatical foundation of abstract data type theory. This means that our code is closer to "formal verification" than guesswork.



Wednesday, 7 October 2020

ADT, type theory and set theory.

Intro

Mathematical models underpin most (arguably all) software, to create models we need to understand the bits that make them. Sets, types, algebraic structures.

Type and set theory provide the formal definitions for programming today. I believe that understanding how these pieces fit together we can create "better" software; more readable, easier to debug.

There is a saying that "the ideal solution for a professor to a problem was to introduce 10 classes instead of creating 1 function" and i think that this blog post might shed light on it. By distinguishing Types from Sets from Algebraic Structures and ADTs.

Sets and types

Sets and types are similar concepts and can both be thought about at a high level.

  1. They are used in logic.
  2. They are used to create models.

Since programming is about representing concepts and creating models, sets and types are important.

An example of a type is PERSON, and using programming we can represent this type in many ways, the most common is by using classes. Therefore we can create a class called PERSON which represents the type PERSON. Also, we can view the PERSON type as a set, it is identical to the type view.

class PERSON {
public:
 void Op();
private:
 bool HasName();
private:
 int data;
};

Algebraic structure as ADT as set/type

An algebraic structure is defined as a carrier set, operations, axioms and distinguished members. The above classes are expressed as an Abstract Data Type. Where PERSON is the carrier set (or type), operations are Op(), and an example of an explicit axiom is HasName().

Since we can represent algebraic structures with an ADT. And algebraic structures can represent types/sets, therefore, we can represent types/sets with an ADT. This is recursive definition where we can represent a set of a set using two ADTs.

Conclusion

By using classes we have bound the operations to the type/set explicitally, this means we can more easily represent individual types than individual sets. However, the unification of the two means that while programming, "names run out" and we often find ourselves creating strange types to manage types. However, if we seperate the carrier set and the operations that perform on it, we can create more sensible programs. To summarise; by using classes to create individual types and favouring modules over types to perform functions. We might end up with better sematic and formalized programs.

Seperating OOP objects and modules using this as our reasoning gives us a huge amount of flexibility with how we structure our programs. On the one hand we can create descriptive real-life heirarchies by following the type view, where PERSON is-a HUMAN and using polymorphism for dynamic dispatch. On the other hand we can functionally decompose the programs system into modules which more directly represent what the software is doing.

I believe that a common error with modern OOP (where real life concept=object) is that everything is strictly a type, and never viewed as a algebraic structure. Functions are bound to the objects as types and then more types are created to hold functions that manage other types. Now this view may seem ideal, and represent real life perfectly where say; a chest holds and number of items, however as we can see above, type theory is not the only way to create programs. This is reflected with Java, with a heavy use of type theory the application can be overly verbose and make abstractions that are wasteful and make no sense.

References

  1. https://en.wikipedia.org/wiki/Abstract_data_type
  2. https://en.wikipedia.org/wiki/Algebraic_structure
  3. Discrete Mathematics in Computer Science - STANAT, DONALD F - 1977 - ISBM 0-13-2160528 - Chapter 7 Algebras, 7.1 Structure of algebras

Sunday, 20 September 2020

Computer Science Reference List

CS Reference List

This is a collection of papers, websites and books that I have found useful when researching into computer science. Mainly into programming paradigms and languages, focusing on understanding OOP

OOP



Phenomena and Concepts

Website

http://people.cs.aau.dk/~normark/oop-csharp/html/notes/intro-oop_themes-phen-concepts-sect.html

About

Learning how objects relate to philosophical concepts and phenomena, provides a starting point to model objects.

Archived

  • Wayback machine (20/09/2020)

Specialization of classes

Website

http://people.cs.aau.dk/~normark/oop-csharp/html/notes/inheritance_themes-specialization-sect.html#inheritance_specialization-sect_section-title_1

About

A description of inhertiance using sets.

Archived

  • Wayback machine (20/09/2020)

A Tour of C++

Blog post

https://www.informit.com/articles/article.aspx?p=25003

Archived

  • Wayback machine (all pages available 20/09/2020)

Programming with abstract data types

PDF

https://dl.acm.org/doi/10.1145/942572.807045

About

Barbara Liskov defines the concept of an ADT which underpins OOP classes.

Archived

  • Present on the ACM website (27/12/2020)

A universal modular ACTOR formalism for artificial intelligence

PDF

https://dl.acm.org/doi/10.5555/1624775.1624804

About

A paper that describes how OOP classes can become functional entities.

Archived

  • Present on the ACM website (27/12/2020)

ALGOL bulletin No. 21 - AB21.3.6 "Record Handling"

About

An old ALGOL bulletin paper that defines records and their relation to types.


Record handling

URL

https://www.computerhistory.org/collections/catalog/102724664

About

C.A.R Hoare defines classes and subclasses.


On Understanding Data Abstraction

About

This paper describes what the difference between an Object (OOP) and ADT (abstract data type) is.


SIMULA INFORMATION - Common Base Language





Modules



Criteria for modularity

About

A white paper describing how to modularize a program.

Archived

  • Google drive (20/09/2020)

C++



CUED - C++ Namespaces

URL

CUED C++ Namespaces

About

Relating namespaces to Contexts (DDD).

Archived

  • Wayback machine (27/12/2020)

Sunday, 6 September 2020

OOP Quotes 1: ADT vs Object

From: "On Understanding Data Abstraction, Revisited. William R. Cook"

 "in modern object-oriented languages, the issue boils down to whether or not classes are used as types. In a pure object-oriented style, classes are only used to construct objects, and interfaces are used for types. When classes are used as types, the programmer is implicitly choosing to use a form of abstract data type."

 

"To summarize, when a class name is used as a type, it represents an abstract data type"

 

"Object-Oriented Programming in Java

While Java is not a pure object-oriented language, it is possible to program in a pure object-oriented style by obeying the following rules

Classes only as constructors: A class name may only be used after the keyword new.

No primitive equality: The program must not use primitive equality (==). Primitive equality exposes representation and prevents simulation of one object by another. "


"Objects work with interfaces as types"

"OOP is using dynamic dispatch, ADT does not"

"ADT work with class as types"



Example ADT:

C++

class Person {}

Person p = new Person();

C

struct set rep; // representation is not defined in header  

typedef struct set rep* set;
set empty();
bool isEmpty(set s);

set insert(set s, int i); 

bool contains(set s, int i); 

set union(set s1, set s2);

 

 

Example Objects:

class PersonManager {};

 
class PersonSystem {

    void printName(Person p) {}

    PersonManager m_manager;

};

Person p = new Person();

PersonSystem.printName(p);



Monday, 24 August 2020

C++ Interfaces Explained

When designing a program, using interfaces improves the program by drastically lowering coupling.

This first diagram, we can see that the EntityManager depends on the Renderer class. This is bad because programs should "depend upon abstractions not concretions", if the Renderer class changes then EntityManager will break too.

Therefore we should 'fix' the Renderers interface so that other class that use the Renderer, will not have to be changed when the renderer functions change. To do this we use what is called an "Interface" class (interface in Java and C# are natively supported but not in C++). The "Interface" class is in fact a PIMPL (pointer to implementation) used to create the boundary between implementation and abstraction.

An "Interface" class in C++ is a polymorphic base class with no implementation (code,data.etc) just function signatures. The reason why it holds nothing but function signatures. One reason why an interface has no implementation is because (see example double-dispatch below) the "Interface" classes can be forward declared and linked at link time, this means the "Interface" class can't contain any implementation, only function signatures, otherwise we receive "Duplicate Symbols" error from the linker when we try to use them.

Without interface
Without the IRenderer interface

This second diagram shows the Renderer concrete class, they are exactly the same other than Renderer is replaced with the abstract polymorphic class "IRenderer" to seperate the Renderer heirachy from the EntityManager.

With the IRenderer interface


IRenderer interface /PIMPL

Although it might seem redundant to duplicate the Renderer interface as IRenderer, it is infact a cornerstone of "Designing by contract", using interfaces you can define contracts between class heirachies.

Sunday, 19 April 2020

C++ Game Project - 1 - Rendering Fonts

Figured out how to render fonts using FreeType and OpenGL.

OpenGL, C++ and FreeType
Learning Points:
  • Orthographic projections and the device coordinate system.
  • Font metrics and FreeType library.
  • Resource Pools and Factory designs.
  • GLM library.

References:
  1. https://www.freetype.org/freetype2/docs/tutorial/step2.html
  2. https://open.gl/
  3. https://learnopengl.com/In-Practice/Text-Rendering

The difference between class and object.

 The difference between class and object is subtle and misunderstood frequently. It is important to understand the difference in order to wr...