1
$\begingroup$

I do not have any argument opposing why we need only a single universal class. However why not we have two universal classes, say an Object and an AntiObject Class. In nature and in science we find the concept of duality - like Energy & Dark Energy; Male & Female; Plus & Minus; Multiply & Divide; Electrons & Protons; Integration & Derivation; and in set theory. There are so many examples of dualism that it is a philosophy in itself. In programming itself we see Anti-Patterns which helps us to perform work in contrast to how we use Design patterns. I am not sure, but the usefulness of this duality concept may lie in creating garbage collectors that create AntiObjects that combine with free or loose Objects to destruct themselves, thereby releasing memory. Or may be AntiObjects work along with Objects to create a self-modifying programming language - that allows us to create a safe self modifying code, do evolutionary computing using genetic programming, do hiding of code to prevent reverse engineering.

We call it object-oriented programming. Is that a limiting factor or is there something fundamental I am missing in understanding the formation of programming languages?

$\endgroup$
7
  • 3
    $\begingroup$ Languages like C++ do not have any root class, so you can build own Object and AntiObject classes if you like. $\endgroup$
    – swegi
    Aug 7, 2012 at 7:57
  • $\begingroup$ @swegi If C++ is superior in this regard then what were the reasons we are moving towards Typed languages - C# and Java. In my understanding, Typed languages provide simplicity and things like Garbage collection, etc. Also people have quoted problems with Multiple inheritance before. In this dual system I want classes to either derive from Object or AntiObject but the system does not allow multiple inheritance. $\endgroup$
    – kaushal
    Aug 7, 2012 at 8:55
  • 3
    $\begingroup$ It is not a question of being superior or otherwise. C# and Java are more modern languages which were designed based on the lessons learned from C++ and other research programming languages. Garbage collection is orthogonal to typing. Both Java and C# avoid the multiple inheritance problem by allowing interfaces separate from classes. There is no technical reason for disallowing two roots to the object hierarchy. $\endgroup$ Aug 7, 2012 at 9:27
  • $\begingroup$ In the application to garbage collecting or evolutionary programming, what benefit would introducing an "AntiObject" class bring to these tasks? A process which combined objects and their opposites to collect garbage could just as easily collect garbage without the auxiliary antiobject, for instance. So the short answer is simply that an AntiObject class hasn't actually suggested itself as a useful tool. As for dualism: if you're keen on philosophy as a motivator for PL design, you may as well adopt Hegel's position that the two opposites may be subsumed in a more general Synthesis. $\endgroup$ Aug 7, 2012 at 13:43
  • 1
    $\begingroup$ What is this AntiObject, and how does it differ from an Object? Is this just duality for the sake of duality? $\endgroup$ Aug 8, 2012 at 0:35

3 Answers 3

10
$\begingroup$

This is only an answer to answer the question in the title.

Languages such as Java have every class deriving from Object for two reasons.

Firstly, to increase the amount of polymorphism available. This was particularly required before generics were added to the language. Without Object, collection classes would be impossible to write in a useful fashion.

Secondly, there are many methods that classes are expected to have or are useful, and these are collected in Object. By ensuring that all classes inherit from Object, all classes will implement the same minimal interface.

As mentioned in a comment, C++ does not have a class like Object. C++ is in many ways untyped, so the issues I mention above are not applicable. Also, C++ templates provide a lot of polymorphism and are used to implement collections.

$\endgroup$
1
  • 1
    $\begingroup$ Great post. I just thought I would mention how Google's "Go" language handles collections. In Go, there is no "Object" that everything inherits from, but there is the "empty interface" that everything implements. In this way they are able to implement collections "generically." $\endgroup$ Apr 20, 2014 at 21:21
3
$\begingroup$

I think the accepted answer covers pretty much the original question, but I would like to supplement it (if I may) slightly by throwing in (quite informally) a few ideas regarding the secondary questions.

From an inheritance point of view, nothing prevents the class hierarchy to have several roots. As it has been pointed out by other peoples, C++, as well as many OO languages don't constraint expressiveness to a single root ancestor class.

However, from a type theoretic point of view (recall that inheritance and subtyping are not the same thing, so I am probably stepping out of the frame of the main question here), a single "top" supertype can make a lot of sense (depending on the type theory of course). For instance, in OCaml, there is a common supertype to all objects (whether class instances, or immediate objects), written < > to denote that the object type is empty, i.e. doesn't accept any message. This seems indeed the most general object type we can define, since we cannot remove anything from it to make it more general. Hence, in this conception of object types, there is necessarily a supertype to all object.

Regarding the dual of the root object, scala sports a class called Nothing, which curiously is also empty, and is the subtype of every other classes. It cannot be instantiated, but holds enough useful semantic to implement the empty list, which is called Nil, and is equal to List[Nothing] (as pointed out in comments, it is possible that programmer never directly use that value in most case, making it seemingly not as useful as it is). Nothing could be considered a dual of the root type - called Any in scala, however these types not only cover classes, but also primitives types, so that everything can be upcasted to Any, for instance.

$\endgroup$
5
  • 1
    $\begingroup$ 1) In Scala, List[Nothing] is the minimal inferred type for the empty list, but hardly ever useful. Usually, you want to provide type information to get a (usable) type such as List[String]. 2) You say, "a single 'top' supertype makes a lot of sense", but you don't give a reason. $\endgroup$
    – Raphael
    Feb 2, 2013 at 13:54
  • $\begingroup$ @Raphael you make 2 very valid points, thank you! I hope my updated answer addresses them somehow. $\endgroup$
    – didierc
    Feb 2, 2013 at 15:31
  • $\begingroup$ In Java and .NET, the universe of class-reference types is essentially the same as the universe of class-instance types, but for the fact that references can exist to abstract classes which cannot actually be instantiated. From a type-theoretic point of view, I wonder how hard it would be to expand the variety of references, so that an int[] which encapsulates ownership of an unsharable array could be distinguished from one which identifies an array which is owned by someone else, or one which is shared among entities that agree never to change it. $\endgroup$
    – supercat
    Feb 22, 2014 at 19:15
  • $\begingroup$ Usually, these type "characteristics" are encoded using polymorphism, either by (1) defining a type for ownership, with as its parameters the type being owned; or by (2) adding a parameter to the type which may be owned, with that parameter being a type representing the owner (a thread, a context, or some other valid runtime entity). For dependently typed language, this owner might even be a value rather than a type. $\endgroup$
    – didierc
    Apr 19, 2014 at 14:42
  • $\begingroup$ What this clearly underline is that we seek to express relationships between types, and polymorphism is a way of encoding that relationship, but we could clearly envision a 3rd option generalizing the previous 2, by defining a type polymorphic on the owner and the owned, or any other kind of relationship we'd like to encode (see for instance this ocaml library which encodes higher kinded types using that idea). $\endgroup$
    – didierc
    Apr 19, 2014 at 15:08
1
$\begingroup$

The ability to define collections that can hold arbitrary kinds of things, without needing to define different methods for different kinds of things, is very useful. Templates in C++ make it possible for a single source file to define collection types that can hold many different kinds of things, but the compiler will have to duplicate the code for every different kind of thing in the collection. If instead one defines almost all of the types in the system to derive from a single type, then a collection which can hold references to things of that type will be able to hold references to things of almost any type.

This approach does have a limitation, however, which is that it blurs the distinctions between values and entities. A reference which encapsulates a value by identifying some particular object can be replaced with a reference to a copy of that object without altering its semantics. A reference which is used to identify an entity, however, cannot be replaced in such fashion. Either the entity itself will be something that can't be copied (e.g. if it represents a connection to something in the real world) or the entity may encapsulate the set of references that exist to it. A key thing to note is that objects behave as values when either they cannot change or only one reference exists to them, and they behave like entities when multiple references exist.

Blurring the distinction between values and entities makes it difficult for collection types to know whether they should regard their contents as values or entities; this in turn limits the ability of collections to implement things like equals or clone in useful fashion. Languages which make a stronger type/entity distinction can have collections do more things automatically than languages which do not, but the distinctions add some complexity, which language designers may or may not feel is justified by the benefits.

$\endgroup$
15
  • $\begingroup$ Be careful with the terminology you are employing, when it's not standard : value, type and kind have specific meanings in type theory. Also, I am not quite sure to understand what you mean by "entity". Could you define that word? $\endgroup$
    – didierc
    Apr 19, 2014 at 15:14
  • $\begingroup$ Many terms have particular meanings in various languages, and so I tried to use terms which would avoid such usages. As for value versus entity, the last sentence of my second paragraph was missing an "or"; does adding it help things? The key point is that references that are used to encapsulate value are equivalent to other references that identify different objects which hold the same values; references that encapsulate identity are only equivalent to other references to the same object. If references to something encapsulate identity, the thing in question is an entity. $\endgroup$
    – supercat
    Apr 19, 2014 at 21:19
  • $\begingroup$ Right, so every value correspond to an entity, however the process by which comparison is made defines whether we're dealing with values or entities (within your own terminology). Is that what you mean? $\endgroup$
    – didierc
    Apr 20, 2014 at 3:28
  • $\begingroup$ @didierc: The fundamental issue isn't comparison, but control. Consider two objects George and Larry of the same class with a private or protected field Fred. If George has exclusive controls the states encapsulated by George.Fred then it encapsulates value (likewise with Larry and Larry.Fred). If George.Fred identifies objects whose state can change outside their George's control, then that object is an entity. If George.Fred and Larry.Fred are values, then if the observable properties of George.Fred and Larry.Fred match, they will continue to do so unless... $\endgroup$
    – supercat
    Apr 20, 2014 at 20:49
  • $\begingroup$ ...George or Larry changes them, so they should be regarded as equivalent. If their states could independently be changed without George or Larry's involvement, then they should not be regarded as equivalent. The method of comparison isn't what makes something a value or an entity, but things should only report themselves as equivalent if there's no way they could become non-equivalent without the involvement of the thing that's asking for the comparison. $\endgroup$
    – supercat
    Apr 20, 2014 at 20:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.