home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / sampl254.zip / gcc2 / samples / sample5 / main.m < prev    next >
Text File  |  1993-11-07  |  8KB  |  210 lines

  1. // main.m - comp.lang.objective-c simple sample Objective-C program
  2.  
  3. // This is a comment.  Everything to the right of a double slash
  4. // is ignored.
  5.  
  6. /*
  7.  * This is too.  Objective-C is a superset of ANSI C,
  8.  * so you don't lose any of your favorite features.
  9.  */
  10.  
  11. // Classes are the one real extension which Objective C adds to
  12. // ANSI C.  A class is a description of a collection of data, like
  13. // a C structure, and the methods by which that data may be accessed
  14. // or manipulated.  Instances of a class are called objects, and
  15. // methods are invoked by sending messages to either the class itself,
  16. // to produce objects, or to those objects.  The recipient of a message
  17. // is called a "receiver".  The form of a message is:
  18. //
  19. //    [receiver method andMaybeSomeArguments]
  20. //
  21. // the receiver and method components are mandatory, as are 
  22.  
  23. // the square brackets surrounding the message.  Additional
  24. // arguments may or may not be present, depending upon the
  25. // method definition.  Messages may appear anywhere a statement
  26. // is allowed in C.
  27.  
  28. // The first thing we do is bring in some include files, as in
  29. // C.  However, we'll use the "import" statement which guarantees
  30. // that the file isn't included more than once.
  31.  
  32. #import <stdio.h>
  33. #import <objc/Object.h>
  34. #import "Queue.h"
  35. #import "Stack.h"
  36.  
  37. // That brought in class definitions for Objects, Queues, and
  38. // Stacks.  The Object class is the basis for all other classes,
  39. // which is why it gets brought in first.  It provides basic functional
  40. // behavior which is inherited by all derived classes.  All user
  41. // created classes should have Object somewhere in their ancestry.
  42.  
  43. // Queue and Stack are classes of our own construction,
  44. // and provide FIFO and LIFO storage capabilities, respectively.
  45. // I'm not going to go into implementation details here.  It's
  46. // irrelevant how they work, all that is important is that they
  47. // both respond to 'put:' and 'get'.  If you want to inspect them,
  48. // look into the Queue.m, Stack.m, Queue.h and Stack.h files.
  49.  
  50. // A simple Class definition follows.  It inherits
  51. // directly from the base class "Object".  This gives
  52. // it lots of nice properties, not the least of which
  53. // is the ability to be referenced by any pointer of the
  54. // generic object type "id".  All objects can be pointed
  55. // to by any id variable, and the default return type from
  56. // methods is id.  This allows messages to be embedded in
  57. // other messages, either as receivers or arguments.
  58.  
  59. // An Int object allocates space for a single integer.
  60. // The "report" message causes it to report its value.
  61. // Everything between the @implementation and the @end
  62. // is part of the class definition.
  63.  
  64. // Note - It is *highly* unusual to have a class implementation
  65. // in your main program.  Since the object is fully defined before
  66. // it gets used, no interface description is required.  There is
  67. // nothing illegal about doing things this way, but it is so
  68. // unusual that the compiler will produce a warning for this class.
  69. // We have included the Int class implementation here solely for
  70. // expository purposes.
  71.  
  72. @interface Int: Object    // Int is derived from Object
  73. {
  74.     int value;        // This is the data portion.  Like a struct.
  75. }
  76.  
  77. - init:(int)i;
  78.  
  79. - report;
  80.  
  81. @end
  82.  
  83. // The following are the method definitions.  A "+" prefix means
  84. // it is a factory method, i.e., how to manufacture instances of
  85. // the class.  The body of the method is between braces, like a C
  86. // function.
  87.  
  88. // This class doesn't define any factory methods.  It relies on the
  89. // +alloc method defined in class Object.  For examples of factory
  90. // methods, look at the +new method defined in the Stack or
  91. // Queue implementations.
  92.  
  93. // Self is a special variable, which refers to the object currently
  94. // being manipulated.  Super refers to the parent class of self.
  95. // The following method asks the parent class (Object) to hand us a
  96. // new instance, which becomes self.  Then we update the instance
  97. // variables and return a pointer to the new object.
  98.  
  99. // It is standard for methods that do not need to return any
  100. // special value to instead return self.  This allows for a 
  101. // nested syntax of method calls.
  102.  
  103. // The "-" in front of init means that it's an instance method,
  104. // i.e., something a particular object should respond to.
  105.  
  106. @implementation Int
  107.  
  108. - init: (int) i        // This method will initialize a new Int 
  109. {
  110.   [super init];        // In case the parent class is doing
  111.               // something special in its init...
  112.   value = i;
  113.   return self;
  114. }
  115.  
  116. - report
  117. {
  118.   printf("%4d", value);
  119.   return self;
  120. }
  121.  
  122. @end
  123.  
  124. // We have implemented Float and Char classes more traditionally, using
  125. // separate files for the interface (.h) and implementation (.m).
  126. // The Float and Char objects are like the Int object, but with the
  127. // obvious difference that they work with floats and characters.
  128. // We include the interface definitions at this point.
  129.  
  130. #import "Float.h"
  131. #import "Char.h"
  132.  
  133. // If you inspect those files, note polymorphism -- methods have same
  134. // names as in the Int class.
  135.  
  136. int main(void)
  137. {
  138.     // First we create instances of "Stack" and "Queue" data structures
  139.  
  140.     id queue = [Queue new];    // +new is an older convention for
  141.     id stack = [Stack new];    // allocation & initialization.
  142.                     // [[x alloc] init] is the preferred
  143.                 // way to do this now.
  144.     int i;
  145.     int reply;
  146.     
  147.     fprintf(stderr, "Include the Char class in the demo? (y/n): ");
  148.     reply = getchar();    // no error checking...
  149.  
  150.     for (i = 5; i > -6; --i)
  151.     {
  152.     // Depending on which version of the demo we're running,
  153.     // we alternate putting Int's and Floats onto the queue and
  154.     // stack, or Int's, Float's, and Char's.
  155.  
  156.     if (reply == 'y')
  157.     {
  158.         // If "i" is odd we put an Int on the queue and a Char on
  159.         // the stack.  If "i" is even we put an Char on the queue
  160.         // and a Float on the stack.
  161.  
  162.         // Since there is more than one method "init", and
  163.         // Objective-C uses run-time binding, the compiler doesn't
  164.         // know what the type of the object returned by alloc.
  165.         // We disambiguate with an explicit C-style cast to make
  166.         // sure the appropriate "init" is invoked. 
  167.  
  168.             [queue put: (i & 1) ?
  169.                 [(Int*)[Int alloc] init: i] :
  170.           [(Char*)[Char alloc] init: 'm'+i]];
  171.             [stack put: (i & 1) ?
  172.                 [(Char*)[Char alloc] init: 'm'+i] :
  173.           [(Float*)[Float alloc] init: i]];
  174.     }
  175.     else    // Note - garbage input will invoke the else clause.
  176.     {
  177.         // If "i" is odd we put an Int on the queue and a Float on
  178.         // the stack.  If "i" is even we put a Float on the queue
  179.         // and an Int on the stack.
  180.  
  181.             [queue put: (i & 1) ?
  182.                 [(Int*)[Int alloc] init: i] :
  183.           [(Float*)[Float alloc] init: i]];
  184.             [stack put: (i & 1) ?
  185.                 [(Float*)[Float alloc] init: i] :
  186.           [(Int*)[Int alloc] init: i]];
  187.     }
  188.     }
  189.  
  190.     while ([queue size] && [stack size])
  191.     {
  192.     // The following illustrates run-time binding.  Will report be
  193.     // invoked for a Float object or an Int object?  Did the user
  194.     // elect for Char objects at run time?  We don't know ahead
  195.     // of time, but with run-time binding and polymorphism
  196.     // it works properly.  The burden is on the class
  197.     // implementer rather than the class user.  
  198.  
  199.     // Note that the following lines remain unchanged, whether
  200.     // we are using the Char class or not.  The queue and stack
  201.     // hand us the next object, it reports itself regardless
  202.     // of its type, and then it frees itself.
  203.  
  204.     printf("queue:");    [[[queue get] report] free];
  205.     printf(", stack:");    [[[stack get] report] free];
  206.     putchar('\n');
  207.     }
  208.     return 0;
  209. }
  210.