Fenestra User's Guide (appendix B) -- contents | previous | next


B An introduction to Pylon

Pylon is the foundation that is used to support to both the implementation of the main library and the communication with library clients when classes from the Eiffel standard kernel library are not sufficient.

A library client need not use this cluster for its own data structures. In this case, it is not necessary to study the full Pylon manual [pylon96] in order to know what is needed to use the few classes that are used in the interface of the GUI clusters. This section documents precisely this usage.

The Pylon classes which are used by the public interface of Fenestra are ordered lists, basic persistence and the date and time abstraction.

B.1 Lists

Pylon's lists are ordered but not sorted, that is any iteration will go through the items in a definite order. Therefore, the order changes only on request, such as when the list client adds, deletes or inserts elements, or orders a sorting operation.

Lists are accessed through the abstract class P_LIST which is a generic class whose generic parameter is the item type. Typical concrete implementations are linked lists, like P_LINKED_LIST or arrayed lists. If a client needs to create a list in the GUI library context, it is most likely to need an instance of P_LINKED_LIST.

An abbreviated version of the flat-short form of P_LIST with the features useful for this usage follows:

deferred class interface P_LIST [G]

indexing

    cluster: pylon, container;
    description: "Abstract list (traversable collection)";
    interface: abstract;

feature specification -- Duplication

    copy (other : like Current)
            -- GENERAL's copy.
            -- Time: O(other.count)
        require
            other_not_void : other /= void;
            conformance : other.conforms_to (Current);
        ensure
            result_is_equal : is_equal (other);

feature specification -- Comparison

    is_equal (other : like Current) : BOOLEAN
            -- GENERAL's equality relation (requires covariant arguments).
            -- Time: O(count)
        require
            other_not_void : other /= void;

    is_equal_list (other : P_LIST [G]) : BOOLEAN
            -- Compare two lists which can be of different dynamic type.
            -- Time: O(count)
        require
            valid : other /= void;

feature specification -- Conversion

    from_list (other : P_LIST [G])
            -- Convert from another list.
            -- Note: The previous contents of this list is deleted.
            -- Time: O(other.count)
        require
            valid : other /= void;
        ensure
            done : is_equal_list (other);
            keep_reference : -- keep copy of items.

    from_array (other : ARRAY [G])
            -- Convert from an ARRAY.
            -- Note: The previous contents of this list is deleted.
            -- Time: O(other.count)
        require
            valid : other /= void;
        ensure
            done : other.count = count;
            keep_reference : -- keep copy of items.

    from_iterable (it : P_ONEWAY_ITERATOR [G])
            -- Convert from a one way linear iterable container.
            -- Note: The previous contents of this list is deleted.
            -- Time: O("it.count")
        require
            valid : it /= void;
            initialised : it.outside;
        ensure
            keep_reference : -- keep copy of items.

    to_array : ARRAY [G]
            -- Convert list to ARRAY.
            -- Time: O(count)
        ensure
            done : is_empty = (Result = void);
            is_shallow_copy : -- new array, old items.

feature specification -- Concatenation

    append (other : P_LIST [G])
            -- Append other container to current.
            -- Time: O(other.count)
        require
            valid : other /= void;
        ensure
            keep_reference : -- keep copy of items.

    append_iterable (it : P_ONEWAY_ITERATOR [G])
            -- Append the items from a linear iterator.
            -- Time: O("it.count")
        require
            valid_iterator : it /= void;
            initialised : it.outside;
        ensure
            keep_reference : -- keep copy of items.

feature specification -- Iteration

    iterator : P_ITERATOR [G]
            -- Get a two-way iterator on this container.
        deferred
        ensure
            done : Result /= void;
            is_shallow_copy : -- Result /= previous Result

feature specification -- Iteration

    is_protected : BOOLEAN
            -- Is an iterator inside the data structure?

feature specification -- Status

    is_empty : BOOLEAN
            -- Is the container empty?

    is_readable : BOOLEAN
            -- Is the container currently readable?

    is_writable : BOOLEAN
            -- Is the structure writable?

feature specification -- Update 

    add (it : G)
            -- Add item to the container.
        require
            writable : is_writable;
        deferred
        ensure
            keep_reference : item = it;

    replace (it : G)
            -- Replace the current item.
        require
            writable : is_writable;
            not_empty : not is_empty;
        deferred
        ensure
            keep_reference : item = it;

    insert (it : G)
            -- Insert item before the current item.
        require
            writable : is_writable;
            not_empty : not is_empty;
        deferred
        ensure
            keep_reference : item = it;

    remove
            -- Remove the current item.
        require
            writable : is_writable;
            not_empty : not is_empty;
            unlocked : not is_locked;
        deferred

feature specification -- Status

    count : INTEGER
            -- Number of items in the container.
        deferred
        ensure
            positive : Result >= 0;

    item : G
            -- Current item.
        require
            readable : is_readable;
            not_empty : not is_empty;
        deferred

feature specification -- Update

    reset
            -- Remove all objects from the container.
        require
            writable : is_writable;
        deferred
        ensure
            done : is_empty;

invariant

    protection : is_protected = (not is_writable);
    empty : is_empty = (count = 0);

end interface -- class P_LIST

The procedures to_array and from_array are especially useful when used as a bridge from or to other data structure libraries.

In order to go through every item in a structure the iteration class P_ITERATOR is used. When a valid iterator is being used, the structure cannot be written to, and is_protected is true. The flat short form shows that any non-empty list always has a current item, although it is not used for iteration -- it does not normally change when iterators are manipulated as they have their own attribute for the currently traversed item.

A typical iteration is:

local
    list : P_LIST[STRING]
    it : P_ITERATOR[STRING] -- Iterator has same generic type as list.
do
    list := -- ... obtain a list of string

    from
        it := list.iterator
        it.first -- Enter (and protect) the container.
    variant
        it.forward_variant -- Iterator provides variant value.
    until
        it.outside -- Is iteration finished?
    loop
        io.put_string(it.item) -- Print current iterated item.
        io.put_new_line

        it.forth -- Step forward.
    end
end

When the iteration is finished -- is_outside is true -- the structure ceases to be protected, as long as no other iterator is inside the containers. It is possible to have several iterators on a single structure.

B.2 Basic persistence

The basic persistence has been introduced in the `Graphics' cluster where it is presented, section (see section 5.1). It allows to store an object into a string for later retrieval.

The class P_TEXT_OBJECT adds the function to_string and the procedure from_string to objects which inherit from it. Descendant of this class also have to effect two corresponding procedures object_to_string and object_from_string -- exported to the classification class PUBLIC_NONE. Both have an instance of P_TEXT_OBJECT_MANAGER as their parameter which allows to put and retrieve basic types have from and to the string. The manager class interface is very similar to usual Eiffel IO classes -- put_integer, put_string, for output and get_integer and last_integer type of pairs for input, in addition to the boolean in_success which allows the client to check that the value has been properly retrieved.

The benefits of this system is portability among Eiffel compilers and architectures. It is also completely independent of runtime object structures. For instance a rectangle can be saved as a pair of coordinates even if it is implemented as a single coordinate pair and width and height. The implementation of the rectangle can be changed later without the need of the external string representation to be altered.

To give a practical example, the string version of an object like a point, whose attribute values are 200 for x and 300 for y will look like:

"(INT:1)(INT:200)(INT:300)"

which is produced using the following code:

object_to_string(tm : P_TEXT_OBJECT_MANAGER) is
    do
        tm.put_integer(1) -- Placeholder for version.
        tm.put_integer(x)
        tm.put_integer(y)
    end

string_to_object(tm : P_TEXT_OBJECT_MANAGER) is
    local
        version : INTEGER
    do
        tm.get_integer    version := tm.last_integer
        tm.get_integer    x := tm.last_integer
        tm.get_integer    y := tm.last_integer

        if not (tm.in_success and then version = 1) then 
            make -- Default values.
        end
    end

This illustrates the general scheme: `(' <TYPE> `:' <CONTENT> `)'. Client applications should not interfere with it in any case, although it can be a useful thing to know for debugging. The content is properly encoded if it contains characters like a closing parenthesis. This enables using the string type to enclose compound objects -- a P_TEXT_OBJECT can have another P_TEXT_OBJECT as an attribute.

The first integer is the version number. It is not a part of the P_TEXT_OBJECT facility but is a convention followed by the GUI library to make future evolutions easier.

B.3 Date and time

The last foundation features used by the main library -- in the `System' cluster -- are date and time abstractions, which are missing from the standard library. The Pylon classes are used to represent the time and not to retrieve it which is a system dependent task left to a cluster closer to the operating system.

The main class used is P_DATE_TIME which itself uses P_TIME and P_DATE as clients. This class inherits from P_TEXT_OBJECT which was previously described. It is also a descendant of HASHABLE.

The creation procedure, make, does not take any parameters and initialises the default value. The date is set with set_date which takes year and month and day integer parameters in that order, and set_time which takes hour and minute and second integer values. Alternatively, set can be used to set them all at once. The date and time attributes are instances of P_DATE and P_TIME, with, respectively, integer attributes year, month, day and hour, minute, second. These classes can be manipulated directly when necessary.

The date and time class also handles the time zone. It is possible not to specify a time zone: the boolean value is_local is then set to true. The time zone is set using set_timezone_bias, specified in minutes (positive or negative depending on the side of UTC). The bias is zero for UTC (formerly known as GMT) and it has to be explicitly set -- otherwise the current instance is local time.

In addition, a few string representations are provided. The function to_iso and its synonym out return the time formatted according to the ISO 8601 standard, for instance ``18870726T140000''. A more readable variant is to_iso_long, e.g. ``1887-07-26 14:00:00''. The time zone information is added when the time is not local, as a bias in hours and minutes. A different alternative is the to_rfc format, ``26 Jul 1887'', introduced in the Internet e-mail standard RFC-822 -- the month names are always in English as RFC-822 specifies.

Various individual string representations for date and time can be obtained from the date and time attributes.