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.