As computer science has evolved, object oriented programming has become one of many familiar models designers and programmers utilize to implement functionality within computer systems. The object model generally is defined by a class structure that includes class members providing both methods and associated data elements belonging to the class. The class members thus provide/define desired functionality within a computer program, wherein an object is declared as an instance of a particular class. As is commonplace, objects often must exchange data and/or invoke other objects operating on the same platform and/or communicate with objects belonging to remote platforms. In order to communicate between objects, interface systems and standards have been developed to define how objects may communicate and/or interact with one another.
A familiar system for communicating and interfacing between objects is known as the Component Object Model (COM), wherein another similar system is referred to as the Common Object Request Brokers Architecture (CORBA). Still yet other communication interfaces may be defined in languages such as JAVA within an operating framework of a Java Virtual Machine, for example. As these and other systems have been developed however, two common object architectures or models generally have emerged and may generally be defined in terms of managed and unmanaged object systems, for example.
Managed objects may be allocated from a heap within a managed software or execution environment and are generally not responsible for managing associated object lifetimes. Managed objects may be described in terms of a data type (e.g., metadata) and automatically collected (e.g., reclaimed) by a managed environment “garbage collector” that removes the object from memory when the object is no longer being accessed. In contrast, unmanaged objects may be allocated from a standard operating system heap, wherein the object itself is responsible for freeing memory it employs when references to the object no longer exist. This may be accomplished through well-known techniques such as reference counting, for example.
As described above, managed objects may be allocated from a managed heap and automatically garbage collected. In order to achieve this, references to managed objects are traced. In one example, reference counting can be used wherein a last reference to an object is removed, the garbage collector reclaims the memory occupied by the object mitigating the need to reference count managed objects. Yet in a Common Language Runtime (CLR), memory is not reclaimed until a garbage collector is run (e.g., which normally happens with a triggering of low resource conditions). Thus in general, a managed environment essentially handles garbage collection internally. Tracing is possible within managed code because the managed environment keeps track of outstanding references that exist on an object. As each new object reference is declared within managed code, the managed environment adds the reference to a list (e.g., building the list on the fly). At any given time, the managed environment, rather than the object itself, is thus aware of live references that exist on a given object. As references fall out of scope or change value, the list (built on the fly) is determined by knowing a combination of stack walking and how to inspect areas of memory owned by the garbage collector, and as long as a reference remains within managed code, the managed environment is able to trace it. Unfortunately, object references originating from unmanaged code present difficulties when interacting with a managed environment.
One difficulty associated with unmanaged references operating in a managed environment relates to that there is substantially no straightforward way for managed environments to trace references from unmanaged code to managed objects. Even if the managed environment were aware of these references, generally, no information is maintained indicating whether a reference is active or inactive. Thus, since unmanaged clients, for example, are written in unmanaged code, presently, there is not a process for tracing references that unmanaged objects may hold on managed objects executing within a managed environment. Similarly, originating calls from managed environments to unmanaged environments also presents problems relating to managing object lifetimes. For example, some unmanaged objects expect to be reference counted, but in a managed environment reference counting is not required for managed objects. It would thus be very confusing if developers that design managed code had to handle references to managed and unmanaged objects differently.
Along with object lifetime management problems described above, managed and unmanaged object systems generally differ in many other significant ways. These differences may include how the object systems provide object interfaces within the respective object systems, how data is structured and/or defined, and how errors and exceptions are handled, for example. Due to these and other differences between managed and unmanaged object systems, it is presently difficult, time consuming, and expensive in terms of development costs to have objects from an unmanaged system interface and interact with objects from a managed system and visa versa. Moreover, it is generally difficult for managed objects designed according to one object system framework to communicate with objects from an architecturally different managed system framework. This also applies to unmanaged object communications between diverse unmanaged system frameworks. Thus, programmers and developers have diverged based at least in part upon programming preferences relating to a managed or an unmanaged system (e.g., type instantiation in memory areas, garbage collection, pointing and reference to types, . . . ).
A classic paradigm relating to managed and unmanaged systems originates from a programming standpoint. Dependent upon a programmer, program language decisions differ based at least in part upon strengths and weaknesses of the language. Therefore, a programmer must take both benefits and detriments when choosing to program between a managed system and unmanaged system. Common Language Runtime (CLR) and C++ Standard are examples of a managed and unmanaged systems respectively, wherein each system delivers tailored benefits and detriments to the individual programmer. Thus, programmers have diverged based upon programming preferences (e.g., type instantiation in memory areas, garbage collection, pointing and reference to types . . . ) in relation to managed systems or unmanaged systems.
In particular, an unmanaged system allows a programmer to have leniency not available in a managed system such as freedom with type instantiation in memory areas; yet does not provide the benefit of garbage collection. For example, a C++ program provides distinction between definition of a type and how or where the type can be instantiated (e.g., producing a particular object from its class template, which can include allocation of a structure with the types specified by the template, and initialization of instance variables with either default values or those provided by a class constructor function). Thus, a C++ environment provides users with certain idioms that control where or where not a type is instantiated, but a definition of type itself does not control instantiation.
On the other hand, various compilers and other tools expose a managed system's functionality that enable designers to write code that benefits from a managed execution environment. Thus, code that is developed with a language compiler that targets a managed system such as, for example, a Common Language Runtime (CLR) is referred to as managed code. This type environment employs features such as, for example, garbage collection based on type, and caps (e.g., handles) to reference whole objects.
Managed and unmanaged systems such as, for example, C++ Standard and Common Language Runtime (CLR), have developed a divergence in programming preference based upon their individual strengths and weakness. Supporting the C++ Standard within the Common Language Runtime (CLR) unearthed various problems with compatibility and the existing standard. Extending the language became problematic and cumbersome. For example, programmers adopted the use of a double underscore in order to preface keywords for managed extensions to define, such as, garbage-collection classes and properties. Such characteristics, although conformed to C++ Standard, deterred programmers from managed systems based at least in part upon readability of code, comprehension, and a large learning curve.
In view of the above, there is a need to build upon the existing C++ Standard in order to improve upon performance utilizing Common Language Runtime (CLR). More particularly, there is a need to conform to C++ Standard within the Common Language Runtime (CLR) that is readable, yet does not interfere with existing code standards.