Chapter 2 

The BASIC Cluster 
=================

   The  BASIC cluster  contains all  those  classes that  almost every 
   Eiffel program will need. Some of  these classes are special in the 
   sense that  the Eiffel/S compiler  knows about them  and gives them 
   special  treatment. Others  are classes  like  any other  class but 
   provide important services such as  access to the facilities of the 
   operating system. 


   The basic  classes of Eiffel/S  differ in several  aspects from the 
   classes defined  in me2  . In fact  Meyer has  recently changed the 
   class definitions of the basic classes and even introduced some new 
   classes.  We have  implemented most  of the  features of  the basic 
   classes   but  we   strongly  disagree  with   some  of  the  newer 
   `improvements' and some of the old features. We hope, however, that 
   there will be a standard for the basic classes in the near future. 



2.3 The universal classses 
==========================


   There are four classes that can  be described as `universal' in the 
   sense that every class  inherits from three of  them and the fourth 
   inherits from every class. They are the classes 

   GENERAL PLATFORM ANY NONE 

   In  fact  PLATFORM  inherits from  GENERAL  and  ANY  inherits from 
   PLATFORM. Every other  class which has  no inherit clause inherits 
   automatically from ANY. Class NONE inherits from every class. 


2.3.1 GENERAL 
=============

   The  class  GENERAL  provides  some  features  that  are  needed in 
   virtually every Eiffel class. These are 

 clone (other  : ANY)  : like  other 
   --  Create an  object with same dynamic type as 
   -- `other' and then copy `other' onto the result. 

   ensure clone_is_equal : equal (result, other) 

 conforms_to  (other  :  ANY)  : BOOLEAN  
   --  Is  dynamic  type of `Current' a 
   -- descendant of dynamic type of `other'? 

 copy (other :  like current) 
   --  Copy `other' field-by-field onto Current.
   require 
      same_type : same_dynamic_type (current, other) 
      source_not_void : other /= void
   ensure 
      copy_is_equal : is_equal (other) 

 deep_clone  (other  : ANY)  :  like other  
   --  Recursive ("deep") version of `clone'. 
   ensure 
      clone_is_deep_equal : deep_equal (result, other) 

 deep_copy (other : like current) 
   -- Recursive ("deep") version of `copy'. 
   require 
      same_type : same_dynamic_type (current,   other) 
      source_not_void : other /= void 
   ensure 
      copy_is_deep_equal : is_deep_equal (other) 

 deep_equal (some : ANY, other : like some) : BOOLEAN 
   -- Recursive ("deep") version of `equal'. 

 equal (some : ANY, other : like some) : BOOLEAN 
   -- Are `some' and `other'  both  Void or
   --  both non-Void  and  then field-by-field identical? 

 is_deep_equal  (other  :  like current)  :  BOOLEAN  
   -- Recursive ("deep") version of `is_equal'. 
   ensure 
      shallow_equal : result implies is_equal (other) 

 is_equal  (other :  like current)  : BOOLEAN 
   -- Are  Current and `other' field-by-field identical? 
   require 
      other_not_void : other /= void 
   ensure  
      same_type  : result  implies  same_dynamic_type (current, 
                   other) 

  same_dynamic_type (some, other : GENERAL) : BOOLEAN 
   -- Is dynamic  type of `some' identical with 
   -- dynamic type of `other'? 

  standard_copy    (other   :  like   current)   
   --   Copy  `other' field-by-field onto Current. 
   require    
      same_type   :   same_dynamic_type   (current,   other) 
      source_not_void : other /= void 
   ensure 
      copy_is_equal : is_equal (other) 

   standard_is_equal (other : like current) : BOOLEAN 
      -- Are Current  and `other' field-by-field 
      -- identical? 
   ensure  
      same_type  : result  implies  same_dynamic_type (current, 
                   other) 

   void : NONE 
      -- (This is only a dummy declaration) 

   Two of these features have two names, the second one beginning with 
   the prefix standard_.  The two names ---  the one with standard_ 
   in front and the one without --- are synonyms for the same routine. 
   The version  called standard_is  frozen; that  is, it  may not be 
   redefined in a derived class. The version without standard_in the 
   name may  be redefined as  needed. Thus  one can always  be sure to 
   have the original version of  xxx available under the name standard 
   _xxx. 

   With the exception of  is_equal and copy in  fact all features of 
   GENERAL are frozen. Since equal is based on is_equal and clone on 
   copy  one can  indeed redefine  the  effect of  equal and  clone by 
   redefining is_equal and copy. 

   Each of the four routines is_equal, equal, copy and clone has a 
   corresponding  deep_version.  The version  without  deep_in the 
   name only  proceeds to  a depth  of one.  The `deep'  version works 
   recursively to the maximum possible depth. 


   The function  equal tests  its two  arguments to  see whether their 
   attributes are identical field by  field. Here `identical' means in 
   the sense of the = operator. 

   Suppose the class C has an  attribute x of non--expanded type (i.e. 
   of  reference  type). Then  for  entities a  and  b of  type  C the 
   statement equal (a, b) = true means among other things that a.x and 
   b.x refer to the same object --- i.e. a.x = b.x holds. 

   On the  other hand  deep_equal (a,  b) =  true means  that (among 
   other things) deep_equal (a.x, b.x) =  true holds. a.x = b.x need 
   not be true. 

   In the same vein the assignment a := clone (b) will have the effect 
   that a.x =  b.x holds ---  that is, a.x  and b.x refer  to the same 
   object after cloning. On the other  hand a := deep_clone (b) will 
   mean that a.x is a copy of  b.x. Hence after a := deep_clone (b) 
   we would have deep_equal (a.x, b.x) = true but not a.x = b.x. 


   Note that the  semantics of is_equal and  copy are different from 
   those defined in me2 . Both require that the current object and the 
   argument  are  of  the  same  dynamic  type.  The  reason  for this 
   requirement is that equality is usually an equivalence relation --- 
   in particular it is symmetric  (if a is equal to  b then b is equal 
   to a).  Unfortunately, Meyer's  definition of  is_equal does not 
   establish an equivalence relation and was therefore rejected by the 
   authors of Eiffel/S. 


   
2.3.2 PLATFORM 
==============

   The   class   PLATFORM  contains   any  information   that  may  be 
   platform--specific. It currently has only one constant. 

 Maximum_character_code  :  INTEGER  is  ???  
   --  The  largest value returned by the 
   -- function `to_integer' in class CHARACTER. 

   This constant is usually 255. 


2.3.3 ANY 
=========

   The class ANY  inherits from PLATFORM  and adds no  new features in 
   the version  supplied with  the Eiffel/S  package. It  is the right 
   place to include routines that may  be needed by all classes within 
   a large project or within an entire company. One should not put any 
   attributes in ANY since they would be inherited by every class. 


2.4 The property classes 
========================

   The  classes  COMPARABLE, NUMERIC  and  HASHABLE  describe certain 
   properties that  other classes may  inherit. These  classes are all 
   deferred. 

2.4.4 COMPARABLE* 
=================

   The class COMPARABLE abstracts the concept of a total ordering. 

 deferred class COMPARABLE 

 
 infix "<" (other : like Current) : BOOLEAN 
   -- Is Current STRICTLY less than `other'? 
   require 
      other_not_void : other /= Void 
   ensure 
      anti_symmetric : Result implies not (other < Current) 

 infix "<=" (other : like Current) : BOOLEAN 
   -- Is Current less or equal than `other'? 
   require 
      other_not_void : other /= Void 

 infix ">" (other : like Current) : BOOLEAN 
   -- Is Current STRICTLY greater than `other'? 
   require 
      other_not_void : other /= Void 

 infix ">=" (other : like Current) : BOOLEAN 
   -- Is Current greater or equal than `other'? 
   require other_not_void : other /= Void 

 compare (other : like Current)  : INTEGER 
   -- Compare Current with `other'. 
   -- '<' <==> Result < 0 
   -- '>' <==> Result > 0 
   -- Otherwise Result = 0 
   require 
      other_not_void : other /= Void 


   The  infix operator  <  is deferred.  All  the other  functions are 
   derived from this one and are effective. Thus a class that inherits 
   from COMPARABLE need only  redefine < to be  effective. It gets the 
   other functions `for free'. However,  one may want to redefine some 
   or all of them as well for reasons of efficiency. 


   The function  compare returns  a result  less than  0 if  current < 
   other, a result greater than 0 if current > other and 0 otherwise. 
   This is a convenience function. In situations where one might write 

   if x < y then ... elseif x > y then ... else -- x = y ! ... end 

   one can instead write 

   cmp := x.compare (y) 
     if cmp < 0 then ... elseif cmp > 0 then ... else ... end 

   and save one  function call (the tests  x < y, x  > y are function 
   calls unless x, y are of basic type). 


   The order relation provided by the  class COMPARABLE can be used to 
   introduce  a  concept  of equality  in  any  class  inheriting from 
   COMPARABLE. We may regard two entities x and y as `equal' if 

   x <= y and then x >= y 



2.4.5 NUMERIC* 
==============

 deferred class NUMERIC 


 infix "+" (other : like Current) : like Current 
   -- Add `other' to Current. 
   require 
     other_not_void : other /= Void 

 infix  "-" (other  :  like Current)  :  like Current  
   -- Subtract `other' from Current. 
   require 
      other_not_void : other /= Void 

 infix  "*" (other  :  like Current)  :  like Current
   -- Multiply Current with `other'. 
   require 
      other_not_void : other /= Void 

 infix "/" (other : like Current) : like Current
   -- Divide Current by `other'. 
   require 
      other_not_void :  other /= Void 
      valid_divisor  :  valid_divisor (other) 

 infix "  " (exp  : INTEGER)  : like  Current
   --  Raise Current to  `exp'-th    power.   
   require  
      other_not_void   :   other   /=  Void 
      non_negative_exponent : exp >= 0 

 prefix "+" : like Current
   -- Unary plus of Current 

 prefix "-" : like Current
   -- Unary minus of Current 

 valid_divisor (other  : like Current)  : BOOLEAN 
   --  Is `other' a valid divisor for `Current'? 
   require 
      other_not_void : other /= Void 


   All features are deferred. 



   The infix operator 

   infix " " (exp : INTEGER) : NUMERIC 

   raisies current  to the power  exp. The power  operator is defined 
   differently  from  the one  in  me2  which allows  real  numbers as 
   exponents. The  reason is  that although  it is  always possible to 
   define the  power operator  for non--negative  integer exponents as 
   soon as we have a notion  of multiplication, it is impossible to do 
   the same for real exponents in  such a general context as the class 
   NUMERIC --- and  for most potential descendants  of NUMERIC it will 
   turn out to be altogether impossible. 



   
2.4.6 HASHABLE* 
===============

   The deferred class HASHABLE has the single deferred feature 

 hash_code : INTEGER 
   ensure 
      non_negative : Result >= 0 

   This class can be  inherited by any other  class whose objects need 
   to be used as hash keys to a hash table. 


   
2.5 The special classes 
=======================

   In  addition to  the universal  classes  the following  classes are 
   known to the Eiffel/S  compiler and are treated  by it in a special 
   way. 

   BOOLEAN
   CHARACTER 
   INTEGER 
   REAL   
   BOOLEAN_REF
   CHARACTER_REF 
   INTEGER_REF
   REAL_REF 
   ARRAY [ G ] 

   The  REF  classes  were  introduced  by  Bertrand  Meyer  after the 
   publication of the first edition of  me2 to deal with some problems 
   arising from  expanded classes  and inheritance.  You will probably 
   never need  to use them  directly but if  you want to  see how they 
   might be used take a look  at the sample programs in examples/basic 
   

     
2.5.7 BOOLEAN 
=============


   The expanded (basic) class  BOOLEAN inherits from the non--expanded 
   class BOOLEAN_REF and provides the logical infix operators 

 infix "and" (other  : BOOLEAN) :  BOOLEAN 
   -- `and'  of Current with `other'.
 
 infix "and then" (other : BOOLEAN) : BOOLEAN 
   -- Semi-strict `and' of Current with `other'.
 
 infix "implies" (other : BOOLEAN) : BOOLEAN 
   -- Does Current imply `other'. 

 infix "or" (other  : BOOLEAN) :  BOOLEAN 
   -- `or'  of Current with `other'
 
 infix "or else"  (other : BOOLEAN) :  BOOLEAN 
   -- Semi-strict `or' of Current with `other'
 
 infix "xor" (other : BOOLEAN) :  BOOLEAN 
   -- `xor' of Current with  `other' 

 prefix "not" : BOOLEAN 
   -- `not' of Current. 



2.5.8 CHARACTER 
===============


   The  expanded   (basic)  class   CHARACTER   inherits   from  the 
   non-expanded class  CHARACTER_REF  which inherits from COMPARABLE 
   and thus provides an ordering of the objects of type CHARACTER. In 
   addition it supplies functions 

   to_integer : INTEGER -- Integer code of character 
     to_lower : CHARACTER -- Lower case version of character 
     to_upper : CHARACTER -- Upper case version of character 

   to_integer returns the code of the character, to_lower and to_ 
   upper provide case conversion functions. 


   
2.5.9 INTEGER 
=============

   The expanded (basic) class  INTEGER inherits from the non-expanded 
   class INTEGER_REF  which inherits  from COMPARABLE,  NUMERIC and 
   HASHABLE.  In addition  it provides  two  new infix  operators for 
   integers 

 infix  "//"  (other  :  INTEGER) :  INTEGER  
   -- Divide  Current by `other'. 
   -- Note : Integer division 
   require 
      non_zero_divisor : other /= 0 

 infix "\\" (other : INTEGER)  : INTEGER 
   -- Remainder  of division of Current  by `other'. 
   require 
      non_zero_divisor : other /= 0 

   The expression 

   a \\ b 

   represents  the  remainder after  dividing  a  by b.  This  is the 
   operator call mod or modulo in other languages. 


   The compiler treats the class INTEGER  as if it conformed to REAL. 
   This allows automatic  type conversion. Thus  in situations where a 
   real  number  is expected  one  may  write 1  instead  of  1.0. The 
   language  definition  in  fact  states  that  for  arithmetic infix 
   operators  the two  arguments  are automatically  converted  to the 
   higher  of  the two  types  (i.e. integer  to  real if  one  of the 
   arguments is real) before the  operation is evaluated. Thus one may 
   mix integers and reals in arithmetic expressions. For a REAL entity 
   r  and  an  INTEGER entity  n  we  may use  both  of  the following 
   expressions 

      r + n 
      n + r 



2.5.10 REAL 
===========

   The  expanded (basic)  class REAL inherits from the non-expanded 
   class REAL_REF  which inherits  from COMPARABLE  and NUMERIC. It 
   adds no new features. 


   In the  Eiffel/S implementation the  numbers of type  REAL have the 
   highest precision the platform offers. 



2.5.11 DOUBLE 
=============

   In the  Eiffel/S implementation  of the  Eiffel language  the class 
   DOUBLE is identical to the class REAL. 


   

2.5.12 ARRAY 
============

   The generic class  ARRAY [ G  ] implements the  familiar concept of 
   array. It provides storage for  a fixed (finite) number of elements 
   of a fixed but otherwise arbitrary  type G. The elements stored in 
   the array can be retrieved with the function item and replaced with 
   the procedure put. 

   We give the  formal descriptions of  all the features  of the class 
   ARRAY [ G ]. 


 class ARRAY [ G ] 

 make (minindex : INTEGER, maxindex  : INTEGER) 
   -- Allocate array. If minindex  <= maxindex, 
   --  index range is  minindex .. maxindex.  Other- 
   -- wise the array is empty. 
   require 
      meaningful_count : maxindex >= minindex - 1 

 all_cleared : BOOLEAN -- Are all items set to default values? 

 clear_all -- Set all items to default values. 

 copy (other  : ARRAY  [ G  ] )  
   -- Copy  `other' elementwise onto Current. 

 count : INTEGER -- Length of index interval. 

 empty : BOOLEAN -- Is array empty? 

 force (element : G, index : INTEGER) 
   -- Put `element' at position `index'.  
   -- Resize  array,  if `index'  is  not 
   --  inside current bounds. 
   ensure 
      bounds_adjusted :  lower <= index and  then index <= upper 
      item_in_place : item (index) = element 

insert (element  : G,  index :  INTEGER)
   --  Insert `element' after position `index'. 
   --  Element at position `upper'  will be lost! 
   --  Note: Insertion is AFTER `index'! 
   require 
      inside_bounds : lower - 1 <= index and then index < upper 

 is_equal (other : ARRAY [ G ]  ) : BOOLEAN 
   -- Test if Current and `other' are 
   -- elementwise equal. 

 infix  "@",  item (index  :  INTEGER)  : G  
   --  Item  at position `index'. 
   require 
      inside_bounds : lower <= index and then index <= upper 
      lower : INTEGER -- Lower index bound 

 move (lower_index, upper_index, distance : INTEGER)
   -- Move Range `lower_index'  .. `upper_index'  by  `distance'
   --  positions. Neg. distance moves  towards lower indices.  
   -- Free  places get default values. 
   require
      non_empty_range   :    lower_index   <=   upper_index 
      inside_bounds_before : lower <= lower_index and then 
                             upper_index <=  upper  
      inside_bounds_after :  lower <=  lower_index +  distance and 
                             then upper_index + distance <= upper 

 put (element : G,  index : INTEGER)
   --  Put `element' at position `index'. 
     require 
       inside_bounds : lower <= index and then index <= upper 
     ensure 
       item_in_place : item (index) = element 

 remove (index :  INTEGER) 
   -- Remove  element at position `index'. 
   -- Elements after `index' will  move 
   -- one position left (=towards lower indices). 
   -- Element at position `upper' is set to default 
   -- value.
   --  Note :  Position `upper' will  be set  to
   -- appropriate default value. 
   require 
      inside_bounds : lower <= index and then index <= upper 

 resize  (new_min,  new_max  : INTEGER)  
   --  Resize  array.  
   -- No elements will be  lost in the  intersection 
   -- of  [ lower, upper ]  and [  new_min, new_max  ] . 
   --  New positions  will be initialized with  appropriate  
   -- default  values.  
   require 
       meaningful_count : new_max >= new_min - 1 

 reindex (new_lower : INTEGER) 
   -- Change index interval so that 
   -- it starts at `new_lower'. No 
   -- elements will be lost. 
   ensure  
      bounds_adjusted  : lower = new_lower and then upper = 
                         new_lower + count - 1 

 size  :  INTEGER 
   --  For  compatiblity  only 
   --  Length  of index interval. 

 to_external : POINTER -- Pointer to actual storage area. 

 upper : INTEGER -- Upper index bound 
 
 wipe_out -- Empty the array, discard all items. 


   The  two procedures  resize and  reindex probably  need a  bit more 
   explanation. With resize  the size of  the array can  be changed as 
   the name suggests  but the boundaries  can also be  altered. If the 
   index range before resize was a to  b and after resize is from c to 
   d,  then  an  element  that was  at  index  i  before  resize will 
   afterwards be 

 * either still at index i if i is in the range c to d 

 * or no longer accessible if i is not in the range c to d. 


   With reindex  on the  other hand  the size  of the  array cannot be 
   altered. The index range  is merely translated to  begin at the new 
   lower bound  new_lower. No element  gets lost.  The element that 
   was previously  to be found  at index  lower is now  at index new_ 
   lower, the element that was at lower + 1 is now at new_lower + 1 
   and so on. 


   The  routine move  can be  used to  move a  block of  array entries 
   within the existing array.  Thus if the index  range runs from 1 to 
   100 then the instruction 

      move (50, 69, -30) 

   will move the twenty objects at  the positions 50, 51, 69 downwards 
   by a distance of 30  to the positions 20, 21,  39 . The index range 
   is not altered by this routine. 


   

2.6 The other basic classes 
===========================



2.6.13 BITS n 
=============


   The  expanded  (basic) class  BITS  n (n  a  non-negative integer 
   constant) provides bit--fields  that can be  manipulated by logical 
   operations. 

 class BIT_N
 
 count : INTEGER -- Nr of bits in sequence 

 infix "and" (other :  BIT_N) : BIT_N 
   --  Bitwise `and' of Current with `other'
 
 infix "or"  (other :  BIT_N) : BIT_N
   -- Bitwise  `or' of Current  with `other' 

 infix "xor" (other :  BIT_N) : BIT_N 
   --  Bitwise `xor' of Current with `other' 

 infix "implies" (other : BIT_N) : BIT_N 
   -- Bitwise implication of Current with `other' 

 prefix "not" : BIT_N -- Bitwise `not' of Current. 

 put (value : BOOLEAN, idx : INTEGER) 
   -- Set bit at position `idx' to '0', if 
   -- value = false, to '1' otherwise. 
   require 
      inside_bounds : 1 <= idx and then idx <= count 

 copy (other : BIT_N) -- Copy other onto Current 

 is_equal (other : BIT_N) : BOOLEAN 
   -- Is Current bitwise equal to `other'? 

 item  (idx  :  INTEGER)  :  BOOLEAN 
   --  Bit  at  position `idx', interpreted
   -- as boolean value (0 = false). 
   require 
      inside_bounds : 1 <= idx and then idx <= count 


 to_string :  STRING 
   -- String  representation of bit  sequence 
   -- A zero  bit is  mapped to  '0',  a one  bit 
   --  to  '1'. item  (1) is rightmost character
   -- in string. 
   ensure
      same_count : Result.count = count 

 from_string (s : STRING) 
   -- Fill sequence from string `s'.'
   -- 's'    must contain `0' and `1' characters only. 
   require 
      string_not_void  : s /=  Void
     valid_initializer  : 
   -- `s' contains `0' and `1' only not_too_long : s.count <= count 

   Note that a implies b is the same as (not a) or b. 

     The procedure put sets the bit at  position index to 1 if value = 
   true  and to  0 otherwise.  The  function item  retuns the  bit at 
   position index treating a 1 as true and a 0 as false. 


   The two routines 

      to_string : STRING 
      from_string (s : STRING) 

   can be  used to  convert strings containing  only `0'  and `1' into 
   objects of type BITS n and vice versa. 

   Please see the  compiler manual for further  details about the BITS 
   type. 


   

2.6.14 STRING 
=============


   The Eiffel runtime system must supply special support for the class 
   STRING  ---  if  for  no other  reason  than  because  the language 
   includes string constants (`literal strings'). 


   The    class   STRING   inherits   from   COMPARABLE   to   provide 
   lexicographical ordering  of strings  and from  HASHABLE to provide 
   the possibility to use strings as  hash keys. In addition to making 
   the deferred features from  these abstract classes effective STRING 
   redefines the  features copy and  is_equal from GENERAL  in a way 
   suitable for strings. 

 class STRING 

 make (nr_blanks : INTEGER) 
   -- Initialize string with `nr_blanks' blanks 
   require
      non_negative_size : nr_blanks >= 0 

 infix "<"  (other :  STRING) :  BOOLEAN 
   --  Is Current  less than `other'? 

 adapt (s : STRING) 
   -- Initialize Current's text from 
   -- string s. 

 append (other : STRING) 
   -- Append `other' to Current 
   require 
      argument_not_void : other /= void 

 compare (other : STRING) : INTEGER 

 copy (other :  STRING) 
   -- Copy `other'  onto Current including 
   -- `other''s character sequence. 

 count : INTEGER -- String length 

 empty : BOOLEAN -- Has string length 0? 

 extend (ch : CHARACTER)
   -- Append `ch' to string 

 fill_with (c  : CHARACTER) 
   --  Fill entire  string with character `c'
 
 hash_code : INTEGER 

 insert (ch  : CHARACTER,  index :  INTEGER) 
   --  Insert `ch' AFTER position `index'. 
   require
      valid_position : 0 <= index and then index <= count 

 is_equal (other : STRING) : BOOLEAN  
   -- Has Current the same text as `other'? 

 infix "@",  item (index  : INTEGER)  : CHARACTER
   -- Character at position `index'. 
   require 
      inside_bounds : 1 <= index and then index <= count 

 precede (ch : CHARACTER)
   -- Prepend `ch' to string 

 prepend (other : STRING) 
   -- Prepend `other' to Current 
   require 
      argument_not_void : other /= void 

 put (ch  : CHARACTER,  index : INTEGER)
   -- Put  `ch' at position  `index'. 
   require 
      inside_bounds : 1 <= index and then index <= count 

 remove (index : INTEGER) 
   -- Remove character at position `index'. 
   require 
      inside_bounds : 1 <= index and then index <= count 

 substring (from_index  : INTEGER, to_index  : INTEGER)  : STRING 
   -- Create   a  string  which  contains  exactly
   -- the  char's  from `from_index' to `to_index' 
   -- of Current (inclusive). 
   require
      sub_interval  : 1  <= from_index  and then  from_index <= 
                          to_index and then to_index <= count 

 to_external : POINTER -- For passing to external routines 

 to_lower -- Convert text to lower case 

 to_upper -- Convert text to upper case 

   The feature adapt can  be used to initialize  an object which is an 
   instance of a descendant of STRING with a text string. 


   

2.7 ENVIRONMENT 
==============


   Most operating systems provide a running program with access to the 
   surrounding environment. In particular  one usually expects to have 
   access to the command  line with which the  user called the program 
   and to `environment variables' the  user can set before calling the 
   program. 


   The class ENVIRONMENT provides Eiffel programs with access to these 
   parts of the  environment. The name with  which the current program 
   was called is available through the attribute 

 program_name : STRING 

   The rest of  the command line  is regarded as  an array of strings. 
   The number of elements in this array is given by the attribute 

 arg_count : INTEGER 

   and one  can retrieve  the nth  element from  this array  with the 
   function 

 arg_item (index : INTEGER) : STRING 

   This function of course has the precondition 

   1 <= index and then index <= arg_count 

   The other aspect of the  environment that is accessible through the 
   class  ENVIRONMENT  is  the list  of  environment  variables. These 
   variables  have names  that are  strings and  values that  are also 
   strings. 


   One  can retrieve  the value  of an  environment variable  with the 
   function 

 env_item (name : STRING) : STRING 

   which returns the value of  the environment variable with name name 
   . The only precondition is that name /= void. 


   One  can also  set the  values of  environment variables  using the 
   procedure 

 env_put (name, value : STRING) 

   Neither name nor value is allowed to be void. 


   The effect of this instruction  depends on the underlying operating 
   system. Under UNIX, for example, this instruction will only have an 
   effect  for  `child  processes' ---  i.e.  for  processes  that the 
   current process later generates using  the system call fork. Under 
   other   operating  systems  the  instruction  may  have  a  lasting 
   effective or none at all. 




2.8 BASIC_IO 
============


   The class  BASIC_IO provides a  mechanism to do  normal input and 
   output in a simple way.  If all one wants to  do is write a message 
   on the screen  or fetch a string  from the user,  this is the right 
   class to use. It has the following features. 

 end_of_input   :  BOOLEAN 
 get_bool 
 get_char 
 get_double 
 get_int 
 get_newline 
 get_real
 get_string 
 
 last_bool  : BOOLEAN 
 last_char  : CHARACTER
 last_double: DOUBLE
 last_int   : INTEGER
 last_real  : REAL 
 last_string: STRING
  
 put_bool  (b  :  BOOLEAN) 
 put_char  (c  :  CHARACTER)  
 put_double (d :  DOUBLE) 
 put_int   (n  :  INTEGER) 
 put_newline  
 put_real  (r  :   REAL) 
 put_string (s :  STRING) 

 set_standard_output
 set_error_output 


   The meaning of most of these  features is evident. All the routines 
   called get_xxx  read their input  from the  standard input medium 
   (usually the keyboard)  and record the  result in the corresponding 
   attribute called last_xxx.  Only get_newline needs  a bit more 
   explanation; it  reads input  until a  newline character  comes. It 
   does not save any of this input including the newline character. 


   All  the  routines  called  put_xxx  write  their  output  to the 
   standard output  medium -  usually the  screen. If  the operating 
   system  allows  I/O-redirection,  the  user  can  connect standard 
   output to a  file, the printer  or some other  device. In that case 
   the output of these put_xxx routines will go to the corresponding 
   medium. 


   If the  operating system supports  the concept of  a standard error 
   output, then set_error_output  causes all further  output to go 
   to  that stream.  Output  can be  redirected  back to  the standard 
   output medium by a succeeding call to set_standard_output. 


   The routine  get_string is  a procedure,  not a  function (it has 
   side effects!).  The string  that it  fetches can  be found  in the 
   attribute last_string. 


   Note  that after  each call  to  get_string the  attribute last_ 
   string refers  to a  different object.  Thus code  of the following 
   kind is safe. 


   io : BASIC_IO 
   i : INTEGER 
   a : ARRAY [ STRING ] 
   from 
     !!io
     !!a.resize  (...) 
     i := 1
     io.get_string 
   until 
     io.end_of_input 
   loop 
     if 
        i > a.size then 
            a.resize (...) 
     end 
     a.put (io.last_string, i) 
     io.get_string 
     i := i + 1 
   end 

   That  is, each  entry in  the array  a will  be a  different string 
   object. 


   Note  that  if the  input  stream  is connected  to  a  file (using 
   I/O-redirection) then  end_of_input will become  true when the 
   end of the file is reached. If the input stream is connected to the 
   keyboard, then end_of_input becomes  true when the user presses 
   ctrl-D (UNIX) or ctrl-C (MS-DOS). 




2.9 FORMAT 
==========


   The class BASIC_IO  provides simple input  and output for various 
   basic objects. In  particular objects of type  INTEGER and REAL are 
   written to output  in some standard format  that will be acceptable 
   in most cases. 


   For those  who need  more control  over the  format in  which these 
   types are written we  have the class FORMAT.  It has the following 
   features. 

 b2s (b : BOOLEAN) : STRING 

 c2s  (c : CHARACTER) : STRING

 i2s (fmt : STRING, i : INTEGER) : STRING

 r2s (fmt : STRING, r : REAL) : STRING 

 s2s (fmt , s : STRING) : STRING

 s2b (s : STRING) : BOOLEAN

 s2c (s : STRING) : CHARACTER

 s2i  (s : STRING) : INTEGER 

 s2r (s : STRING) : REAL 

   The  put_xxx  routines  in  BASIC_IO  could  be  implemented as 
   follows: 

   put_bool (b : BOOLEAN) is 
      do 
          put_string (b2s (b)) 
      end 


   put_char (c : CHARACTER) is
      do 
          put_string (c2s (c)) 
      end 

   put_int (i : INTEGER) is 
      do 
          put_string (i2s (std_fmt, i)) 
      end 

   put_real (r : REAL) is 
      do 
          put_string (r2s (std_fmt, r)) 
      end 


   where std_fmt is some appropriate standard format string. 


   The real significance of the class FORMAT, however, is the ability 
   to write  integers and  reals to the  output in  a different format 
   from the one provided by put_int and put_real. 


   The argument fmt of  type STRING required by  the functions i2s and 
   r2s is expected to be a  string of the form "mmm.nnn", where "mmm" 
   is  a  number  specifying  the  `field  width'and  "nnn"  a  number 
   specifying the `precision'. 


   The field width  specifies the minimum number  of characters in the 
   resulting string. If "mmm" begins with  a 0 the string is filled on 
   the  left with  the character  `0' if  needed to  pad to  the given 
   minimum width.  Otherwise the blank  character is used  to pad. The 
   string may, however, be  longer than the given  field width, if the 
   field width does not suffice  for expressing the number. One should 
   remember that for real numbers the  decimal point has to be counted 
   when computing the needed field width. 


   The precision means the number of  decimal places for a real number 
   and  for an  integer  the minimum  number  of digits  used.  If the 
   precision for an integer is p and the decimal representation of the 
   integer would normally need fewer than p digits, then the string is 
   preceded with  as many  0 digits  as needed  to reach  the required 
   number of digits. 


   Strings can be  formatted using s2s. Here,  too, the format string 
   has the form "mmm.nnn", where "mmm" is the field width and in this 
   case "nnn" specifies the maximum number of characters in the string 
   returned.  If  "nnn" is  missing,  then  a maximum  of  infinity is 
   assumed. 



   r2s ("10.6", pi)          --> " 3.141593" 
   r2s ("010.6", pi)         --> "003.141593" 
   i2s ("5", 1)              --> " 1"
   i2s  ("5.4", 1)           --> "  0001" 
   i2s ("05.4", 1)           --> "00001"  
   s2s   ("6.8",  "long")    --> "  long"
   s2s  ("6.8", "superlong") --> "superlon" 





2.10 EXCEPTION 
==============



2.10.15 The features of EXCEPTION 


   The Eiffel  exception mechanism is  one of the  central features of 
   the language. It  supports --- indeed enforces  --- the doctrine of 
   programming  by  contract.  But  it  also  supports  fault tolerant 
   software   by  means  of  the  the  rescue  clause  and  the  retry 
   instruction. 


   Many Eiffel  programs will be  able to use  the exception mechanism 
   just  as it  is.  For those  who need  a  finer grained  control of 
   exceptions we have the class  EXCEPTION. It provides the following 
   features 

 raise  (rout_name, msg  : STRING,  code :  INTEGER, xobject  : ANY)
 
 last_ecall  :  STRING  

 last_etext  :  STRING 

 last_ecode  : INTEGER 

 last_eobj : ANY raise_on_interrupt ignore_interrupt 

   as well as a number of predefined exception codes. 


   When Eiffel assertions  (or loop variants)  are violated the Eiffel 
   runtime system automatically raises  an exception. With the routine 
   raise  from  the  class EXCEPTION  the  Eiffel  programmer  has the 
   possibility of raising  an exception at any  point where this seems 
   appropriate.  The  effect  of calling  raise  is  to  interrupt the 
   execution of the enclosing routine and to return immediately to the 
   calling routine with  an error status. For  the calling routine the 
   effect  is just  as if  the  Eiffel runtime  system had  raised the 
   exception. 


   Four pieces of  information are associated  with every exception: a 
   string naming the routine in which the exception occurred, a string 
   describing the exception, an integer error code that could uniquely 
   specify the type of the exception and (optionally) an Eiffel object 
   that  is  somehow  associated  with  the  exception.  All  of  this 
   information is supplied by the caller of raise. 


   Normally  the message  string and  the error  code will  suffice as 
   designation  of  the  exception  type.  In  such  cases  the fourth 
   argument xobject should be set to  void. However, in cases where a 
   string and an  integer code do  not suffice for  handling the error 
   the  programmer  has  the additional  flexibility  of  providing an 
   arbitrary Eiffel object as  fourth argument. Presumably this object 
   will be used by a rescue clause  in some routine higher up the call 
   hierarchy. 


   The  four  pieces  of  information  attached  to  an  exception are 
   available through the four attributes last_ecall, last_etext, 
   last_ecode and last_eobj.  These should only  be accessed in a 
   rescue clause, where one is certain that an exception has occurred, 
   for otherwise their values are likely to be undefined. 


   One kind of exception gets special treatment: the interrupt signal. 
   This signal is sent  by the operating system  when the user presses 
   the interrupt key. Under UNIX the interrupt key is typically either 
   the DEL--key or the BREAK--key. Under MS--DOS it is the combination 
   Ctrl--C. 


   An  Eiffel  routine  can  announce that  it  does  not  wish  to be 
   interrupted in this way by calling the procedure ignore_interrupt 
   in the class EXCEPTION. If at a later point the routine is willing 
   to allow this exception again it can announce this by calling raise 
   _on_interrupt. 


   Please note  that the default  state is `raise  on interrupt'. Thus 
   programs that do  not wish to  be interrupted by  the interrupt key 
   must   explicitly  call  ignore_interrupt  ---  probably  in  the 
   creation procedure of the root class. 


   
2.10.16 How to use EXCEPTION 

   We give  some guidelines  for the  use of  the class  EXCEPTION for 
   those who need this kind of fine grained control. 


   One  will almost  certainly want  to  introduce some  new exception 
   codes specific to the application being programmed. The recommended 
   way  to  do  this  is  to derive  a  new  class  from  EXCEPTION by 
   inheritance and define the new codes there. 

   class MY_EXCEPTION 

     inherit EXCEPTION 

   feature 
     POLY_NOT_CLOSED  : INTEGER  is 1
     SELF_INTERSECT  : INTEGER  is 2 
     OUT_OF_RANGE : INTEGER is 3 ... 

   end -- class MY_EXCEPTION 

   The  exception codes  in  the range  0  to 9999  are  available for 
   programmer defined  codes. Those above  10000 are  reserved for the 
   Eiffel/S runtime system. 


   In every class  in which programmer exceptions  are to be generated 
   using raise or  in which exceptions  are to be  handled in a rescue 
   clause one should inherit from MY_EXCEPTION. 

   inherit MY_EXCEPTION 
     ... 

   Raising a programmed exception is very easy. 

   if self_intersect (poly) then
      raise ("poly_test", "Self-intersection", SELF_INTERSECT, void) 
   end 

   Rescue clauses  will often  use a  multibranch instruction  to deal 
   appropriately  with the  different  kinds of  exception  that could 
   occur. 

   rescue  
      inspect  last_ecode  
      when  POLY_NOT_CLOSED  then  ...  
      when  SELF_INTERSECT then 
        ... 
      else 
        ... 
      end 

   If the kinds of exceptions that  can occur are more complex than in 
   the example above this use of multibranch instructions could become 
   cumbersome.  In  such cases  it  would  probably be  better  to use 
   exception objects and polymorphism to handle the problem. 

   deferred class X_HDLR 

   feature 

     action is 
        deferred 
        end 

     end -- class X_HDLR 


   class SCT_HDLR 
      inherit X_HDLR redefine action end 

   feature 
     action is 
        local
           io : BASIC_IO 
        do
           !!io 
           io.put_string ("There is a self-intersection. %N")
           io.put_string ("Please check your data. %N)
        end 
     end -- class SCT_HDLR 

   Raising a programmed exception now looks as follows. 

   local sct_hdlr : SCT_HDLR 
     ... 
     if  self_intersect  (poly)  then  
        !!sct_hdlr  raise ("test_poly", "Self-intersection", 
                            SELF_INTERSECT, sct_hdlr) 
     end 

   The rescue clauses can all look as follows. 

   some_routine  is  
      local  
         xhdlr  : X_HDLR  
      do 
         ...  
      rescue  
         xhdlr ?= last_eobj 

         if xhdlr /= void then 
            xhdlr.action
         end
      end 




2.11 SYSTEM_TIME 
================


   In Eiffel/S time is handled internally  as a real number. This real 
   number measures time  in units of one  day and represents Greenwich 
   Mean Time.  Whenever one needs  to interpret this  number for human 
   consumption  one uses  the  class SYSTEM_TIME.  It  provides the 
   following features. 

 year        : INTEGER
 month       : INTEGER 
 day         : INTEGER
 hour        : INTEGER
 minute      : INTEGER
 second      : INTEGER 
 day_of_year : INTEGER 
 day_of_week : INTEGER 

 now : REAL  -- The current time (GMT) 

 localtime (gm_time : REAL) : REAL 
   -- The local time corresponding to
   --  to GMT  `gm_time'. Takes  timezones 
   --  and daylight savings into account. 

 to_time (y, mo, d, h, mi, s : INTEGER) : REAL 

 to_date (t : REAL) 

 sysclock : INTEGER
   -- High resolution system  clock 
   -- Result is in 1/1000 seconds. 
   -- The value  is 0 immediately after 
   -- start of program execution. 

   The features year, month etc. have the obvious meaning but are all 
   0 until the first call to to_date. The routine to_date is used 
   to convert the  internal time representation  to one understandable 
   by human  users. Note, however,  that the  times computed represent 
   Greenwich Mean  Time. The converse  translation is  achieved by the 
   function to_time, which turns a date  given as a sequence of six 
   integers into a real number representing the date in internal form. 
   You can use the function local_time  to convert GMT to your local 
   timezone. 


   The  function  sysclock is  available  for fine  grained  timing of 
   internal  processes.  The  function sysclock  returns  the  time in 
   milliseconds  that  has  elapsed  since  program  start.  The  true 
   resolution of sysclock depends on the hardware platform. 


   Here are two examples for a typical use of to_date. 



   st : SYSTEM_TIME
   months : ARRAY [ STRING ] 
   months :=  << "January", "February", .. "December" >> 
   !!st
   st.to_date (st.now)

   io.put_string  ("The  date   :  ") 
   io.put_string (months.item (st.month)) 
   io.put_char (' ')
   io.put_int  (st.day)
   io.put_string  (", ") 
   io.put_int (st.year) 
   io.put_newline 

   io.put_string  ("The  time :  ")
   io.put_int  (st.hour)
   io.put_char  (':')
   io.put_int   (st.minute) 
   io.put_char   (':')
   io.put_int (st.second)
   io.put_newline 

   ------------------------------------------------- 
   st     : SYSTEM_TIME 
   birth  : REAL 
   death  : REAL
   age_in_days : INTEGER 
   !!st  
   birth  :=  st.to_time  (1777, 4,  30,  0,  0,  0)
   death  :=  st.to_time (1855,  2, 23,  0, 0, 0)  
   age_in_days :=  floor (death -  birth + 0.5) 
   io.put_string  ("C.F.   Gauss  lived   to   be   ") 
   io.put_int   (age_in_days)
   io.put_string (" days old 



   


2.12 INTERNAL 
=============


   A  typical  Eiffel program  creates  numerous objects  while  it is 
   running. Many of these  are soon discarded in  the sense that there 
   is no  longer any  entity referring  to them.  Such objects  can no 
   longer be used by the program: they are `garbage'. 


   If there were no  way to `recycle' such  garbage, an Eiffel program 
   would  soon  use  up  all available  memory.  For  this  reason the 
   Eiffel/S runtime system  includes a `garbage  collector' that works 
   very discretely  in the background  collecting all  the garbage the 
   program leaves  lying around and  returning it to  the memory pool. 
   Normally  the  programmer need  waste  no thoughts  on  the garbage 
   collection process.  For those, however,  who do  need some control 
   over the garbage collector we have the class INTERNAL. 


   The features of this class are the following. 

 disable_collector 
 enable_collector 
 force_collection
 set_threshold (mem_size : INTEGER) 

   With  the procedure  disable_collector one  can turn  the garbage 
   collector off altogether. This can  be useful in the rare situation 
   that a routine is time critical and one wants to be sure that it is 
   not delayed  by the  work of  the garbage  collector. Afterward one 
   turns the garbage  collector on again  using the procedure enable_ 
   collector. Note that the  default condition is `garbage collection 
   on'. 


   One  might  wonder  what  happens  if  one  turns  off  the garbage 
   collector with  disable_collector and  nevers turns  it on again. 
   Will the runtime system eventually run out of memory if the program 
   runs  long enough?  The  answer is  `no';  if the  operating system 
   eventually  declines  to  give the  process  any  more  memory, the 
   garbage collector is automatically turned  on. Then it collects all 
   the garbage  that has accumulated  since the  program started. This 
   could however take some time! 


   For  small programs  it  might seem  exorbitant  to have  a garbage 
   collector working in  the background. One could  be tempted to turn 
   it off in such  cases. There is, however,  a better way of handling 
   this  situation.  The garbage  collector  does not  in  fact become 
   active  until  the amount  of  memory  used has  reached  a certain 
   threshold. This threshold is operating system dependent; under UNIX 
   for example it is likely to  be 1 megabyte. Using the procedure set 
   _threshold  one  can  alter the  threshold  at  which  the garbage 
   collector is activated. One can set  the threshold at a value which 
   is not  expected to  be reached.  Should the  threshold be reached, 
   however, the program will still run normally; the garbage collector 
   will simply be activated. 


   Finally one has  the ability to  force the garbage  collector to do 
   its cleaning  up at  a particular  moment. One  calls the procedure 
   force_collection.  This  will  cause  the  garbage  collector to 
   recycle  all garbage  it can  find at  that moment.  In interactive 
   programs, for  example, one  might want  to call force_collection 
   whenever one is  waiting for input  from the user.  At such moments 
   there is nothing else the program  can do anyway. Note that force_ 
   collection  activates the  garbage collector  even  if it  has been 
   turned off with a call to disable_collection. 


   The  reader is  also  referred to  Section  3.8.13 of  the compiler 
   manual. 

