Universal class and its features
The Eiffel inheritance mechanism is set up in such a way that every class is a descendant of a Kernel Library class called ANY . The features of this class provide a number of generally applicable facilities covering such needs as comparison, copying and rudimentary input and output.
The structure of universal classes
Every class which has no inheritance clause is understood to have an inheritance clause of the form
inherit ANY
As a result, every developer-defined class is a descendant of ANY . You may introduce your own project specific features in ANY so that all the classes of your system will be able to use these features.
Using the universal classes
If you need to rename or redefine a feature inherited from one of the universal classes, you should include an explicit inheritance clause, as in
class C inherit ANY rename out as basic_out redefine print end ... feature ... end
The features of ANY are usable in both qualified and unqualified form. For example, the argumentless function out, which produces a printable representation of any object, may be called under either of the forms
x := out x := a.out
The first call yields a printable representation of the current object; the second, which assumes that a is not void, yields a printable representation of the object attached to a.
Input and output features
Some of the features of ANY cover common input and output needs.
Feature io
, of type STD_FILES , gives access to standard input and output facilities. For example, io.input
is the standard input file and io
.new_line
will print a line feed on the standard output. Feature io
is declared as a once function which, when first called, returns the value of an instance of STD_FILES that provides access to the standard input, the standard output and the error output. As a result, io
is never void, so that operations such as io
.new_line
are always possible.
Function out
, of type STRING , is a universal mechanism for obtaining a simple external representation of any object. For non-void x
of any type, the string x.out
is a printable representation of x
. This works for x
of all types, reference or expanded. For example, if x
is an integer expression, x.out
is its string representation, such as -897
; if n is a non-void reference, x.out
is (recursively) the concatenation of the result of applying out to the successive fields of the attached object, each labeled by the name of the corresponding attribute. You may redefine out in any class to specify any suitable format for displaying instances of the class. To obtain the default representation regardless of any redefinition of out, use tagged_out, declared as a frozen synonym of the original out.
The call print (x)
will output the value of x.out
on the default output if x
is not void, and do nothing otherwise.
Copy and comparison routines
Procedure copy copies the fields of an object onto those of another. It is used under the form
target.copy (source)
Here both target and source must be non-void; this means that copy
is only good for copying onto an object that already exists. If you need both to allocate a new object and to initialize it as a copy of another, use the function twin
. For non-void source, the assignment
target := source.twin
starts by creating a new object, then populates its fields to be identical to source
.
The boolean function equal
compares two objects for field-by-field equality. This is different from the equality operators =
and /=
which, in the case of reference types, compare references, not objects.
The function deep_twin
produces a duplicate of an entire object structure. The boolean function deep_equal
determines whether two object structures are recursively identical. These routines are the deep counterparts of the shallow copy and equality tests provided by twin
and equal
.
A class that needs a specific notion of equality and the corresponding copy semantics may redefine copy
and is_equal
(from which equal
follows, since equal (a, b)
is defined as a.is_equal (b)
for non-void a
). You will find such redefinitions in a number of classes of the Base libraries. For example an instance of STRING is a string descriptor containing a reference to the actual character sequence, not that sequence itself, so that what the default equal compares and the default copy copies is the descriptor, not the string. Class STRING redefines these routines to yield the semantics normally expected by string clients; the frozen variants standard_copy
and standard_equal
, originally declared as synonyms to equal
and copy
, remain available with the default semantics.
The function twin
is defined in terms of copy
, and so will follow any redefinition of copy
. This makes it impossible to change the semantics of one but not of the other, which would be a mistake. The variant standard_twin
is defined in terms of standard_copy
.
Type information
The string-valued query generator
, applied to any object, returns the name of the object's generating class: the class of which it is an instance. The boolean function conforms_to
makes it possible to test dynamically whether the type of an object conforms to that of another - that is to say whether the first one's generator is a descendant of the second one's.
These two features enable clients to ascertain the dynamic type of an entity at runtime. They are only useful for low-level components; the normal mechanism for type-dependent operations is dynamic binding.
Miscellaneous
The query Void, of type NONE
, denotes a reference that is always void - not attached to any object.
Procedure do_nothing
does what its name implies.
Function default also has an empty body; its result type is like Current
, so what it returns is the default value of the current type. This is mostly interesting for expanded types, since for reference types the default value is simply a void reference.