Tuesday, April 19, 2011

Shallow vs. deep copying

Shallow copying
Because C++ does not know much about your class, the default copy constructor and default assignment operators it provides use a copying method known as a shallow copy (also known as a memberwise copy). A shallow copy means that C++ copies each member of the class individually using the assignment operator. When classes are simple (eg. do not contain any dynamically allocated memory), this works very well.
For example, let’s take a look at our Cents class:

class Cents {
private:
int m_nCents;
public:
Cents(int nCents=0)
{
m_nCents = nCents;
}
};
When C++ does a shallow copy of this class, it will copy m_nCents using the standard integer assignment operator. Since this is exactly what we’d be doing anyway if we wrote our own copy constructor or overloaded assignment operator, there’s really no reason to write our own version of these functions!
However, when designing classes that handle dynamically allocated memory, memberwise (shallow) copying can get us in a lot of trouble! This is because the standard pointer assignment operator just copies the address of the pointer — it does not allocate any memory or copy the contents being pointed to!
class MyString
{
private:
char *m_pchString;
int m_nLength;
public:
MyString(char *pchString="")
{
// Find the length of the string
// Plus one character for a terminator
m_nLength = strlen(pchString) + 1;
// Allocate a buffer equal to this length
m_pchString= new char[m_nLength];
// Copy the parameter into our internal buffer
strncpy(m_pchString, pchString, m_nLength);
// Make sure the string is terminated
m_pchString[m_nLength-1] = '\\0';
}


~MyString() // destructor
{
// We need to deallocate our buffer
delete[] m_pchString;
// Set m_pchString to null just in case
m_pchString = 0;
}
char* GetString() { return m_pchString; }
int GetLength() { return m_nLength; }
};
The above is a simple string class that allocates memory to hold a string that we pass in. Note that we have not defined a copy constructor or overloaded assignment operator. Consequently, C++ will provide a default copy constructor and default assignment operator that do a shallow copy.
MyString cHello("Hello, world!");
{
MyString cCopy = cHello; // use default copy constructor
} // cCopy goes out of scope here
std::cout << cHello.GetString() << std::endl; // this will crash While this code looks harmless enough, it contains an insidious problem that will cause the program to crash! Can you spot it? Don’t worry if you can’t, it’s rather subtle. Let’s break down this example line by line: MyString cHello("Hello, world!"); This line is harmless enough. This calls the MyString constructor, which allocates some memory, sets cHello.m_pchString to point to it, and then copies the string “Hello, world!” into it. MyString cCopy = cHello; // use default copy constructor This line seems harmless enough as well, but it’s actually the source of our problem! When this line is evaluated, C++ will use the default copy constructor (because we haven’t provided our own), which does a shallow pointer copy on cHello.m_pchString. Because a shallow pointer copy just copies the address of the pointer, the address of cHello.m_pchString is copied into cCopy.m_pchString. As a result, cCopy.m_pchString and cHello.m_pchString are now both pointing to the same piece of memory! } // cCopy goes out of scope here Now you can see why this crashes. We deleted the string that cHello was pointing to, and now we are trying to print the value of memory that is no longer allocated. The root of this problem is the shallow copy done by the copy constructor — doing a shallow copy on pointer values in a copy constructor or overloaded assignment operator is almost always asking for trouble. Deep copying
The answer to this problem is to do a deep copy on any non-null pointers being copied. A deep copy duplicates the object or variable being pointed to so that the destination (the object being assigned to) receives it’s own local copy. This way, the destination can do whatever it wants to it’s local copy and the object that was copied from will not be affected. Doing deep copies requires that we write our own copy constructors and overloaded assignment operators.
Let’s go ahead and show how this is done for our MyString class:
// Copy constructor
MyString::MyString(const MyString& cSource)
{
// because m_nLength is not a pointer, we can shallow copy it
m_nLength = cSource.m_nLength;
// m_pchString is a pointer, so we need to deep copy it if it is non-null
if (cSource.m_pchString)
{
// allocate memory for our copy
m_pchString = new char[m_nLength];
// Copy the string into our newly allocated memory
strncpy(m_pchString, cSource.m_pchString, m_nLength);
}
else
m_pchString = 0;
}

As you can see, this is quite a bit more involved than a simple shallow copy! First, we have to check to make sure cSource even has a string (line 8). If it does, then we allocate enough memory to hold a copy of that string (line 11). Finally, we have to manually copy the string using strncpy() (line 14).
Now let’s do the overloaded assignment operator. The overloaded assignment operator is a tad bit trickier:
// Assignment operator
MyString& MyString::operator=(const MyString& cSource)
{
// check for self-assignment
if (this == &cSource)
return *this;
// first we need to deallocate any value that this string is holding!
delete[] m_pchString;
// because m_nLength is not a pointer, we can shallow copy it
m_nLength = cSource.m_nLength;
// now we need to deep copy m_pchString
if (cSource.m_pchString)
{
// allocate memory for our copy
m_pchString = new char[m_nLength];
// Copy the parameter the newly allocated memory
strncpy(m_pchString, cSource.m_pchString, m_nLength);
}
else
m_pchString = 0;
return *this;
}
Note that our assignment operator is very similar to our copy constructor, but there are three major differences:
• We added a self-assignment check (line 5).
• We return *this so we can chain the assignment operator (line 26).
• We need to explicitly deallocate any value that the string is already holding (line 9).
When the overloaded assignment operator is called, the item being assigned to may already contain a previous value, which we need to make sure we clean up before we assign memory for new values. For non-dynamically allocated variables (which are a fixed size), we don’t have to bother because the new value just overwrite the old one. However, for dynamically allocated variables, we need to explicitly deallocate any old memory before we allocate any new memory. If we don’t, the code will not crash, but we will have a memory leak that will eat away our free memory every time we do an assignment!

Checking for self-assignment
In our overloaded assignment operators, the first thing we do is check for self assignment. There are two reasons for this. One is simple efficiency: if we don’t need to make a copy, why make one? The second reason is because not checking for self-assignment when doing a deep copy will cause problems if the class uses dynamically allocated memory. Let’s take a look at an example of this.
Consider the following overloaded assignment operator that does not do a self-assignment check:
// Problematic assignment operator
MyString& MyString::operator=(const MyString& cSource)
{
// Note: No check for self-assignment!
// first we need to deallocate any value that this string is holding!
delete[] m_pchString;
// because m_nLength is not a pointer, we can shallow copy it
m_nLength = cSource.m_nLength;
// now we need to deep copy m_pchString
if (cSource.m_pchString)
{
// allocate memory for our copy
m_pchString = new char[m_nLength];
// Copy the parameter the newly allocated memory
strncpy(m_pchString, cSource.m_pchString, m_nLength);
}
else
m_pchString = 0;
return *this;
}

What happens when we do the following?
cHello = cHello;
This statement will call our overloaded assignment operator. The this pointer will point to the address of cHello (because it’s the left operand), and cSource will be a reference to cHello (because it’s the right operand). Consequently, m_pchString is the same as cSource.m_pchString.
Now look at the first line of code that would be executed: delete[] m_pchString;.

This line is meant to deallocate any previously allocated memory in cHello so we can copy the new string from the source without a memory leak. However, in this case, when we delete m_pchString, we also delete cSource.m_pchString! We’ve now destroyed our source string, and have lost the information we wanted to copy in the first place. The rest of the code will allocate a new string, then copy the uninitialized garbage in that string to itself. As a final result, you will end up with a new string of the correct length that contains garbage characters.
The self-assignment check prevents this from happening.
Preventing copying

Sometimes we simply don’t want our classes to be copied at all. The best way to do this is to add the prototypes for the copy constructor and overloaded operator= to the private section of your class.
class MyString
{
private:
char *m_pchString;
int m_nLength;
MyString(const MyString& cSource);
MyString& operator=(const MyString& cSource);
public:
// Rest of code here
};

In this case, C++ will not automatically create a default copy constructor and default assignment operator, because we’ve told the compiler we’re defining our own functions. Furthermore, any code located outside the class will not be able to access these functions because they’re private.
Summary
•The default copy constructor and default assignment operators do shallow copies, which is fine for classes that contain no dynamically allocated variables.
•Classes with dynamically allocated variables need to have a copy constructor and assignment operator that do a deep copy.
•The assignment operator is usually implemented using the same code as the copy constructor, but it checks for self-assignment, returns *this, and deallocates any previously allocated memory before deep copying.
•If you don’t want a class to be copy able, use a private copy constructor and assignment operator prototype in the class header.

Straight through processing

Straight through processing (STP) is the end-to-end automation of the trading processes both within and between buy and sell side institutions. In short, it is a vehicle to real-time stock/ trade processing in Financial Service industry, with a seamless integration of components and processes involved in the trading cycle starting from first request to buy/sell interest ending up to trading settlement and reporting.

It starts from the first capture of an order through to final settlement. It involves the seamless, electronic transfer of information to all parties involved in the trading cycle utilizing standardized information flows, technologies, and infrastructures.

STP provides wired links for investment managers and ability to process trade without manual intervention and exception, thereby eliminating chances for human errors.

Advantages
The present trade lifecycle is a maze of manual and electronic processes, taking several days, typically three to five days, from initiation to settlement. STP does it all electronically without the need for re-keying or manual intervention. Today, when an investor (individual or corporate) makes a trade, the order starts a complex procedure that extends over a few days. Phone calls and other paper documents fly back and forth between various players like broker/dealers, asset managers, etc. This complex set of operations is true even for a relatively simple domestic retail equity order. The complexity increases for a cross - border trade before it’s finalized.

It is a known fact that as trading volumes explodes, failure rates increase, which in turn, degrades the quality of customer service. To a customer, the ability to achieve a fully integrated STP capability enables greater access to liquidity with a service linking all the areas of the investment chain. STP, in its entirety, is expected to provide all affected financial services players with tremendous benefits, including greatly shortened processing cycles, reduced risk and lower operating costs. In addition, STP reduces errors through lost or wrongly input orders, speeding settlement, reducing risk, and cost of capital.

One of the key drivers of this interest was the T+1 initiative, originally conceived by SIA, the American Securities Industry forum, to address potentially increasing trading volumes in the US securities market. It was anticipate that, STP solutions would be needed to meet the global demand that has resulted from the explosive growth of online trading.

Historically, STP solutions were needed to help financial markets firms move to one-day trade settlement of equity transactions, as well as to meet the global demand resulting from the explosive growth of online trading. Now the concepts of STP are applied to reduce systemic and operational risk and to improve certainty of settlement and minimize operational costs.

When fully realized, STP provides asset managers, broker/dealers, custodians, banks and other financial services players with tremendous benefits, including greatly shortened processing cycles, reduced settlement risk and lower operating costs. Some industry analysts believe that STP is not an achievable goal in the sense that firms are unlikely to find the cost/benefit to reach 100% automation. Instead they promote the idea of improving levels of internal STP within a firm while encouraging groups of firms to work together to improve the quality of the automation of transaction information between themselves, either bilaterally or as a community of users (external STP). Other analysts, however, believe that STP will be achieved with the emergence of business process interoperability.


Impacted players:
Every player in the trade cycle will be affected in this process. Investors (Retail customers), Fund Managers, Broker/ Dealer, Custodian, Clearing Agents, Stock Exchange, Investment Managers, Credit rating agencies, Electronic Transaction Network, Information Providers (Electronic & others), Regulatory Bodies, Vendors are a few of the chain of players who would definitely be affected.
In summary
STP is a critical competitive weapon in the financial services industry. The key driver has always been business needs and therefore firms should not view STP narrowly as an IT solution. Its influence stretches far beyond the trading realm of operations and, when intelligently applied, STP will have a favourable impact on costs as well as the top line.

International Financial Reporting Standards

International Accounting Standards (IAS), now renamed International Financial Reporting Standards (IFRS), are gaining acceptance worldwide.
International Financial Reporting Standards (IFRS) are principles-based Standards, Interpretations and the Framework (1989) adopted by the International Accounting Standards Board (IASB).
Countries that have Adopted IFRS

Africa:
Botswana, Egypt, Ghana, Kenya, Malawi, Mauritius, Mozambique, Namibia, South Africa, Tanzania
Americas:
Bahamas, Barbados, Brazil (2010), Canada (2011), Chile (2009), Costa Rica, Dominican Republic, Ecuador, Guatemala, Guyana, Haiti, Honduras, Jamaica, Nicaragua, Panama, Peru, Trinidad and Tobago, Uruguay, Venezuela
Asia:
Armenia, Bahrain, Bangladesh, Georgia, Hong Kong, India (2011), Israel, Jordan, Kazakhstan, Kuwait, Kyrgyzstan, Lebanon, Nepal, Oman, Philippines, Qatar, Singapore, South Korea (2011), Sri Lanka (2011), Tajikistan, United Arab Emirates
Europe:
Austria, Belarus, Belgium, Bosnia and Herzegovina, Bulgaria, Croatia, Cyprus, Czech Republic, Denmark, Estonia, Finland, France, Germany, Greece, Hungary, Iceland, Ireland, Italy, Latvia, Liechtenstein, Lithuania, Luxembourg, Macedonia, Malta, Montenegro, Netherlands, Norway, Poland, Portugal, Romania, Russia, Serbia, Slovakia, Slovenia, Spain, Sweden, Turkey, Ukraine, United Kingdom
Oceania:
Australia, Fiji, New Zealand, Papua New Guinea
Components of IFRS financial statements:
Formats-To show specific items on the face of the primary IFRS financial statements.

Compliance with IFRS-Financial Statements complying with the IFRS should disclose the fact
For First time adoption of IFRS-The entity adopting IFRS for the first time should prepare financial statements(including comparatives) at the reporting date for the first IFRS financial statements.
The set of financial statements under IFRS

• Accounting Policies
• Statement of Comprehensive Income
• Balance Sheet
• Cash Flow Statement
• Statement of changes in Equity
• Notes on Accounts Need for IFRS
• Level of confidence: The key benefit will be common accounting system that is perceived as stable, transperant and fair to investors across the world.
• Risk Evaluation: IFRS will eliminate the barriers to cross-border listings and will be beneficial for investors who generally ascribe a risk premium if the underlying financial information is not prepared in accordance with international standards
• Merger and Takeover Activity: Cross-border mergers and acquisitions will get a boost by making it easier for the parties involved in as far as redrawing the financial statements is concerned.
• Investments: Foreign investors will be attracted to economies where IFRS-complaint financial statements are the norm.
Expected Benefits
(1) More efficient formulation of domestic accounting standards, improvement of their international image, and enhancement of the global rankings and international competitiveness of our local capital markets;
(2) Better comparability between the financial statements of local and foreign companies;
(3) No need for restatement of financial statements when local companies wish to issue overseas securities, resulting in reduction in the cost of raising capital overseas;
(4) For local companies with investments overseas, use of a single set of accounting standards will reduce the cost of account conversions and improve management efficiency.

Information Source:
http://en.wikipedia.org/wiki/International_Financial_Reporting_Standards
http://catuts.com/ifrs-introduction/
http://www.ftkmc.com/newsletter/Vol1-3-apr5-2010.pdf

Return by address

Returning by address involves returning the address of a variable to the caller. Just like pass by address, return by address can only return the address of a variable, not a literal or an expression. Like return by reference, return by address is fast. However, as with return by reference, return by address cannot return local variables:
int* DoubleValue(int nX)
{
int nValue = nX * 2;
return &nValue; // return nValue by address here
}

As you can see here, nValue goes out of scope just after its address is returned to the caller. The end result is that the caller ends up with the address of non-allocated memory, which will cause lots of problems if used. This is one of the most common programming mistakes that new programmers make. Many newer compilers will give a warning (not an error) if the programmer tries to return a local variable by address — however, there are quite a few ways to trick the compiler into letting you do something illegal without generating a warning, so the burden is on the programmer to ensure the address they are returning will be to a valid variable after the function returns.
Return by address is often used to return newly allocated memory to the caller:

int* AllocateArray(int nSize)
{
return new int[nSize];
}
int main()
{
int *pnArray = AllocateArray(25);
// do stuff with pnArray
delete[] pnArray;
return 0;
}

Return by reference

Return by reference
Just like with pass by reference, values returned by reference must be variables (you can not return a reference to a literal or an expression). When a variable is returned by reference, a reference to the variable is passed back to the caller. The caller can then use this reference to continue modifying the variable, which can be useful at times. Return by reference is also fast, which can be useful when returning structs and classes.
However, returning by reference has one additional downside that pass by reference doesn’t — you cannot return local variables to the function by reference.
Consider the following Example:

int& DoubleValue(int nX)
{
int nValue = nX * 2;
return nValue; // return a reference to nValue here
}

See the problem here? The function is trying to return a reference to a value that is going to go out of scope when the function returns. This would mean the caller receives a reference to garbage. Fortunately, your compiler will give you an error if you try to do this.
Return by reference is typically used to return arguments passed by reference to the function back to the caller. In the following example, we return (by reference) an element of an array that was passed to our function by reference:

struct FixedArray25
{
int anValue[25];
};
// Returns a reference to the nIndex element of rArray
int& Value(FixedArray25 &rArray, int nIndex)
{
return rArray.anValue[nIndex];
}
int main()
{
FixedArray25 sMyArray;
// Set the 10th element of sMyArray to the value 5
Value(sMyArray, 10) = 5;
cout << sMyArray.anValue[10] << endl; return 0; } Output : 5


When we call Value(sMyArray, 10), Value() returns a reference to the 10th element of the array inside sMyArray. main() then uses this reference to assign that element the value 5.

Although this is somewhat of a contrived example (because you could access sMyArray.anValue directly), once you learn about classes you will find a lot more uses for returning values by reference.

Return by value

Return by value is the simplest and safest return type to use. When a value is returned by value, a copy of that value is returned to the caller. As with pass by value, you can return by value literals (eg. 5), variables (eg. x), or expressions (eg. x+1), which makes return by value very flexible.

Advantage of return by value is that you can return variables (or expressions) that involve local variables declared within the function. Because the variables are evaluated before the function goes out of scope, and a copy of the value is returned to the caller, there are no problems when the variable goes out of scope at the end of the function.

int DoubleValue(int nX)
{
int nValue = nX * 2;
return nValue; // A copy of nValue will be returned here
}

Return by value is the most appropriate when returning variables that were declared inside the function, or for returning function arguments that were passed by value. However, like pass by value, return by value is slow for structs and large classes.

virtual functions

To implement virtual functions, C++ uses a special form of late binding known as the virtual table. The virtual table is a lookup table of functions used to resolve function calls in a dynamic/late binding manner. The virtual table sometimes goes by other names, such as “vtable”, “virtual function table”, “virtual method table”, or “dispatch table”.

Every class that uses virtual functions (or is derived from a class that uses virtual functions) is given its own virtual table. This table is simply a static array that the compiler sets up at compile time. A virtual table contains one entry for each virtual function that can be called by objects of the class. Each entry in this table is simply a function pointer that points to the most-derived function accessible by that class.
Second, the compiler also adds a hidden pointer to the base class, which we will call *__vptr. *__vptr is set (automatically) when a class instance is created so that it points to the virtual table for that class. Unlike the *this pointer, which is actually a function parameter used by the compiler to resolve self-references, *__vptr is a real pointer. Consequently, it makes each class object allocated bigger by the size of one pointer. It also means that *__vptr is inherited by derived classes, which is important.
Example
class Base
{
public:
virtual void function1() {};
virtual void function2() {};
};
class D1: public Base
{
public:
virtual void function1() {};
};
class D2: public Base
{
public:
virtual void function2() {};
};
There are 3 classes here, the compiler will set up 3 virtual tables: one for Base, one for D1, and one for D2.
The compiler also adds a hidden pointer to the most base class that uses virtual functions. Although the compiler does this automatically.

class Base
{
public:
FunctionPointer *__vptr;
virtual void function1() {};
virtual void function2() {};
};

class D1: public Base
{
public:
virtual void function1() {};
};
class D2: public Base
{
public:
virtual void function2() {};
};

When a class object is created, *__vptr is set to point to the virtual table for that class. For example, when an object of type Base is created, *__vptr is set to point to the virtual table for Base. When objects of type D1 or D2 are constructed, *__vptr is set to point to the virtual table for D1 or D2 respectively.

How these virtual tables are filled out. Because there are only two virtual functions here, each virtual table will have two entries (one for function1(), and one for function2()). Remember that when these virtual tables are filled out, each entry is filled out with the most-derived function an object of that class type can call.
Base’s virtual table is simple. An object of type Base can only access the members of Base. Base has no access to D1 or D2 functions. Consequently, the entry for function1 points to Base::function1(), and the entry for function2 points to Base::function2().
D1′s virtual table is slightly more complex. An object of type D1 can access members of both D1 and Base. However, D1 has overridden function1(), making D1::function1() more derived than Base::function1(). Consequently, the entry for function1 points to D1::function1(). D1 hasn’t overridden function2(), so the entry for function2 will point to Base::function2().
D2′s virtual table is similar to D1, except the entry for function1 points to Base::function1(), and the entry for function2 points to D2::function2().


The *__vptr in each class points to the virtual table for that class. The entries in the virtual table point to the most-derived version of the function objects of that class are allowed to call.
So consider what happens when we create an object of type D1:
int main()
{
D1 cClass;
}
Because cClass is a D1 object, cClass has it’s *__vptr set to the D1 virtual table.
Now, let’s set a base pointer to D1:

int main()
{
D1 cClass;
Base *pClass = &cClass;
}
Note that because pClass is a base pointer, it only points to the Base portion of cClass. However, also note that *__vptr is in the Base portion of the class, so pClass has access to this pointer. Finally, note that pClass->__vptr points to the D1 virtual table! Consequently, even though pClass is of type Base, it still has access to D1′s virtual table.

So what happens when we try to call pClass->function1()?
int main()
{
D1 cClass;
Base *pClass = &cClass;
pClass->function1();
}
First, the program recognizes that function1() is a virtual function. Second, uses pClass->__vptr to get to D1′s virtual table. Third, it looks up which version of function1() to call in D1′s virtual table. This has been set to D1::function1(). Therefore, pClass->function1() resolves to D1::function1()!
Now, you might be saying, “But what if Base really pointed to a Base object instead of a D1 object. Would it still call D1::function1()?”. The answer is no.

int main()
{
Base cClass;
Base *pClass = &cClass;
pClass->function1();
}

In this case, when cClass is created, __vptr points to Base’s virtual table, not D1′s virtual table. Consequently, pClass->__vptr will also be pointing to Base’s virtual table. Base’s virtual table entry for function1() points to Base::function1(). Thus, pClass->function1() resolves to Base::function1(), which is the most-derived version of function1() that a Base object should be able to call.

By using these tables, the compiler and program are able to ensure function calls resolve to the appropriate virtual function, even if you’re only using a pointer or reference to a base class!

Calling a virtual function is slower than calling a non-virtual function for a couple of reasons: First, we have to use the *__vptr to get to the appropriate virtual table. Second, we have to index the virtual table to find the correct function to call. Only then can we call the function. As a result, we have to do 3 operations to find the function to call, as opposed to 2 operations for a normal indirect function call, or one operation for a direct function call. However, with modern computers, this added time is usually fairly insignificant.

Late Binding

Late Binding
In C++, one way to get late binding is to use function pointers. To review function pointers briefly, a function pointer is a type of pointer that points to a function instead of a variable. The function that a function pointer points to can be called by using the function call operator (()) on the pointer.

For example, the following code calls the Add() function
int Add(int nX, int nY)
{
return nX + nY;
}
int main()
{
// Create a function pointer and make it point to the Add function
int (*pFcn)(int, int) = Add;
cout << pFcn(5, 3) << endl; // add 5 + 3 return 0; } Calling a function via a function pointer is also known as an indirect function call.

int Add(int nX, int nY)
{
return nX + nY;
}
int Subtract(int nX, int nY)
{
return nX - nY;
}

int Multiply(int nX, int nY)
{
return nX * nY;
}
int main()
{
int nX;
cout << "Enter a number: "; cin >> nX;
int nY;
cout << "Enter another number: "; cin >> nY;
int nOperation;


do
{
cout << "Enter an operation (0=add, 1=subtract, 2=multiply): "; cin >> nOperation;
} while (nOperation < 0 || nOperation > 2);
int (*pFcn)(int, int);
// Set pFcn to point to the function the user chose
switch (nOperation)
{
case 0: pFcn = Add; break;
case 1: pFcn = Subtract; break;
case 2: pFcn = Multiply; break;
}

cout << "The answer is: " << pFcn(nX, nY) << endl;
return 0;
}

Instead of calling the Add(), Subtract(), or Multiply() function directly, we’ve instead set pFcn to point at the function we wish to call. Then we call the function through the pointer. The compiler is unable to use early binding to resolve the function call pFcn(nX, nY) because it can not tell which function pFcn will be pointing to at compile time!
Late binding is slightly less efficient since it involves an extra level of indirection. With early binding, the compiler can tell the CPU to jump directly to the function’s address. With late binding, the program has to read the address held in the pointer and then jump to that address. This involves one extra step, making it slightly slower. However, the advantage of late binding is that it is more flexible than early binding, because decisions about what function to call do not need to be made until run time.