
                           Class(y) v2.0
                Copyright (c) 1992 Anton van Straaten

                   Conversion from Class(y) v1.0x
                =====================================

Introduction
============

If you have been using Class(y) v1.0x, this document will discuss the issues
involved in switching to v2.0.  In most cases, it is not necessary to make
any changes to your existing classes to use v2.0.  Class(y) v2.0 provides
three different "compatibility modes" to ease the transition from v1.0x.
These are as follows:

1.  Full v1.0x compatibility - this allows you to take existing v1.0x
    code and recompile it with very few, if any, changes.

2.  v1.0x syntax-only compatibility - allows you to use v2.0 in its native
    mode without completely converting all old-style syntax.

3.  v2.0 native mode - no concession is made to obsolete v1.0x syntaxes or
    behavior.

Note that all three modes can be mixed in the same application, so you can
switch to v2.0 native mode on a class-by-class basis if you wish.  However,
all v1.0x classes must be recompiled under v2.0.  Modules compiled with
v1.0x cannot be mixed with modules compiled under v2.0.

Use of each of the three modes is decsribed in more detail in the following
sections.

We suggest that you print out this document.  It is about 15 pages long and
is more manageable on paper.


Class(y) v1.0x Compatibility Mode
---------------------------------

To compile v1.0x classes with v2.0 without changes, you must specify that
v1.0x compatibility mode should be used.  The easiest way to do this is
to use the following statement:

    #include "classy1.ch"

at the beginning of each class module, instead of including "class(y).ch".
This should allow your code to recompile without changes.  If you don't want
to change all your #include statements, see the section entitled "New
Header Arrangement" for alternative ways of selecting the compatibility
mode.

The only change which may affect code compiled in compatibility mode is if
any of your classes define a method called 'init()'.  If any of your classes
define a method named init(), you will need to change that method name or
otherwise modify your code.  For more information, see the section entitled
"New() and Init()".


V1.0x Syntax Compatibility Mode
-------------------------------

This mode allows you to compile 2.0 classes in native mode, but still
supports all v1.0x command syntaxes.  The syntax compatibility mode can be
enabled with a #define statement prior to including "class(y).ch":

    #define CSY2C
    #include "class(y).ch"

See the section entitled "Converting to v1.0x Syntax Compatibility Mode" for
information about what changes may be required in your code to use this mode.


V2.0 Native Mode
----------------

This mode will be used by default when you use the statement:

    #include "class(y).ch"

Alternatively, if you set a different default in CLASS(Y).CH (see the
section "New Header Arrangement"), you may wish to use:

    #include "classy2.ch"

which will also enable 2.0 native mode but will not be affected by changes
to the default mode in CLASS(Y).CH.

Using native mode involves changing any use of obsolete commands such
as INSTVAR and CLASSVAR to their 2.0 equivalents (VAR and CLASS VAR, in
this case).  Also, native mode behaves differently in some areas.  See the
section "Converting to 2.0 Native Mode" for more information.


New() and Init()
================

When you create an object by sending a new() message to a class, two
separate but related operations take place.  First, a new, empty object
of the correct class is created.  Second, the object is initialized.
In v1.0x, the 'new()' message was used for both of these operations.
First, the new() message was sent to the class, which would invoke an
internal Class(y) method which created a new object.  This internal method
would then forward the new() message, with all parameters, to the newly
created object.  This would invoke the specific new() method which was
defined for that class.

However, using the new() message for both creating and initializing objects
leads to problems in some circumstances, especially when using metaclasses,
which are a key component of the architecture of Class(y) v2.0.

For this reason, the name of the message used to initialize an object
was changed to 'init()'.  You still send the 'new()' message to a class
to create an object, which invokes an internal Class(y) method, but instead
of sending 'new()' to the new object Class(y) sends 'init()' to it, with
all the parameters that were supplied to 'new()'.

In practice, this means that code such as:

    o := Box():new(...)

does _not_ need to be changed.  However, inside the class definition,
CONSTRUCTOR methods named 'new' need to be changed to 'init'.

If you use v1.0x compatibility mode, the definition of the CONSTRUCTOR
command will do this for you, so you will not usually need to make any
changes.

The only need for a change would be if you already have a method named
'init' in the class.  If you do, you will need to change its name and
change any calls to it accordingly.

Note: Some people have used a method named 'init' as a CLASS METHOD, to
initialize the class variables in a class.  In this case, the best solution
may be to rename the method to 'initClass'.  A method named 'initClass'
will automatically be invoked by Class(y) when a class has been created.

See "Eliminating the CONSTRUCTOR command" for more information about the
use of the 'init()' method.


Converting to v1.0x Syntax Compatibility Mode
=============================================

The syntax-only compatibility mode, which corresponds to 2.0's native mode
but with v1.0x syntax still supported, should help you to make the
transition to 2.0's native mode gradually.  The syntax-only compatibility
mode supports all v1.0x syntax (examples: INSTVAR, CLASSVAR, CONSTRUCTOR),
but does not emulate the following 1.0x behaviors:

o   Class variables are not automatically shared amongst subclasses.
    Instead, each class has its own copy of its class variables, including
    inherited ones.  Shared class variables can still be implemented using
    the new SHARED clause in the CLASS VAR command, as follows:

        CLASS VAR <names,...> SHARED

    This change may or may not affect you, depending on how you have used
    class variables.  Classes which have no subclasses will obviously not
    be affected.


o   Class messages cannot be sent to ordinary instances, only to class
    objects.  This means that to invoke a class method or class variable
    via an ordinary instance, you must use the 'class' message, as follows:

        obj:class:<message>

    whereas v1.0x would allow you to use obj:<message> directly.  In v2.0
    native mode, the v1.0x behavior can be achieved selectively, by
    delegating messages to the class:

        CLASS VAR <names,...>
        CLASS METHOD <names,...>
        MESSAGE <names,...> TO CLASS <className>
        VAR <names,...> TO CLASS <className>

    Using "MESSAGE...TO CLASS" and "VAR...TO CLASS", when the specified
    messages are sent to ordinary objects, they will be delegated to the
    object's class, simulating the direct access that v1.0x provided
    automatically.

    Note: at present, <className> in the "MESSAGE...TO CLASS" command must
    *always* be the name of the class currently being defined.  Other
    options will be available in future versions.

    This change may not affect you if you do not use class messages,
    or if you always send them to a class object using either a class
    function (eg. Customer():nCount), or the 'class' message as shown
    above.

o   The operation of the INIT CLASS: command conforms to 2.0 native
    behavior: you cannot access protected or hidden messages directly
    in the INIT CLASS: section.  Instead, you must invoke an exported
    method in that class to perform such access.  If you define a class
    method called initClass, it will be invoked automatically, doing
    away with the need for the INIT CLASS: command in most situations.

    Code which doesn't use the INIT CLASS: command, or only uses INIT
    CLASS: with exported methods and variables, will not be affected by
    this change.

o   The 'new' method is not automatically declared for each class.  This
    change is likely to affect everyone, especially since the default
    initializer name 'new' has been changed to 'init'.  There are a number
    of ways this change could affect you:

    *   At the very least, any class which contains a 'new' method (which
        in v1.0x should be almost every class) should include the following
        statement in the class declaration:

            METHOD init

        Although v1.0x did not require you to declare the 'new' method in
        your class declarations, some people did so anyway.  If you are one
        of those, any declarations similar to the following:

            METHOD new CONSTRUCTOR

        must be removed (ie. they are replaced by the "METHOD init"
        declaration).

    *   If you have defined the actual code for any of the 'new' methods in
        your classes without using the CONSTRUCTOR command, you will need
        to change the name of the 'new' method to 'init'.

        If you always use the CONSTRUCTOR command, you do not need to make
        this change to use the v1.0x syntax-only compatibility mode.  You
        will need to make this change to use v2.0 native mode.

        Here are a couple of generalized examples of a 'new' method
        declared without the CONSTRUCTOR command.  They are declared as
        ordinary METHODs (not METHOD PROCEDUREs) to conform with the new
        conventions (see "Returning self").

            METHOD new( ... ), ( ... )        // beta 3 syntax
                // code for the 'new' method

        or:

            METHOD new( ... )
                ::super:new( ... )          // explicit superclass initialization

        These should be changed to:

            METHOD init( ... ), ( ... )

        or:

            METHOD init( ... )
                ::super:init( ... )

        If you have used the CONSTRUCTOR command, these translations are
        done for you automatically, *unless* you have explicitly specified
        the name of the superclass constructor, as follows:

            CONSTRUCTOR new( ... ), new( ... )

        This should either be changed to:

            CONSTRUCTOR new( ... ), ( ... )

        or, preferably, to the 2.0 native syntax:

            METHOD init( ... ), ( ... )


Converting to v2.0 Native Mode
==============================

To convert to v2.0 native mode, all of the points discussed in the previous
section apply, with the addition that obsolete commands are no longer
supported.

The affected commands are:

    v1.0x command           v2.0 equivalent
    -------------           ---------------
    CONSTRUCTOR             METHOD <name>(...), (...)
    INSTVAR                 VAR
    CLASSVAR                CLASS VAR
    LOCAL:                  HIDDEN:
    PRIVATE:                HIDDEN:
    METHOD...=              MESSAGE...METHOD
    INIT CLASS:             Not required; can send exported messages
                            to class object (self) inside class function.



                           ------------------


               2.0 Features & Other Important Information
               ==========================================

Overview
========

As you might expect, Class(y) v2.0 provides many features not found in
v1.07.  But a list of features by itself can become a liability, if the
features are not well integrated and fitted properly into an overall
framework.  dBASE IV provides a good example of a feature list which has
outgrown its architecture.

To avoid such terminal "featuritis", a major goal in designing the
architecture of Class(y) v2.0 was to achieve a powerful and extensible
system with an open architecture.  Class(y) v2.0 meets this goal, with a
very open architecture which takes full advantage of object technology, and
is capable of being extended and interfaced to in well-defined ways.

The architecture of Class(y) v2.0 is based on classes.  For example, the
'Class' class is central to the system - all classes are an instance of
this class or its subclasses.  The 'Object' class is another key component.
Most classes ultimately inherit from the Object class, which ensures that
objects will respond to standard messages such as 'className'.

This class-based architecture makes Class(y) v2.0 very powerful, providing
a stable base for further enhancements, and simplifying and encouraging the
development of supporting tools, some of which are currently under
development by ObjecTech and other vendors.

But power is useless unless it can be harnessed, so another major goal was
to ensure that none of the underlying complexity shows through during
normal application development.  This goal was also achieved, so that the
development of ordinary classes in v2.0 is no more complex than it was in
v1.0x, and in fact in some respects has been simplified.

Much of this document focuses on the differences between v1.0x and v2.0.
Don't be put off by this - on the surface, the differences are not that
great.  Version 2.0 provides almost 100% compatibility with v1.0x.

Many of the differences relate to syntax - to cut down on header file
overhead, not to mention conceptual overhead, some of the alternative
syntaxes that have evolved since Class(y) was initially released are being
phased out.  This was discussed in the Class(y) Norton Guide for v1.0x.
The 2.0 "native" syntax is essentially an enhanced version of the commands
described in that Guide.  This means that commands such as INSTVAR are
considered obsolete and are only provided, in a separate header file, to
maintain backward compatibility.

The major differences in behavior between v1.0x and v2.0, from a compatibility
perspective, are summarized in the section "Behavior: v1.0x vs v2.0"


New Features
============

The major new features provided by v2.0 are:

    Feature                         Discussed in Norton Guide section
    ----------------------------    ---------------------------------
*   Type checking of
    instance variables              Commands: VAR
*   Automatic message delegation    Commands: MESSAGE...[IS...] TO
*   Scalar classes                  Usage: Advanced Topics: Scalar Classes
*   Message synonyms                Commands: MESSAGE...IS [...IN]
*   Enhanced error system           Usage: Advanced Topics: Error System
*   Enhanced object inspector       Usage: Debugging: Enhanced Object Inspector
*   Multiple inheritance            Usage: Advanced Topics: Multiple Inheritance
*   Metaclasses                     Usage: Advanced Topics: Metaclasses
                                    (also see TABLE example for metaclass use)


New Header Arrangement
======================

The Class(y) headers have been arranged with three goals in mind:

*   Providing an easy transition from v1.0x to v2.0

*   Minimizing compiler memory use

*   Ensuring, as far as possible, that future versions of 2.x will
    be able to coexist with modules compiled with 2.0.

Even though the headers have been minimized as much as possible, modules that
include other large headers in addition to the Class(y) headers may cause
problems.  These problems usually take the form of "Memory Overbooked"
messages when compiling such modules.  Running the compiler with limited
memory available, such as from inside some make utilities, can contribute
to the problem.  The best way to solve these problems is to modify affected
modules to use v2.0 native mode, so that the v1.0x compatibility header
files CLASSY1.CH and CSY1SNTX.CH are not included.

There are now six headers which should be available to the compiler, ie.
in one of the directories in the INCLUDE path, or in the current directory.
The necessary headers are:

    CLASS(Y).CH
    CLASSY2.CH
    CLASSY1.CH
    CSY1SNTX.CH
    NEWCLASS.CH
    ENDCLASS.CH

The only header file which is usually used directly is CLASS(Y).CH, and
possibly CLASSY1.CH or CLASSY2.CH depending on which mode is used.  The
others are included automatically as necessary.

By default, if you include CLASS(Y).CH in a class .PRG as usual, the system
is set up to compile 2.0-style classes.  It will NOT compile v1.0x classes
unless you tell it to do so.  There are four ways of enabling full v1.0x
compatibility:


1.  Define the manifest constant CSY1 prior to including CLASS(Y).CH, eg:

        #define CSY1
        #include "class(y).ch"

    This documents that the class is a v1.0x class, but will still work
    if you wish to be able to compiled your classes under both versions,
    since v1.0x will ignore the manifest constant.  However, it does
    require that you make this change in all v1.0x classes.


2.  Use:            #include "classy1.ch"

    instead of:     #include "class(y).ch"

    This also documents which version the class will work with, but
    modules changed like this will not compile directly under v1.0x.


3.  Define the manifest constant CSY1 from the Clipper command line:

        CLIPPER <prgName> /dCSY1

    This may be useful in makefiles or batch files, but the class .PRGs
    will contain no explicit Class(y) version indication.  On the other
    hand, you do not need to make any changes to your source code.


4.  Modify CLASS(Y).CH by uncommenting line 19, which defines CSY1.  This
    means that classes will be compiled in v1.0x compatibility mode by
    default.  However, you will then need to explicitly specify when you
    wish to compile classes in 2.0 mode, either by defining the manifest
    constant CSY2 or by including "classy2.ch".

    Modifying CLASS(Y).CH is the least desirable alternative, but it does
    allow you to recompile existing v1.0x libraries and applications with
    minimal changes.  A possible compromise is to copy CLASS(Y).CH (which
    is now just a 36-line shell) into the same directory as a v1.0x system,
    and modify the copied header.  You can then compile the v1.0x system
    without changes, but elsewhere compilation will still default to the
    v2.0 native mode.  But if you do this, don't forget that the modified
    file is there!


Eliminating the CONSTRUCTOR command
===================================

The CONSTRUCTOR command in v1.0x began the definition of what was referred
to as a constructor method.  Strictly speaking, this was a slightly
innacurate use of the term 'constructor'.  Booch's glossary has a succinct
definition of a constructor: "an operation that creates an object and/or
initializes its state".  The method which was defined using the CONSTRUCTOR
command in v1.0x was only responsible for the latter part - initializing
the state of the newly created object.  Creating the object and initializing
it are actually two distinct operations, and it is sometimes necessary to
separate these operations, especially in system-level programming (eg. when
loading an object from disk).

Class(y) 2.0 therefore decouples the constructor from the initializer more
clearly than was the case in v1.0x.  In practice, it should make very
little difference to the way Class(y) code is written.

One way in which the change is very obvious, though, is that the name of
the default initializer method has been changed from 'new' to 'init'.  This
does not change the way you create new objects - the 'new' message still
gets sent to a class object, where it invokes a default constructor which
in turn invokes the initializer, now called 'init'.  This does change class
definitions slightly, as we will see shortly.

Implementation Note: giving the initializer a different name from the
constructor was essential for consistency at the metaclass level.  Having
both the constructor and the initializer share the same name led to
problems which forced the use of alternate constructors where it would not
otherwise be necessary.  In addition, demonstrations of CA-Visual Objects
for Clipper ("Aspen") at the November 1992 CA-TechniCon in New York
indicate that both CA-Visual Objects and Clipper 5.x are likely to use a
similarly-named initializer.

Let's look at a small example of how the change affects code.  First,
written the 1.0x way:

    LOCAL oAcc := CredCardAccount():new( cName, nBal )
    // ...

    CREATE CLASS CredCardAccount FROM Account
        VAR creditLimit
    EXPORT:
        // ...
    END CLASS

    CONSTRUCTOR new( cName, nBal, nCreditLimit ), ( cName, nBal )
        ::creditLimit := nCreditLimit
    RETURN

    // ...

This code will still work fine if you use either of the v1.0x compatibility
modes that v2.0 provides.

Now we'll rewrite this the new way.  We only have to do two things:

1.  Declare the 'init' method (using "METHOD init") in the class declaration.
    In v1.0x there was no need to declare the 'new' method, but this led to
    problems when no 'new' method was required.  Under 2.0, you must
    declare the initializer method if there is one, but there does not have
    to be one.  If you have been declaring your 'new' methods anyway, using
    something like "METHOD new CONSTRUCTOR", you must change these
    definitions to "METHOD init".  The CONSTRUCTOR clause is no longer
    needed, and should not be included, unless you are declaring alternate
    constructors other than 'init'.

2.  Change "CONSTRUCTOR new" in the method definition (the actual code) to
    "METHOD init".  In most cases, this is all you need to do; but there is
    an exception which we will look at after we have seen the modified
    code.

    LOCAL oAcc := CredCardAccount():new( cName, nBal )
    // ...


    CREATE CLASS CredCardAccount FROM Account
        VAR creditLimit
    EXPORT:
        METHOD init     // declare initializer method
        // ...
    END CLASS

    // define initializer method
    METHOD init( cName, nBal, nCreditLimit ), ( cName, nBal )
        ::creditLimit := nCreditLimit
    RETURN self

    // ...

The first line of code above has not changed.  As mentioned earlier, new
objects are still created by sending the 'new' message to a class object.
This (usually) invokes the 'new' method defined in the Class class, which
creates a new, empty object and initializes it by sending the 'init'
message to it.

Notice that the "METHOD init" statement still has the second set of
parameters which are passed up to the superclass initializer.  Class(y) 2.0
extends the METHOD [PROCEDURE|FUNCTION] command to allow this.  See the
next section details of this command.

In most cases, these will be the only changes you will need to make.
However, there is one situation which could require further code
modification: if the 'new' message is ever sent to ordinary objects,
rather than class objects.  For example, it was possible in v1.0x (and is
still possible in v2.0, using 'init') to re-initialize an existing object
by sending it the 'new' message, as in the following example:

    LOCAL o := Box():new( 12, 40, 18, 55 )      // create new Box
    o:draw()                                    // do something with it
    o:new( 5, 10, 15, 30 )              // reinitialize the existing box
    o:draw()

In the third line of code, the 'new' message is sent to a Box object.  This
executes the 'new' method, reinitializing the box.  A new Box is not
created, because actual creation of objects only occurs when the 'new'
message is sent to a class object.

If you have taken advantage of this behavior, you will have to change
occurences of 'new' to 'init' wherever 'new' has been sent to an ordinary
object.  IMPORTANT: You will need to make this change even if you are using
the v1.0x compatibility mode.

The third line above then becomes:

    o:init( 5, 10, 15, 30 )

Notice that the first line doesn't change - 'new' is still used to create
new objects.


The extended METHOD command
===========================

As discussed in the previous sections, the CONSTRUCTOR command was
really used to define initializers.  Rather than create a new command
called something like INITIALIZER, the METHOD [PROCEDURE | FUNCTION]
command was extended to optionally provide similar functionality to
the CONSTRUCTOR command.  The functionality in question is the ability to
automatically invoke a superclass method, usually of the same name, prior
to executing the body of the initializer method.

For example, the command:

    CONSTRUCTOR new( a, b, c ), ( b, c+1 )

can now be replaced by:

    METHOD init( a, b, c ), ( b, c+1 )

Notice the change of the method name from 'new' to 'init'.

The second parameter list after the comma causes the superclass method
of the same name to be invoked with those parameters.  A different method
name can be specified if necessary.

One difference between the CONSTRUCTOR command and the extended METHOD
command is that CONSTRUCTOR would always invoke a superclass method, even
if none was specified.  In some cases, this was unnecessary, especially
when there was no superclass.  However, very often, it was necessary to
execute the superclass' initializer method.  In these cases, the command:

    CONSTRUCTOR new( <params,...> )

must be replaced with:

    METHOD init( <params,...>), ()

The trailing comma and empty parenthesis pair causes the init() method in
the superclass to be invoked.

It is worthwhile getting into the habit of invoking the superclass
initializer like this even when it is not strictly necessary (eg. when a
class has no superclass).  This will work in all cases, and handles
situations in which the superclass has an initializer which does something
meaningful but does not take parameters.  On the other hand, if a
superclass initializer is _not_ called when it should be, bugs will occur.

The extended form of the METHOD command can be used for any method, not
just initializers.  It can be useful when defining an initClass() method
to initialize class objects.  The initClass() method operates on a class
object and serves as a kind of user-defined initializer for classes.  As
with init(), if you define an initClass() method for a class, it is often
necessary to invoke initClass() in the superclass.  The extended METHOD
command provides a convenient way to do this, consistent with the way it is
done for init().

In special situations, the superclass initializer can be invoked
explicitly.  This can be necessary, for example, in a class which makes use
of DEFERRED or overridden methods, in which a method in the subclass is
invoked from a superclass initializer.  The subclass method might expect
that its instance variables are initialized - but by using the extended
METHOD command, the superclass initializer will have been invoked before
executing the current class initializer - so this will not be the
case.  To resolve this, an initializer such as the following can be
written:

    METHOD init( p1, p2, p3 )
        ::iv1 := p1 + p2
        ::super:init(p3)
        ...
    RETURN self

In this case, the extended METHOD command has not been used, since the
superclass initializer has been invoked explicitly instead.


Behavior: v1.0x vs v2.0
=======================

As supplied, Class(y) v2.0 will not compile code written under v1.0x unless
it is told to do so.  See the notes at the beginning of this document on
this subject.

In its native mode, Class(y) v2.0 is not 100% compatible with 1.0x.  The
areas of incompatibility and the ways they have been addressed are
described below.  In most cases, compatibility has been achieved by
redefining native 2.0 commands in the header file CLASSY1.CH.  CLASSY1.CH
is included automatically by CLASS(Y).CH when the v1.0x compatibility mode
is enabled.


i.  Class messages sent to instances
------------------------------------

An inevitable result of v2.0's class-based architecture is that class
variables and methods can no longer be accessed directly by sending
messages to instances of the class.  This is in contrast to 1.0x, where
class messages could be sent either to instances or their classes, with
equal success.

Separation between classes and their instances is much clearer under 2.0;
they are only linked by the 'class' method, which when sent to an instance
will return the class object.  In 2.0 native mode, to send a message to a
class via an instance, you must use the 'class' message, as follows:

    obj:class:<message>

When v1.0x compatibility mode is enabled, CLASSY1.CH causes class variables
and class messages to be automatically delegated to the class object, using
commands of the form:

    MESSAGE <msg> TO CLASS <className>

This will cause class messages sent to an instance to be rerouted to their
class, ensuring compatibility with v1.0x.


ii.  Shared class variables
---------------------------

In v1.0x, only one copy of each class variable existed throughout the
system.  All subclasses of a class containing a class variable shared the same
variable with their superclass; changing the value of that variable from
any class caused all other classes to see the same change in that variable.

Again, it is an inevitable consequence of the v2.0 metaclass architecture
that each class will have its own copy of each class variable, rather than
sharing them with the class in which they were defined.  This is consistent
with the way ordinary instances inherit variables.  Each instance has its
own copy of all variables defined by all its superclasses.  Since in the
metaclass system, classes are instances too, any other behavior requires
special support.

To achieve backward compatibility, support was built into the Class(y)
kernel.  The CLASS VAR command in CLASSY1.CH causes variables to be created
that will behave in the same way as they would have under 1.0x.

In addition, v2.0 native mode supports shared class variables via the
SHARED clause in the CLASS VAR command, eg:

    CLASS VAR <names,...> SHARED


iii.  The INIT CLASS: command
-----------------------------

From v1.05 onwards, this command allowed initialization of a class
immediately after it had been created.  After this command had been
executed, the system behaved as though a class method were being executed,
allowing access to hidden and protected variables and methods.

Version 2.0 no longer requires the INIT CLASS: command.  Messages can be
sent to the class object (self) inside a class function at any time, although
this is usually done immediately prior to the END CLASS command.

However, protected and hidden messages can no longer be sent to the class
object directly, since a class function is not a class method and thus
cannot access protected elements.

Instead, to access hidden or protected elements of the class, an exported
class method should be invoked.  Inside such a method, as in any class
method, full access to hidden and protected elements will be permitted.  A
default method called 'initClass' has been provided for - if a class method
called 'initClass' is implemented, it will automatically be executed when
the class is created.

To achieve backward compatibility with v1.0x, the INIT CLASS: command
defined in CLASSY1.CH actually defines an 'initClass' method to contain the
specified initialization code, which is automatically invoked on class
creation.


iv.  Declaring the initializer method: 'new' and 'init'
-------------------------------------------------------

Due to the internal design of v1.0x, every class had to respond to the
'new' message.  To achieve this, the command "METHOD new CONSTRUCTOR" was
included in the CREATE CLASS command in the v1.0x CLASS(Y).CH.  An
equivalent command has been included in CLASSY1.CH for v2.0.

However, in the 2.0 native mode, not only is the 'new' method not
automatically declared, but its name has been changed to 'init'.
(Note: you still create objects using 'new', but during this process,
the initializer method 'init' is automatically invoked).

In 2.0 native mode, if an init() method exists in a class, it must be
explicitly declared in the class declaration, as follows:

    METHOD init

It is not necessary to include the 'CONSTRUCTOR' clause, as in
'METHOD init CONSTRUCTOR' - under 2.0, this clause is not usually
necessary. This is explained in more detail in the section on
Instantiation.

One side effect of this change is that constructors which do nothing but
pass their parameters up to their superclass, such as the one shown below,
are no longer necessary:

    CONSTRUCTOR new(p1, p2, p3), (p1, p2, p3)
    RETURN

Instead, no 'init' or 'new' method should be declared or defined for such a
class; the superclass initializer 'init' will automatically be invoked when
instances of the class are created.

See also: Instantiation, Eliminating the Constructor Command


v.  METHOD m DEFERRED | NULL
----------------------------

This syntax is considered obsolete in 2.0.  For compatibility with v1.0x,
it has been defined in CLASSY1.CH more or less as follows:

#xcommand   METHOD <message1> <clause: DEFERRED, NULL>  ;
                =>                                      ;
                MESSAGE <message1> IS <clause>

Here are examples of the new format:

    MESSAGE msg1 IS DEFERRED
    MESSAGE msg2 IS NULL

This makes use of the message synonym capability of v2.0 to map the
specified message onto standard methods defined in the Object class.  The
Object class defines the methods 'NULL' and 'DEFERRED', and these will be
invoked accordingly when the specified message is sent.  Note that deferred
messages declared in this way will generate an error if invoked, since that
is what the 'DEFERRED' method in class Object does.  This helps
implementors of subclass to find problems which might otherwise arise from
non-implementation of deferred methods.


vi.  The CONSTRUCTOR command
----------------------------

This is now considered obsolete.  It should be replaced by a METHOD
command of the appropriate form.  Note that the METHOD command has slightly
stricter syntax requirements than the CONSTRUCTOR command.  For example,
you cannot leave out the name of the method being defined, whereas with
CONSTRUCTOR, it used to default to 'new'.  See the section entitled
"Eliminating the CONSTRUCTOR Command" for more information.

A specific cases to watch out for when converting is when the CONSTRUCTOR
command is used without a second set of parameters.  In this case, an empty
second parameter list must be explicitly provided for the METHOD command.
In some cases, this may not be necessary; but when in doubt, provide it.
Examples:

1.0x command                        2.0 command
----------------------------------------------------------------------------
CONSTRUCTOR                         METHOD PROCEDURE init, ()
CONSTRUCTOR new                             <as above>
CONSTRUCTOR ( [<params,...>] )      METHOD PROCEDURE init( <params,...> ), ()
CONSTRUCTOR new( [<params,...>] )           <as above>



vii.  Change in PROTECTED READONLY scoping enforcement
------------------------------------------------------

Although I have not investigated this extensively, it seems that variables
could be declared PROTECTED and READONLY in v1.0x, but still be assigned to
in subclass methods.  The READONLY clause was therefore having no effect,
since the same behavior would be achieved without it.  Class(y) v2.0
enforces the READONLY restriction on such variables, preventing assignment
to them in subclasses.

If this affects you, you have one of two choices: to remove the READONLY
clause, because you want to be able to assign to the variable in a
subclass; or to stop trying to assign to the variable in a subclass.

Since this is considered a bug in v1.0x, no support for the original
behavior is provided.


Performance & Size
==================

All modules in v2.0 can be overlaid with the exception of _CYCLASS.OBJ and
CSYXSEND.OBJ.  When overlaid like this and linked in to an application,
Class(y) 2.0 occupies space in the root similar to that occupied by v1.0x.

If used in compatibility mode, v2.0 may execute marginally slower in some
cases than v1.0x, mainly due to the way shared class variables have been
implemented.  However, running in native mode, v2.0 should be slightly
faster than v1.0x, since the consistency of the new architecture has
reduced the code in the message lookup module and improved the logic in
some areas.

Class creation is slightly slower than it was under v1.0x; however, this
only happens once per class during each execution of an application, and
thus should not be significant.  Performance in this area should be
improved in future releases (ie. in v2.x).

Class creation for multiply inherited classes is somewhat slower than for
singly inherited classes.  This may be improved in future releases.

                            < end >
