Circular dependency
Encyclopedia
In software engineering
Software engineering
Software Engineering is the application of a systematic, disciplined, quantifiable approach to the development, operation, and maintenance of software, and the study of these approaches; that is, the application of engineering to software...

, a circular dependency is a relation between two or more modules which either directly or indirectly depend on each other to function properly.

Overview

Circular dependencies are natural in many domain model
Domain model
A domain model in problem solving and software engineering can be thought of as a conceptual model of a domain of interest which describes the various entities, their attributes, roles and relationships, plus the constraints that govern the integrity of the model elements comprising that problem...

s where certain objects of the same domain depend on each other. However, in software design
Software design
Software design is a process of problem solving and planning for a software solution. After the purpose and specifications of software are determined, software developers will design or employ designers to develop a plan for a solution...

 circular dependencies between larger software modules are considered an anti-pattern
Anti-pattern
In software engineering, an anti-pattern is a pattern that may be commonly used but is ineffective and/or counterproductive in practice.The term was coined in 1995 by Andrew Koenig,...

 because of their negative effects.

Problems of circular dependencies

Circular dependencies can cause many unwanted effects in software programs. Most problematic from a software design point of view is the tight coupling of the mutually dependent modules which reduces or makes impossible the separate re-use of a single module.

Circular dependencies can cause a domino effect
Domino effect
The domino effect is a chain reaction that occurs when a small change causes a similar change nearby, which then will cause another similar change, and so on in linear sequence. The term is best known as a mechanical effect, and is used as an analogy to a falling row of dominoes...

 when a small local change in one module spreads into other modules and has unwanted global effects (program errors, compile errors). Circular dependencies can also result in infinite recursions or other unexpected failures.

Circular dependencies may also cause memory leak
Memory leak
A memory leak, in computer science , occurs when a computer program consumes memory but is unable to release it back to the operating system. In object-oriented programming, a memory leak happens when an object is stored in memory but cannot be accessed by the running code...

s by preventing certain very primitive automatic garbage collector
Garbage collector
Garbage collector may refer to:* Waste collector, a person employed to collect waste* A waste collection vehicle* A waste picker, or a dumpster diver* Garbage collection , the detection and pruning of unused or inaccessible data structures...

s (those that use reference counting
Reference counting
In computer science, reference counting is a technique of storing the number of references, pointers, or handles to a resource such as an object, block of memory, disk space or other resource...

) from deallocating unused objects.

Causes and solutions

In very large software designs, software engineers may lose the context and inadvertently introduce circular dependencies. There are tools to analyze software and find unwanted circular dependencies.

Circular dependencies are often introduced by inexperienced programmers who need to implement some kind of callback functionality. Experienced programmers avoid such unnecessary circular dependencies by applying design patterns
Design Patterns
Design Patterns: Elements of Reusable Object-Oriented Software is a software engineering book describing recurring solutions to common problems in software design. The book's authors are Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides with a foreword by Grady Booch. The authors are...

 like the observer pattern
Observer pattern
The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods...

.

Example of circular dependencies in C++

Implementation of circular dependencies in C/C++ can be a bit tricky, because any class or structure definition must be placed above its usage in the same file. A circular dependency between classes A and B will thus both require the definition of A to be placed above B, and the definition of B to be placed above A, which of course is impossible. A forward declaration trick is therefore needed to accomplish this.

The following example illustrates how this is done.
  • File a.h:

  1. ifndef A_H
  2. define A_H


class B; //forward declaration

class A {
public:
B* b;
};
  1. endif //A_H


  • File b.h:

  1. ifndef B_H
  2. define B_H


class A; //forward declaration

class B {
public:
A* a;
};
  1. endif //B_H


  • File main.cpp:

  1. include "a.h"
  2. include "b.h"


int main {
A a;
B b;
a.b = &b;
b.a = &a;
}


Note that although a name (e.g. A) can be declared multiple times, such as in forward declarations, it can only be defined once (the One Definition Rule
One Definition Rule
The One Definition Rule is an important concept in the C++ programming language. It's defined in the ISO C++ Standard 2003, at section 3.2.- Summary :In short the ODR states that:...

).

Self-reference example

Following is another example of forward declaration, which might be useful if the application needs a self-sustaining array of objects which is able to add and remove objects from itself during run-time:
  • File a.h:


class A {
public:
static A *first, *last;
A *previous, *next;

A;
~A;
};


The static variables first and last have to be defined, because their declaration does not reserve memory space for them. Note: static variables do not change from object to object and stay the same for this given class.

They should also be initialized to 0, or NULL, so we know what they are to start with.
  • File a.cpp:

  1. include "a.h"


A *A::first=0, *A::last=0; // don't put the word static here, that will cause an error

A::A {
if(first

0) first=this; //first A created
previous=last;
if(previous != 0) previous->next=this;
last=this;
next=0;
}

A::~A {
if(previous != 0) previous->next=next;
if(next != 0) next->previous=previous;
}

External links
The source of this article is wikipedia, the free encyclopedia.  The text of this article is licensed under the GFDL.
 
x
OK