Events and Delegates – Part 3 of 3

19. November 2020 13:14 by Parakh in   //  Tags:   //   Comments

In part 2 of this series, I introduced delegates as the implementation of the callback mechanism in .net. We saw how a delegate act as a pipeline connecting code that generates information to the code that uses that information.

In this post, I will introduce events and how they fit neatly into the entire picture and complement the abstraction that we started with delegates.

Non-Technical Overview of Events

Events in real life are important occurrences which, when happen, result in something done. Similarly, events in object-oriented programming languages represent important occurrences which when exercised need something done.

Technical Overview

In the previous post we saw how we can use a delegate as a pipeline to broadcast the information from an object to the subscribers.

Events take this concept to the next level and defer the work of creating the underlying delegate to the compiler. All a developer has to worry about is creating the right kind of event that fits in the domain model.

Events can be created with the help of the “event” keyword. We have to use a user defined delegate or a .net framework provided delegate to let the compiler know what type of underlying delegate needs to be formed behind the scenes. To keep the article short and focus on understanding the concept, I will only cover the EventHandler delegate provided by the .net framework in this post.

The EventHandler delegate is provided as a ready to use delegate. Its signature comprises passing an object type and an object of the EventArgs class. The first parameter is an object of the class that exposes the event itself, and the EventArgs object represents additional information related to the emitted event that might not be contained in the object of the class itself. The delegate returns a void.

public void EventHandler (object? sender, EventArgs e);
 

To pass any event information that might not be contained in the object, we can create a user-defined class derived from EventArgs class, and provide the peripheral information and functionality related to the emitted event via properties and methods.

The concepts covered in the technical overview will become a bit clearer in the example code covered in use cases.

Use Cases of Events

Events are calls that are raised when programmed conditions are met. Some examples are:

1. To broadcast changes in an object’s state
2. To broadcast fulfilment of a condition

We saw in the previous post how we have to create additional code to register and un-register methods that want to use the delegates. With the event keyword we can bypass all that boilerplate code and directly work with events and event handlers.

Broadcast changes in an object’s state

I am going to continue an example discussed in my previous post. Human beings are sensitive to their ambient temperature. In the code below, we will create a class “Human” and broadcast the response of its object to different temperatures. In my previous post, this was implemented with the help of delegates, but in this post, I will use events to implement the same.

public class Human
    {
        // Basic properties
        public int Id { get; set; }
        public string Name { get; set; }
        public float MinTemp { get; set; }
        public float MaxTemp { get; set; }
        private string feeling;
        public string Feeling
        {
            get
            {
                return feeling;
            }
            set
            {
                feeling = value;
 
                // If there are subscribers to the OnTemperatureChanged event
                // change in Feeling property will trigger off the event
                if (OnTemperatureChanged != null)
                {
                    OnTemperatureChanged(this, new EventArgs());
                }
            }
        }
 
        // Events
        public event EventHandler OnTemperatureChanged;
 
        public Human()
        {
 
        }
 
        // User defined constructor
        public Human(int id, string name, float minTemp, float maxTemp, string feeling)
        {
            Id = id;
            Name = name;
            MinTemp = minTemp;
            MaxTemp = maxTemp;
            Feeling = feeling;
        }
 
        public void TemperatureSensation(float temperature)
        {
 
            if (temperature > MaxTemp)
            {
                // If the OnTemperatureChanged event's invocation list is not empty
                // change in Feeling property's value will trigger the event to fire off
                Feeling = "I am feeling hot";
            }
            else if (temperature < MinTemp)
            {
                Feeling = "I am feeling cold";
            }
            else
            {
                Feeling = "I am feeling normal";
            }
        }
    }

In the code above, we have a class "Human" with five properties, of which three are of importance - MinTemp, MaxTemp and Feeling. The method TemperatureSensation accepts a float type parameter and depending on where the value stands in the spectrum between MinTemp and MaxTemp, sets the value of the Feeling property. We have an explicit implementation of the Feeling property and if there are subscribers to the OnTemperatureChanged event, it fires off when the value of the Feeling property’s underlying variable is set to a new value. In the following code, we create an object of the Human class and test the functionality of event declared in the Human class.

class Program
    {
        static void Main(string[] args)
        {
            Human human = new Human() 
            {
                Id = 1,
                Name = "Parakh Singhal",
                MaxTemp = 45f,
                MinTemp = 10f, 
                Feeling = null
            };
 
            human.OnTemperatureChanged += OnTemperatureChangeHandler;
 
            human.TemperatureSensation(8f);
            human.TemperatureSensation(25f);
            human.TemperatureSensation(50f);
 
            Console.WriteLine("Press any key to terminate the program...");
            Console.ReadKey();
        }
 
        public static void OnTemperatureChangeHandler(object sender, EventArgs e)
        {
            if (sender is Human)
            {
                Human human = sender as Human;
                Console.WriteLine(human.Feeling);
            }
        }
    }

 

In the code above we created an object of the Human class and instantiated it with some data. Then, we enrolled in a method “OnTemperatureChangeHandler” that matched the “OnTemperatureChanged“ event’s underlying delegate’s signature and return type. Then we invoked the TemperatureSensation method on the human object which then broadcasted the messages to the event’s subscribed members.

The code when executed provides the following output:

3 of n 01 Object State

Contrast this code with the one created in the previous post, where not only we operated on the back of a delegate object, but also created the registration and un-registration methods for the methods to get enrolled in the delegate’s invocation list, to prevent direct access to delegate object’s invocation list. We also had more lines of programming as we had to trigger off the delegate wherever the state of the object was deemed to change. The new code is not only concise but also more maintainable.

Here we leverage the code that gets created by C# compiler for us. The event keyword, behind the scenes gets expanded into a delegate accepting the standard input parameters of an object type and an EventArgs class object and returning a void. We can then enrol methods with the same signature and return type, using the overridden “+” operator. Methods can be un-registered using the “-“ operator.

Broadcast of fulfilment of a certain condition

Some conditions when they get fulfilled, warrant an intimation. The information about the fulfilment of condition is broadcasted via events and the subscribers then process the information as they deem fit.

Let’s take an example of a library where the information about successful checkout of a book is processed.

 

public class Author
    {
        public int AuthorId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
public class Book
    {
        public int BookId { get; set; }
        public string ISBN { get; set; }
        public string Title { get; set; }
        public Author Author { get; set; }
        public int PageCount { get; set; }
        public bool IsCheckedOut { get; set; }
    }
public class Member
    {
        public int MemberId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int NumberOfBooksCheckedOut { get; set; }
        public List<Book> BooksCheckedOut { get; set; }
    }
public Library()
        {
            Books = new List<Book>()
                        {
                            new Book()
                            {
                                BookId = 1,
                                Title = "Alice in Wonderland",
                                IsCheckedOut = false,
                                PageCount = 200,
                                Author = new Author()
                                {
                                    AuthorId = 1,
                                    FirstName = "Lewis",
                                    LastName = "Carroll"
                                }
                            },
                            new Book()
                            {
                                BookId = 2,
                                Title = "Bad Blood",
                                IsCheckedOut = false,
                                PageCount = 350,
                                Author = new Author()
                                {
                                    AuthorId = 2,
                                    FirstName = "John",
                                    LastName = "Carreyrou"
                                }
                            },
                            new Book()
                            {
                                BookId =  3,
                                Title = "The Dream Machine",
                                IsCheckedOut = false,
                                PageCount = 250,
                                Author = new Author()
                                {
                                    AuthorId = 3,
                                    FirstName="Mitchell",
                                    LastName = "Waldrop"
                                }
                            },
                            new Book()
                            {
                                BookId = 4,
                                Title = "The Structure of Scientific Revolution",
                                IsCheckedOut = false,
                                PageCount = 500,
                                Author = new Author()
                                {
                                    AuthorId = 4,
                                    FirstName = "Thomas",
                                    LastName=  "Kuhn"
                                }
                            },
                            new Book()
                            {
                                BookId =5,
                                Title = "Sapiens: A Brief History of Humankind",
                                IsCheckedOut = false,
                                PageCount = 450,
                                Author =new Author()
                                {
                                    AuthorId = 5,
                                    FirstName = "Yuval",
                                    LastName = "Hariri"
                                }
                            }
                        };
            Members = new List<Member>()
                        {
                            new Member()
                            {
                                MemberId = 1,
                                FirstName = "Parakh",
                                LastName = "Singhal",
                                NumberOfBooksCheckedOut = 0
                            },
                            new Member()
                            {
                                MemberId = 2,
                                FirstName = "Prateek",
                                LastName = "Mathur",
                                NumberOfBooksCheckedOut = 0
                            },
                            new Member()
                            {
                                MemberId =3,
                                FirstName = "Sumant",
                                LastName = "Sharma",
                                NumberOfBooksCheckedOut = 0
                            }
                        };
        }
 
        public void CheckOutBook(int memberId, int bookId)
        {
            Book book = Books.Find(book => book.BookId == bookId);
            Member member = Members.Find(member => member.MemberId == memberId);
 
            if (book.IsCheckedOut)
            {

Console.WriteLine("Apologies, but book is already checked out.

Please select another book.");

            }
            else if (member.NumberOfBooksCheckedOut >= 2)
            {

Console.WriteLine("Apologies, but there are already 2 books

checked out to you.");

            }
            else
            {
                book.IsCheckedOut = true;
                member.NumberOfBooksCheckedOut += 1;

OnSuccessfulCheckOut?.Invoke(this,

new LibraryEventArgs() { Message = "Checkout of book is successful" });

 
            }
        }
    }
 
public sealed class LibraryEventArgs : EventArgs
    {
        public string Message { get; set; }
    }

 

The model created above is consumed in the console application.

class Program
    {
        static void Main(string[] args)
        {
            Library library = new Library();
 
            library.OnSuccessfulCheckOut += CheckoutSuccessfulEventHandler;
 
 
            library.CheckOutBook(1, 1);
 
            Console.WriteLine("Press any key to exit the program...");
            Console.ReadKey();
        }
 
        private static void CheckoutSuccessfulEventHandler(object sender, EventArgs e)
        {
            if (sender is Library && e is LibraryEventArgs)
            {
                LibraryEventArgs libraryEventArgs = e as LibraryEventArgs;
                Console.WriteLine(libraryEventArgs.Message);
            }
        }    
}

 

When executed the following output appears:

3 of n 02 Object State

The example shows usage of event for emitting information for an important activity with the help of event. In the example when the book is successfully checked out, the event OnSuccesfulCheckOut is fired, provided that the underlying delegate’s invocation list is not empty, and the information regarding the successful checkout of the book is emitted to the subscribed event handlers.

Summary

Delegates help separation with the process of emitting the information and processing that information, events take things to the next level by raising the level of abstraction and using a more natural vocabulary.

I hope that this post helped you in rounding out the concept of events and delegates and how events are built on the foundation of delegates, which is the reason, delegates are discussed first in academic texts.

References

  1. Pro C# 8 with .NET Core 3 by Andrew Troelsen and Phil Japikse
  2. CLR via C# by Jeffrey Richter

Delegates And Events – Part 2 of 3

19. November 2020 12:42 by Parakh in Visual C#  //  Tags: ,   //   Comments
This post explains the concept of delegates in a lucid manner, giving simple to understand code examples.

In my last post, I explained the concept of events, delegates, and event handlers at a high level. In this post, let’s take a look at delegates. Why delegates and not events, because among them, they are the tricky ones and can be understood in relative isolation.

Delegates form the glue connecting the events and event handlers and are instrumental in conveying to all the subscribed event handlers about the firing of an event. What I will try to show in this post are the following:
1. High-level conceptual coverage of delegates,
2. Technical overview of delegates,
3. How a delegate can execute a connected method, aka an event handler

High-Level Overview:

Consider the following scenario where you have a pipeline going out from a pumping station and connected to that pipeline are houses and industries. Houses will use the supplied water for cleaning, cooking, etc. while the industries will use the same water for chemical and other manufacturing purposes. Water Pumping station supplying water to homes and industries


 

The pumping station here is synonymous with an event firing when an action of interest takes place. The water is the information conveyed by the event, and the houses and industries are the event handlers which process the supplied water, aka the information in the desired form. Delegates form the plumbing connecting the events and event handlers.

Before we move any further, we must understand what is a callback mechanism.

Callback Mechanism

Essentially, a callback mechanism that lets us chain pieces of code together in such a way that the first piece calls the second. The call can be made in two ways:

1) Synchronous callbacks, in which the first code (calling code) waits for the second code (called code) to finish the work and deliver the result, and, only after that resumes execution.
E.g. You can have a windows form application which has a button which upon clicking starts execution of a long running process. While the process is running the windows form will remain unresponsive.

2) Asynchronous callbacks, where the first code calls the second code but does not wait for it to finish the work. The work by the second piece of code is carried out on a different thread.

Callback mechanism is known by different names in different programming languages. In C, it is known as function pointers, and in C# it is called “delegates”.

In C#, delegates form the plumbing that allows one code to call another code synchronously or asynchronously. Adding to that is the fact that they are type-safe, i.e. you can only call methods that comply with the delegate’s signature and return type. In this post we will focus only on the synchronous calling via delegates

Use cases for delegates

Delegates can be used in two scenarios:

1. To broadcast changes in an object’s state
2. To broadcast fulfillment of a condition

Delegates behind the scenes are a special type of class, which means that we need to create an object of delegate type to use it for callback purposes.

Let’s dive into practical examples that show the use cases in action.

Broadcast changes in an object’s state


Consider human beings and their sensitiveness to ambient temperature. We can create a class “Human” and broadcast the response of its object to different temperatures.

public class Human
    {
        // Basic properties
        public int Id { get; set; }
        public string Name { get; set; }
        public float MinTemp { get; set; }
        public float MaxTemp { get; set; }
 
        //Delegate declaration
        public delegate void TemperatureSensationHandler(string message);
 
        // Member variable of the declared delegate
        public TemperatureSensationHandler temperatureSensationMembers;
 
        public Human()
        {
        }
 
        // User defined constructor
        public Human(int id, string name, float minTemp, float maxTemp)
        {
            Id = id;
            Name = name;
            minTemp = MinTemp;
            maxTemp = MaxTemp;
        }
 
        public void TemperatureSensation(float temperature)
        {
            if (temperatureSensationMembers!= null)
            {
                if (temperature > MaxTemp)
                {
                    temperatureSensationMembers("I am feeling hot");
                }
                else if (temperature < MinTemp)
                {
                    temperatureSensationMembers("I am feeling cold");
                }
                else
                {
                    temperatureSensationMembers("I am feeling normal");
                }
            }         
        }
    }

 

In the code above, we have a class "Human" with four properties, of which two are of importance - MinTemp and MaxTemp. The method TemperatureSensation accepts a float type parameter and depending upon where the value stands in the spectrum between MinTemp and MaxTemp, broadcasts an appropriate message. In the following code, we create an object of the Human class and test the functionality of delegate declared in the Human class.

class Program
    {
        static void Main(string[] args)
        {
            Human human = new Human() 
{ Id = 1, Name = "Parakh", MinTemp = 25.5f, MaxTemp = 45.0f };
 
            human.temperatureSensationMembers += OnTemperatureSensationEvent;
            human.TemperatureSensation(100);
            human.TemperatureSensation(30);
            human.TemperatureSensation(10);
            Console.ReadLine();
        }
 
        public static void OnTemperatureSensationEvent(string message)
        {
            Console.WriteLine(message);
        }
    }

 

In the code above we created an object of the Human class and instantiated it with some data. Then, we enrolled in the delegate object a method that matched the delegate’s signature and return type. Then we invoked the TemperatureSensation method on the human object which then broadcasted the messages to the delegate’s subscribed members.

The above code when executed yields the following outputBoradcast changes in an object's state

Now there’s one flaw in the code above. Delegate class at the .Net framework level overrides the “+” and “-“ operators, allowing the subscription and unsubscription of complying methods. It means that having direct access to the delegate object is sensitive and a developer should not be able to empty a delegate object’s invocation list by using the “-“ operator repeatedly.

We thus encapsulate the subscription and unsubscription of the methods to the delegate object via methods.

public class Human
    {
        // Basic properties
        public int Id { get; set; }
        public string Name { get; set; }
        public float MinTemp { get; set; }
        public float MaxTemp { get; set; }
 
        //Delegate declaration
        public delegate void TemperatureSensationHandler(string message);
 
        // Member variable of the declared delegate
        private TemperatureSensationHandler temperatureSensationMembers;
 
        //Registration and un-registration methods
        public void RegisterTempSensationHandlerMethods(TemperatureSensationHandler methodToRegister)
        {
            temperatureSensationMembers += methodToRegister;
        }
 
        public void UnRegisterTempSensationMethods(TemperatureSensationHandler methodToUnregister)
        {
            if (temperatureSensationMembers != null)
            {
                temperatureSensationMembers -= methodToUnregister;
            }
        }
 
        public Human()
        {
 
        }
 
        // User defined constructor
        public Human(int id, string name, float minTemp, float maxTemp)
        {
            Id = id;
            Name = name;
            minTemp = MinTemp;
            maxTemp = MaxTemp;
        }
 
        public void TemperatureSensation(float temperature)
        {
            if (temperatureSensationMembers!= null)
            {
                if (temperature > MaxTemp)
                {
                    temperatureSensationMembers("I am feeling hot");
                }
                else if (temperature < MinTemp)
                {
                    temperatureSensationMembers("I am feeling cold");
                }
                else
                {
                    temperatureSensationMembers("I am feeling normal");
                }
            }         
        }
    }

With the modified code, we now can register and un-register the methods without exposing the delegate object to a developer.

The code above yields the same output.

Boradcast changes in an object's state

Broadcast of fulfilment of a condition


Some conditions warrant broadcast of information when they materialize. Examples would include intimation upon sending or receiving a message, dispatch, and delivery of a physical item in case of e-commerce applications, etc.

Here we will take an example of checking out a book from a library.

We have four classes - Book, Member, Author, and Library. The idea in this example is to broadcast a message upon execution of certain activities like searching for a book, searching for member records, and successful or unsuccessful checking out of a book.

public class Author
   {
        public int AuthorId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
 
public class Book
    {
        public int BookId { get; set; }
        public string ISBN { get; set; }
        public string Title { get; set; }
        public Author Author { get; set; }
        public int PageCount { get; set; }
        public bool IsCheckedOut { get; set; }
    }
 
public class Member
    {
        public int MemberId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int NumberOfBooksCheckedOut { get; set; }
        public List<Book> BooksCheckedOut { get; set; }
    }
 
    public class Library
    {
        public int LibraryId { get; set; }
        public List<Book> Books { get; set; }
        public List<Member> Members { get; set; }
        public Library()
        {
            LibraryId = 1;
            Books = new List<Book>()
                        {
                            new Book()
                            {
                                BookId = 1, 
                                Title = "Alice in Wonderland", 
                                IsCheckedOut = false, 
                                PageCount = 200,
                                Author = new Author() 
                                { 
                                    AuthorId = 1, 
                                    FirstName = "Lewis", 
                                    LastName = "Carroll"
                                }
                            },
                            new Book()
                            { 
                                BookId = 2, 
                                Title = "Bad Blood", 
                                IsCheckedOut = false, 
                                PageCount = 350,
                                Author = new Author()
                                { 
                                    AuthorId = 2, 
                                    FirstName = "John", 
                                    LastName = "Carreyrou"
                                }
                            },
                            new Book()
                            { 
                                BookId =  3, 
                                Title = "The Dream Machine", 
                                IsCheckedOut = false, 
                                PageCount = 250,
                                Author = new Author()
                                { 
                                    AuthorId = 3, 
                                    FirstName="Mitchell", 
                                    LastName = "Waldrop"
                                }
                            },
                            new Book()
                            { 
                                BookId = 4, 
                                Title = "The Structure of Scientific Revolution", 
                                IsCheckedOut = false,
                                PageCount = 500, 
                                Author = new Author()
                                { 
                                    AuthorId = 4, 
                                    FirstName = "Thomas", 
                                    LastName=  "Kuhn"
                                }
                            },
                            new Book()
                            { 
                                BookId =5,
                                Title = "Sapiens: A Brief History of Humankind", 
                                IsCheckedOut = false,
                                PageCount = 450, 
                                Author =new Author() 
                                { 
                                    AuthorId = 5, 
                                    FirstName = "Yuval", 
                                    LastName = "Hariri"
                                }
                            }
                        };
            Members = new List<Member>()
                        {
                            new Member()
                            { 
                                MemberId = 1, 
                                FirstName = "Parakh", 
                                LastName = "Singhal", 
                                NumberOfBooksCheckedOut = 0
                            },
                            new Member()
                            { 
                                MemberId = 2, 
                                FirstName = "Prateek", 
                                LastName = "Mathur", 
                                NumberOfBooksCheckedOut = 0
                            },
                            new Member()
                            { 
                                MemberId =3, 
                                FirstName = "Sumant", 
                                LastName = "Sharma", 
                                NumberOfBooksCheckedOut = 0
                            }
                        };
 
        }
 
        //Delegate which can accept methods having a string parameter
        public delegate void CheckoutHandler(string message);
 
        private CheckoutHandler checkOutHandlerMembers;
 
        public void RegisterCheckOutHandlerMembers(CheckoutHandler methodToRegister)
        {
            checkOutHandlerMembers += methodToRegister;
        }
 
        public void UnRegisterCheckOutHandlerMembers(CheckoutHandler methodToUnregister)
        {
            if (checkOutHandlerMembers != null)
            {
                checkOutHandlerMembers -= methodToUnregister;
            }
        }
 
        public void CheckOutBook(int MemberId, int bookId)
        {
            //The operation of search will be printed out by the program only 
            //if there are members to the delegate type
            if (checkOutHandlerMembers != null)
            {
                checkOutHandlerMembers("Searching for book and Member records");
            }
 
            Book bookToBeCheckedOut = Books.Find(book => book.BookId == bookId);
            Member MemberCheckingOut = Members.Find(Member => Member.MemberId == MemberId);
 
            //The operation of success in finding the book and Member will
            //only be printed if there are members to the delegate type
            if (bookToBeCheckedOut != null &&
                MemberCheckingOut != null && 
                checkOutHandlerMembers != null)
            {
                checkOutHandlerMembers("Book and Member records found.");
            }
 
            if (bookToBeCheckedOut.IsCheckedOut == false)
            {

//The final result, whether the book can be checked

//out needs to be printed whether

                //there are any members to the delegate type. 
                //That's why if-else statement with duplicate
                //console writes
                if (checkOutHandlerMembers != null)
                {
                    checkOutHandlerMembers("Congratulations, the book is available");
                }
                else
                {
                    Console.WriteLine("Congratulations, the book is available");
                }
            }
            else
            {
                if (checkOutHandlerMembers != null)
                {

checkOutHandlerMembers("Apologies, but the book is already

checked out to an existing Member.");

                }
                else
                {

Console.WriteLine("Apologies, but the book is

already checked out to an existing Member.");

                }
            }
        }
    }
}

 

The model created above is consumed in the console application.

class Program
    {
        static void Main(string[] args)
        {
            Library library = new Library();
            library.RegisterCheckOutHandlerMembers(OnCheckingOutEvent);            
            library.CheckOutBook(1, 1);
            
            Console.ReadLine();
        }
 
        public static void OnCheckingOutEvent(string message)
        {
            Console.WriteLine(message);
        }
    }

 

When executed the following output appears:

Broadcast of fulfillment of a conditionIn the output shown above, the program emitted certain messages related to the searching of the member and book details and successful checkout of the book. Now, remember, the domain is responsible for emitting the information, but what we do with the information is entirely in the hands of the developer. We can compose an email or an SMS and embed the emitted message or have it logged in a log file or a database.

Summary

Delegates help in separating the act of broadcasting information and how that information is consumed.
I hope this post helped in laying a strong foundation by presenting the concept of delegates in an easy to understand manner.

References

  1. Pro C# 8 with .NET Core 3 by Andrew Troelsen and Phil Japikse
  2. CLR via C# by Jeffrey Richter

Delegates And Events–Part 1 of 3

19. November 2020 09:45 by Parakh in Visual C#  //  Tags: , ,   //   Comments
This post attempts at explaning the concept of delegates and events in C# as it relates to real life, in as simple a manner as possible.

In my experience, if there’s one topic in C# that baffles the programmers the most, it is the topic of events and delegates. And the root of the state of confusion is not the lack of attempt on the programmer’s part, but the way the books on programming languages explain the concept – in a dry academic sense, devoid of any relatability to real life.

This blog post is my attempt to explain the concept of events and delegates in an easy way.

Events in real life are occurrences where something of importance happened to an entity. Let me elaborate on that. Consider a normal human being. Events in the life of a normal human being would be:
1. Birth
2. First day of school
3. Graduation from school
4. First day of college
5. Graduation from college
6. First pay-check
7. Getting married
8. First child
…and so on. The aforementioned occurrences would normally be considered important, hence endowed with a special term, events.

Whenever an event occurs, there’s something done. Birth of a child is celebrated, graduation from school is celebrated with a farewell party, marriages are celebrated with near and dear ones, etc.

This is what is the inspiration for the abstraction, aptly called events in modern object-oriented programming languages. Events are important occurrences in the life-span of an entity. An entity can be a button in a Windows Form, a dropdown on a web page, or some kind of a custom activity in a user-defined object like a domain class. Correspondingly, the event would be pressing a button, changing the selected element in a dropdown or value of a property in a domain class.

Whenever some event occurs or gets fired, something is done. That something is done in some defined code, called the event handler. An event handler is essentially a method, with details of what needs to be done when the event is fired.

Now that we have understood the concept of events and event handlers, let’s understand the concept of delegates. Delegates are like the consciousness that pushes us to do something when an event occurs. Essentially, a delegate is the glue that ties an event and an event handler together.

To summarise:
When something of importance happens -> Event
What we do in case of an event -> Event Handler
The glue connecting the event and event handler –> Delegate

I hope that this post was able to sow the idea of events and delegates your mind in a non-technical and relatable way. In future posts, I will shed more light on the topic.

How to Create and Apply Git Patch Files

2. November 2019 09:20 by Parakh in Git  //  Tags: , , ,   //   Comments
This post explains how to create patch files using the git format-patch command and then apply them using the apply and am commands.

Introduction

In the years during which Git evolved, there was no provision of using a central remote repository which different contributors could use to merge their changes to a feature branch or request pull requests. Sending patch file(s) via email was the name of the game. A patch file is a handy way of encapsulating the changes introduced into the repository as part of a commit, into a single file. Patches can be created on a per commit basis or a bunch of commits can be squashed into a single patch file.

Git Format-Patch

The command that is used to create a patch file is format-patch. Various options are available that can be used in conjunction with the command to modify the output as desired. Let’s take a look at the most common operations that use format-patch command.

To learn about the command let’s create a repository and track a text file with some text entries.

$ mkdir PatchFiles
$ cd PatchFiles
$ git init
$ touch file1.txt
$ printf "first line" > file1.txt
$ git add .
$ git commit -m "First commit"
$ printf "\nsecond line" >> file1.txt
$ git commit -am "Second commit"
$ git log --online master

Creation of master branch

Next let’s create a branch named develop off of the master branch and track a text file with some text entries.

$ git branch develop
$ git checkout develop
$ touch file2.txt
$ printf "first line" > file2.txt
$ git add .
$ git commit -m "First commit in develop branch"
$ printf "\nsecond line" >> file2.txt
$ git commit -am "Second commit in develop branch"
$ git log --oneline

Creation of develop branch

Now that we have laid the groundwork, let’s understand the format-patch command. The format-patch command takes in the name of the branch against which you want to compare the commits of the current branch pointed to by the INDEX pointer. By default, the format-patch creates a patch file for every commit not available in the target branch.

$ git format-patch master
$ dir

Format Patch Multiple files

In earlier times, when there was no remote repository, such patch files used to be mailed by project contributors to the project maintainer.
Next, we will discuss the two commands that can be used to apply the patch files, i.e., apply and am.

Git Apply

There could be situations that demand the application of changes in a patch to the target branch, but, not include the corresponding commit message into the commit history of the target branch. Git’s apply command is used in such situations.

Apply command helps you to test out the changes introduced by the patch locally before you formally commit them into the repository. Since the changes are applied to the working directory, you can use git diff to view the changes applied. Also, the commit message can be a bit more descriptive signifying the nature of the changes applied.

Let’s see the command in action in code.

$ git checkout master
$ git apply 0001-First-commit-in-develop-branch.patch
$ git status
$ git log --oneline
$ dir

 05 Apply command - cropped

Git AM

Git’s am (Apply Mailbox) command is used in a situation when you are assured of the commits in a patch and want them to be applied verbatim, along with their corresponding metadata consisting of author’s information and commit message.

$ git checkout master
$ git am 0001-First-commit-in-develop-branch.patch
$ git status
$ git log --oneline
$ dir

06 AM command - cropped

Word of Caution

If you are selectively applying patches, and if a patch contains an artifact that comes to life in a prior patch, then the application of such a patch will fail. This is because patch files are commit-specific and carry changes specific to the commit.
In such cases, you will be required to sequentially apply patches in chronological order, first bringing the artifact into existence, followed by any changes in the artifact.

$ git checkout master
$ git am 0002-Second-commit-in-develop-branch.patch

07 Problem with patch application - cropped

 

We were not able to successfully apply the second patch as the file2.txt came into existence in the first commit, hence first patch. It would be imperative here, to first apply the first patch and then the second patch.

Conclusion

Git provides the ability to create patches as discreet units signifying the evolution of a project and enables the sharing of this evolution in the absence of a central remote repository.

Git offers two ways to apply patches as per requirements.

Git’s apply command applies the changes locally to the working directory and gives you the freedom to further introduce changes in the artifacts before formally committing into the repository.

Git’s am command applies the patches in the repository and includes the commit messages contained in the patches. It retains vital metadata like author information, email, etc..

A short note on Git Cherry-Pick

16. October 2019 13:27 by Parakh in Git, GitHub  //  Tags: ,   //   Comments
A short note demonstrating git&#39;s cherry-pick command.

Key Takeaway

In the real world, situations arise where some urgent work is done on a codebase that is required to be released to mainstream users. This work then needs to be bought down into the feature branches to maintain parity with the master branch.

In Git, we have the command of Rebase to handle such a situation, but in some cases, a more surgical approach is required, whereby, only the commit having the changes is required to be applied to the feature branch and exclude anything else which might otherwise pollute the feature branch. This is what Git’s cherry-pick command achieves.

Read On

One of the founding premises of Git is to commit often and commit early. This aspect of the foundation enables you, the user, to see the evolution of your work over time and enables Git to take the responsibility to manage the evolution in a discreet order via commits. By having small commits, you enable Git to recover your work in a granular manner, should the situation come to be, as desired. And dovetailing this practice of small and frequent discreet commits, revolves the power of the command of cherry-pick.

Git’s cherry-pick command helps you apply a commit in a surgical manner such that it only brings in the changes corresponding to a commit to the branch under concern. This command can be thought to be useful in scenarios whereby you have to bring in a limited number of changes that are pertinent to your work. Examples:
1. There’s a hotfix branch created from the master branch and you need to include the hotfix in your feature branch.
2. There are a couple of commits that you need to take from some other feature branch and incorporate in your branch

Let’s take a look at an example to understand the cherry-pick command.

$ mkdir cherrypick
$ cd cherrypick
$ git init
$ touch file1.txt
$ printf "first line" > file1.txt
$ git add .
$ git commit -m "First commit in master branch"
$ printf "\nsecond line" >> file1.txt
$ git commit -am "Second commit in master branch"
$ printf "\nthird line" >> file1.txt
$ git commit -am "Third commit in master branch"
$ git branch develop
$ git checkout develop
$ touch file2.txt
$ printf “first line” >> file2.txt
$ git add .
$ git commit -m “First commit in develop branch”
$ printf “\nsecond line” >> file2.txt
$ git commit -am “Second commit in develop branch”
$ printf “\nthird line” >> file2.txt
$ git commit -am “Third commit in develop branch”
$ git checkout master
$ git log --oneline develop
$ git cherry-pick SHA1 hash of the second commit from the develop branch

 

Resolve any conflicts that arise from the cherry pick here and then run a git log

$ git log --oneline master

 

In this example, we created a directory aptly named cherrypick and then inserted some text entries into a text file named file1.txt. We then created a branch called develop from the master branch. In the develop branch we created some entries in a text file named file2.txt and then moved back to the master branch. Now listed the log entries from the develop feature branch and noted down the SHA1 hash of the commit corresponding to which we want to pick the changes from the develop branch. In this case, we picked the second commit from the develop branch.

01 Creation of repoFigure 1 Creating the repository and some initial commits

02 In Develop BranchFigure 2 Creation of a branch and some initial commits

03 In Develop BranchFigure 3 Going back to the branch where a cherry-picked commit needs to be merged

Finally, we used Git’s cherry-pick command in the master branch in conjunction with the SHA1 hash noted before. This will bring in the changes from the develop branch into the master branch that were made corresponding to the commit hash. In doing so, you may be required to resolve any conflict that may arise.

04 In Master BranchFigure 4 Process of cherry picking may throw up some conflicts which would require intervention

05 In Master BranchFigure 5 Once a commit is cherry picked, its content will then become available in the target branch

This way we can literally cherry-pick the changes corresponding to specific commit(s) in a branch and bring them to the branch of our choice.

Hope this was helpful.

Month List

ParakhSinghal@Twitter.com

Note: For Customization and Configuration, CheckOut Recent Tweets Documentation