Is-a

Last updated

In knowledge representation and ontology components, including for object-oriented programming and design, is-a (also written as is_a or is a) is a subsumptive [lower-alpha 1] relationship between abstractions (e.g., types, classes), wherein one class A is a subclass of another class B (and so B is a superclass of A). In other words, type A is a subtype of type B when A's specification implies B's specification. That is, any object (or class) that satisfies A's specification also satisfies B's specification, because B's specification is weaker. [1]

Contents

For example, a cat 'is a' animal, but not vice versa. All cats are animals, but not all animals are cats. Behaviour that is relevant to all animals is defined on an animal class, whereas behaviour that is relevant only for cats is defined in a cat class. By defining the cat class as 'extending' the animal class, all cats 'inherit' the behaviour defined for animals, without the need to explicitly code that behaviour for cats.

The is-a relationship is to be contrasted with the has-a (has_a or has a) relationship between types (classes); confusing the relations has-a and is-a is a common error when designing a model (e.g., a computer program) of the real-world relationship between an object and its subordinate. The is-a relationship may also be contrasted with the instance-of relationship between objects (instances) and types (classes): see Type–token distinction.

To summarize the relations, there are:

Examples of subtyping

Subtyping enables a given type to be substituted for another type or abstraction. Subtyping is said to establish an is-a relationship between the subtype and some existing abstraction, either implicitly or explicitly, depending on language support. The relationship can be expressed explicitly via inheritance in languages that support inheritance as a subtyping mechanism.

C++

The following C++ code establishes an explicit inheritance relationship between classes B and A, where B is both a subclass and a subtype of A, and can be used as an A wherever a B is specified (via a reference, a pointer or the object itself).

classA{public:voidDoSomethingALike()const{}};classB:publicA{public:voidDoSomethingBLike()const{}};voidUseAnA(Aconst&some_A){some_A.DoSomethingALike();}voidSomeFunc(){Bb;UseAnA(b);// b can be substituted for an A.}

[3]

Python

The following python code establishes an explicit inheritance relationship between classes B and A, where B is both a subclass and a subtype of A, and can be used as an A wherever a B is required.

classA:defdo_something_a_like(self):passclassB(A):defdo_something_b_like(self):passdefuse_an_a(some_a):some_a.do_something_a_like()defsome_func():b=B()use_an_a(b)# b can be substituted for an A.

The following example, type(a) is a "regular" type, and type(type(a)) is a metatype. While as distributed all types have the same metatype (PyType_Type, which is also its own metatype), this is not a requirement. The type of classic classes, known as types.ClassType, can also be considered a distinct metatype. [4]

>>> a=0>>> type(a)<type 'int'>>>> type(type(a))<type 'type'>>>> type(type(type(a)))<type 'type'>>>> type(type(type(type(a))))<type 'type'>

Java

In Java, is-a relation between the type parameters of one class or interface and the type parameters of another are determined by the extends and implements clauses.

Using the Collections classes, ArrayList<E> implements List<E>, and List<E> extends Collection<E>. So ArrayList<String> is a subtype of List<String>, which is a subtype of Collection<String>. The subtyping relationship is preserved between the types automatically. When defining an interface, PayloadList, that associates an optional value of generic type P with each element, its declaration might look like:

interfacePayloadList<E,P>extendsList<E>{voidsetPayload(intindex,Pval);...}

The following parameterizations of PayloadList are subtypes of List<String>:

PayloadList<String,String>PayloadList<String,Integer>PayloadList<String,Exception>

Liskov substitution principle

Liskov substitution principle explains a property, "If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T,". [5] Following example shows a violation of LSP.

Here is perhaps an example of violation of LSP:

classRectangle{public:voidSetWidth(doublew){itsWidth=w;}voidSetHeight(doubleh){itsHeight=h;}doubleGetHeight()const{returnitsHeight;}doubleGetWidth()const{returnitsWidth;}doubleGetArea()const{returnGetHeight()*GetWidth();}private:doubleitsWidth;doubleitsHeight;};

From a programing point of view, the Square class may be implemented by inheriting from the Rectangle class.

publicclassSquare:Rectangle{public:virtualvoidSetWidth(doublew);virtualvoidSetHeight(doubleh);};voidSquare::SetWidth(doublew){Rectangle::SetWidth(w);Rectangle::SetHeight(w);}voidSquare::SetHeight(doubleh){Rectangle::SetHeight(h);Rectangle::SetWidth(h);}

However, this violates LSP even though the is-a relationship holds between Rectangle and Square

Consider the following example, where function g does not work if a Square is passed in, and so the open-closed principle might be considered to have been violated.

voidg(Rectangle&r){r.SetWidth(5);r.SetHeight(4);assert(r.GetArea())==20);// assertion will fail}

Conversely, if one considers that the type of a shape should only be a constraint on the relationship of its dimensions, then it is the assumption in g() that SetHeight will change height, and area, but not width that is invalid, not just for true squares, but even potentially for other rectangles that might be coded so as to preserve area or aspect ratio when height changes.

[6]

See also

Notes

  1. "Subtypes and Subclasses" (PDF). MIT OCW. Retrieved 2 October 2012.
  2. See also Containment (computer programming).
  3. Mitchell, John (2002). "10 "Concepts in object-oriented languages"". Concepts in programming language. Cambridge, UK: Cambridge University Press. p. 287. ISBN   0-521-78098-5.
  4. Guido van Rossum. "Subtyping Built-in Types" . Retrieved 2 October 2012.
  5. Liskov, Barbara (May 1988). Data Abstraction and Hierarchy (PDF). SIGPLAN Notices. Archived from the original on Jun 21, 2020.{{cite book}}: CS1 maint: unfit URL (link)
  6. "The Liskov Substitution Principle" (PDF). Robert C. Martin, 1996. Archived from the original (PDF) on 5 September 2015. Retrieved 2 October 2012.

Related Research Articles

In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes a group of objects that are treated the same way as a single instance of the same type of object. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly.

In programming language theory, subtyping is a form of type polymorphism. A subtype is a datatype that is related to another datatype by some notion of substitutability, meaning that program elements, written to operate on elements of the supertype, can also operate on elements of the subtype.

A method in object-oriented programming (OOP) is a procedure associated with an object, and generally also a message. An object consists of state data and behavior; these compose an interface, which specifies how the object may be used. A method is a behavior of an object parametrized by a user.

In programming language theory and type theory, polymorphism is the use of a single symbol to represent multiple different types.

In database design, object-oriented programming and design, has-a is a composition relationship where one object "belongs to" another object, and behaves according to the rules of ownership. In simple words, has-a relationship in an object is called a member field of an object. Multiple has-a relationships will combine to form a possessive hierarchy.

<span class="mw-page-title-main">Liskov substitution principle</span> Object-oriented programming principle

The Liskov substitution principle (LSP) is a particular definition of a subtyping relation, called strong behavioral subtyping, that was initially introduced by Barbara Liskov in a 1987 conference keynote address titled Data abstraction and hierarchy. It is based on the concept of "substitutability" – a principle in object-oriented programming stating that an object may be replaced by a sub-object without breaking the program. It is a semantic rather than merely syntactic relation, because it intends to guarantee semantic interoperability of types in a hierarchy, object types in particular. Barbara Liskov and Jeannette Wing described the principle succinctly in a 1994 paper as follows:

Subtype Requirement: Let be a property provable about objects of type T. Then should be true for objects of type S where S is a subtype of T.

The fragile base class problem is a fundamental architectural problem of object-oriented programming systems where base classes (superclasses) are considered "fragile" because seemingly safe modifications to a base class, when inherited by the derived classes, may cause the derived classes to malfunction. The programmer cannot determine whether a base class change is safe simply by examining in isolation the methods of the base class.

In object-oriented programming such as is often used in C++ and Object Pascal, a virtual function or virtual method is an inheritable and overridable function or method that is dispatched dynamically. Virtual functions are an important part of (runtime) polymorphism in object-oriented programming (OOP). They allow for the execution of target functions that were not precisely identified at compile time.

In computer science, a tagged union, also called a variant, variant record, choice type, discriminated union, disjoint union, sum type, or coproduct, is a data structure used to hold a value that could take on several different, but fixed, types. Only one of the types can be in use at any one time, and a tag field explicitly indicates which type is in use. It can be thought of as a type that has several "cases", each of which should be handled correctly when that type is manipulated. This is critical in defining recursive datatypes, in which some component of a value may have the same type as that value, for example in defining a type for representing trees, where it is necessary to distinguish multi-node subtrees and leaves. Like ordinary unions, tagged unions can save storage by overlapping storage areas for each type, since only one is in use at a time.

Class-based programming, or more commonly class-orientation, is a style of object-oriented programming (OOP) in which inheritance occurs via defining classes of objects, instead of inheritance occurring via the objects alone.

<span class="mw-page-title-main">Method overriding</span> Language feature in object-oriented programming

Method overriding, in object-oriented programming, is a language feature that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its superclasses or parent classes. In addition to providing data-driven algorithm-determined parameters across virtual network interfaces, it also allows for a specific type of polymorphism (subtyping). The implementation in the subclass overrides (replaces) the implementation in the superclass by providing a method that has same name, same parameters or signature, and same return type as the method in the parent class. The version of a method that is executed will be determined by the object that is used to invoke it. If an object of a parent class is used to invoke the method, then the version in the parent class will be executed, but if an object of the subclass is used to invoke the method, then the version in the child class will be executed. This helps in preventing problems associated with differential relay analytics which would otherwise rely on a framework in which method overriding might be obviated. Some languages allow a programmer to prevent a method from being overridden.

Many programming language type systems support subtyping. For instance, if the type Cat is a subtype of Animal, then an expression of type Cat should be substitutable wherever an expression of type Animal is used.

In object-oriented programming, inheritance is the mechanism of basing an object or class upon another object or class, retaining similar implementation. Also defined as deriving new classes from existing ones such as super class or base class and then forming them into a hierarchy of classes. In most class-based object-oriented languages like C++, an object created through inheritance, a "child object", acquires all the properties and behaviors of the "parent object", with the exception of: constructors, destructors, overloaded operators and friend functions of the base class. Inheritance allows programmers to create classes that are built upon existing classes, to specify a new implementation while maintaining the same behaviors, to reuse code and to independently extend original software via public classes and interfaces. The relationships of objects or classes through inheritance give rise to a directed acyclic graph.

<span class="mw-page-title-main">Covariant return type</span>

In object-oriented programming, a covariant return type of a method is one that can be replaced by a "narrower" (derived) type when the method is overridden in a subclass. A notable language in which this is a fairly common paradigm is C++.

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral (null) behavior. The null object design pattern, which describes the uses of such objects and their behavior, was first published as "Void Value" and later in the Pattern Languages of Program Design book series as "Null Object".

The circle–ellipse problem in software development illustrates several pitfalls which can arise when using subtype polymorphism in object modelling. The issues are most commonly encountered when using object-oriented programming (OOP). By definition, this problem is a violation of the Liskov substitution principle, one of the SOLID principles.

The enhanced entity–relationship (EER) model in computer science is a high-level or conceptual data model incorporating extensions to the original entity–relationship (ER) model, used in the design of databases.

In object-oriented programming, behavioral subtyping is the principle that subclasses should satisfy the expectations of clients accessing subclass objects through references of superclass type, not just as regards syntactic safety but also as regards behavioral correctness. Specifically, properties that clients can prove using the specification of an object's presumed type should hold even though the object is actually a member of a subtype of that type.

In knowledge representation, a class is a collection of individuals or individuals objects. A class can be defined either by extension, or by intension, using what is called in some ontology languages like OWL. According to the type–token distinction, the ontology is divided into individuals, who are real worlds objects, or events, and types, or classes, who are sets of real world objects. Class expressions or definitions gives the properties that the individuals must fulfill to be members of the class. Individuals that fulfill the property are called Instances.

In object-oriented programming, forwarding means that using a member of an object results in actually using the corresponding member of a different object: the use is forwarded to another object. Forwarding is used in a number of design patterns, where some members are forwarded to another object, while others are handled by the directly used object. The forwarding object is frequently called a wrapper object, and explicit forwarding members are called wrapper functions.

References