Loading ...
Sorry, an error occurred while loading the content.

like Current in STRING and ARRAY

Expand Messages
  • Alexander Kogtenkov
    It appears that the functions that return like Current can be implemented in at least two different ways: 1) clone (Current) 2) create Result.make_empty /
    Message 1 of 20 , Dec 19, 2001
    • 0 Attachment
      It appears that the functions that return "like Current"
      can be implemented in at least two different ways:
      1) clone (Current)
      2) create Result.make_empty / create Result.make (...)

      Provided that neither the functions that return "like Current"
      nor "copy" function are redefined, the result will be different
      for the two implementations:
      1) all the attributes of the result get their values from the
      current object
      2) all the attributes of the result are initialized by the creation
      procedure (make, make_empty, etc.) without any hint
      from the current object

      So, if the descendant relies on some additional attributes,
      there is no portable way to implement it without redefining
      all the "like Current" functions given the existing NICE
      standard. This would not be the case if the NICE standard
      explicitly specifies the way the result is obtained.

      Regards,
      Alexander Kogtenkov
      Object Tools, Moscow
    • Dominique Colnet
      ... Yes, because it _is_ like Current. ... But this would not be like Current ... or I am missing something. As a function Result, it seems to me that like
      Message 2 of 20 , Dec 19, 2001
      • 0 Attachment
        Alexander Kogtenkov writes:
        > It appears that the functions that return "like Current"
        > can be implemented in at least two different ways:
        > 1) clone (Current)
        > 2) create Result.make_empty / create Result.make (...)
        >
        > Provided that neither the functions that return "like Current"
        > nor "copy" function are redefined, the result will be different
        > for the two implementations:
        > 1) all the attributes of the result get their values from the
        > current object
        Yes, because it _is_ like Current.
        > 2) all the attributes of the result are initialized by the creation
        > procedure (make, make_empty, etc.) without any hint
        > from the current object
        But this would not be like Current ... or I am missing something.

        As a function Result, it seems to me that like Current does not raise
        any problem.

        Just my 2 centimes (of Franc),
        Best regards to all,

        --
        --------------------------------------------------------------
        Dominique.Colnet@... -- UHP (Nancy 1) -- INRIA Lorraine
        http://SmallEiffel.loria.fr -- The GNU Eiffel Compiler
        POST: Loria, B.P. 239,54506 Vandoeuvre les Nancy Cedex, FRANCE
        Voice:+33 0383593032 Mobile: +33 0665362381 Fax:+33 0383413079
      • Eric Bezault
        ... Why? The fact that it is like Current does not intrinsically mean that their attributes should have the same values. ... Why? like Current is a type,
        Message 3 of 20 , Dec 19, 2001
        • 0 Attachment
          Dominique Colnet wrote:
          >
          > Alexander Kogtenkov writes:
          > > It appears that the functions that return "like Current"
          > > can be implemented in at least two different ways:
          > > 1) clone (Current)
          > > 2) create Result.make_empty / create Result.make (...)
          > >
          > > Provided that neither the functions that return "like Current"
          > > nor "copy" function are redefined, the result will be different
          > > for the two implementations:
          > > 1) all the attributes of the result get their values from the
          > > current object
          > Yes, because it _is_ like Current.

          Why? The fact that it is "like Current" does not intrinsically
          mean that their attributes should have the same values.

          > > 2) all the attributes of the result are initialized by the creation
          > > procedure (make, make_empty, etc.) without any hint
          > > from the current object
          > But this would not be like Current ...

          Why? "like Current" is a type, it says nothing about the
          values of the attributes of that type.

          --
          Eric Bezault
          mailto:ericb@...
          http://www.gobosoft.com
        • Arno Wagner
          ... [...] ... That was also my understanding. Every property the result must have except the type needs to be specified in the postcondition. like Current
          Message 4 of 20 , Dec 19, 2001
          • 0 Attachment
            On Wed, Dec 19, 2001 at 10:16:34PM +0100, Eric Bezault wrote:
            > Dominique Colnet wrote:
            [...]
            > > > 2) all the attributes of the result are initialized by the creation
            > > > procedure (make, make_empty, etc.) without any hint
            > > > from the current object
            > > But this would not be like Current ...
            >
            > Why? "like Current" is a type, it says nothing about the
            > values of the attributes of that type.

            That was also my understanding. Every property the result must
            have except the type needs to be specified in the postcondition.
            "like Current" only specifies the type.

            Regards,
            Arno

            --
            Arno Wagner Dipl. Inform. ETH Zuerich wagner@...
            GnuPG: ID: 1E25338F FP: 0C30 5782 9D93 F785 E79C 0296 797F 6B50 1E25 338F

            Known Plaintext Attack n.:
            Faking the ability to break a cipher when one already knows the answer.
          • Alexander Kogtenkov
            ... Yes. The question is whether the descendant can rely on the default implementation (the values of the attributes) or it should redefine all the functions
            Message 5 of 20 , Dec 20, 2001
            • 0 Attachment
              Arno Wagner wrote:

              >That was also my understanding. Every property the result must
              >have except the type needs to be specified in the postcondition.
              >"like Current" only specifies the type.

              Yes. The question is whether the descendant can rely on the
              default implementation (the values of the attributes)
              or it should redefine all the functions that return
              "like Current" to be on the safe side.

              The current NICE standard does not say anything about this.

              Regards,
              Alexander Kogtenkov
              Object Tools, Moscow
            • Arno Wagner
              ... I think I still don t understand what you mean. Do you mean that there are some implicit postconditions that are not inherited? Or dou you mean that in a
              Message 6 of 20 , Dec 20, 2001
              • 0 Attachment
                On Thu, Dec 20, 2001 at 11:07:55AM +0300, Alexander Kogtenkov wrote:
                > Arno Wagner wrote:
                >
                > >That was also my understanding. Every property the result must
                > >have except the type needs to be specified in the postcondition.
                > >"like Current" only specifies the type.
                >
                > Yes. The question is whether the descendant can rely on the
                > default implementation (the values of the attributes)
                > or it should redefine all the functions that return
                > "like Current" to be on the safe side.

                I think I still don't understand what you mean.

                Do you mean that there are some implicit postconditions that are
                not inherited?

                Or dou you mean that in a derived class the implementation cannot
                fulfill the contract anymore?

                Or maybe that in a derived class a feature might fulfill its contract,
                but that does not make sense as there are additional
                restrictions/fields in Current and therefore the result
                is wrong? In this case these additional restrictions
                are likely to be new class invariants, and so the implementation
                needs to be changed.

                In any other cases, everything not specified can rightfully
                have some arbitrary value. Is this your concern?

                > The current NICE standard does not say anything about this.

                Regards,
                Arno

                --
                Arno Wagner Dipl. Inform. ETH Zuerich wagner@...
                GnuPG: ID: 1E25338F FP: 0C30 5782 9D93 F785 E79C 0296 797F 6B50 1E25 338F

                Known Plaintext Attack n.:
                Faking the ability to break a cipher when one already knows the answer.
              • Alexander Kogtenkov
                ... No. ... No. ... Yes, this is my concern. For example, class COLOR_STRING inherit STRING creation make, make_empty, make_filled feature color: ... -- The
                Message 7 of 20 , Dec 20, 2001
                • 0 Attachment
                  Arno Wagner wrote:

                  >Do you mean that there are some implicit postconditions that are
                  >not inherited?

                  No.

                  >Or dou you mean that in a derived class the implementation cannot
                  >fulfill the contract anymore?

                  No.

                  >Or maybe that in a derived class a feature might fulfill its
                  >contract,
                  >but that does not make sense as there are additional
                  >restrictions/fields in Current and therefore the result
                  >is wrong? In this case these additional restrictions
                  >are likely to be new class invariants, and so the implementation
                  >needs to be changed.
                  >
                  >In any other cases, everything not specified can rightfully
                  >have some arbitrary value. Is this your concern?

                  Yes, this is my concern. For example,

                  class COLOR_STRING
                  inherit
                  STRING
                  creation
                  make, make_empty, make_filled
                  feature
                  color: ...
                  -- The current color
                  -- It is set to "white" upon creation
                  set_color (new_color: like color) is
                  do
                  color := new_color
                  end
                  white: like color is ...
                  red: like color is ...
                  green: like color is ...
                  blue: like color is ...
                  end

                  ...
                  c: COLOR_STRING
                  ...
                  create c.make_filled ('A', 5)
                  check c.color = c.white end
                  c.set_color (c.red)
                  check c.color = c.red end
                  c := c.substring (2, 3)
                  -- What is the value of "c.color" at this point?

                  Note that "substring" is not redefined in COLOR_STRING,
                  so the default implementation from STRING is used.

                  Regards,
                  Alexander Kogtenkov
                  Object Tools, Moscow
                • Arno Wagner
                  ... [...] ... [nice example with colored string snipped] O.K., I see your point. I think in cases where the class invariant (executable or not) has changed,
                  Message 8 of 20 , Dec 20, 2001
                  • 0 Attachment
                    On Thu, Dec 20, 2001 at 02:59:02PM +0300, Alexander Kogtenkov wrote:
                    > Arno Wagner wrote:
                    [...]
                    > >In any other cases, everything not specified can rightfully
                    > >have some arbitrary value. Is this your concern?
                    >
                    > Yes, this is my concern. For example,
                    [nice example with colored string snipped]

                    O.K., I see your point.

                    I think in cases where the class invariant (executable or not)
                    has changed, the "like Current" functions have to be reimplemented
                    in the general case, as the semantics of the class
                    has changed far enough that a function implemented in an
                    ancestor usually cannot have anticipated the changes.

                    Take e.g. the case that an instance of "Current" may either
                    be freshly created or has some complex internal state,
                    with this requirement being new in the child.
                    Even if creation with "make" is mandatory, an inherited
                    function that changes some attributes would need to do the
                    complex initialisation, but has no clue how to do it or even
                    that it is required at all.
                    Along the same lines might a specific change in an attribute might
                    require complex other changes in other attributes new in this class
                    that inherited code has no clue about, so that a "clone"d
                    instance cannot be changed without knowledge of the new
                    class invariant and new attributes.

                    This shows that requiring creation via clone, make
                    or make_empty or the like are not enough to ensure the
                    correctness even of a carefully implemented function
                    after inheritence.

                    I think there might really be no other option than having
                    a designer decide whether the additional fields
                    need special treatment or can be left with their
                    default values.

                    Regards,
                    Arno

                    --
                    Arno Wagner Dipl. Inform. ETH Zuerich wagner@...
                    GnuPG: ID: 1E25338F FP: 0C30 5782 9D93 F785 E79C 0296 797F 6B50 1E25 338F

                    Known Plaintext Attack n.:
                    Faking the ability to break a cipher when one already knows the answer.
                  • Alexander Kogtenkov
                    ... The class invariant is preserved by either clone or make/make_empty. So the result does not violate the class invariant. I think, creating the result that
                    Message 9 of 20 , Dec 21, 2001
                    • 0 Attachment
                      Arno Wagner wrote:

                      > I think in cases where the class invariant (executable or not)
                      > has changed, the "like Current" functions have to be reimplemented
                      > in the general case, as the semantics of the class
                      > has changed far enough that a function implemented in an
                      > ancestor usually cannot have anticipated the changes.

                      The class invariant is preserved by either clone or
                      make/make_empty. So the result does not violate the
                      class invariant.

                      I think, creating the result that violates the class invariant is
                      not an option. And the only (?) way to do it is to use the
                      creation procedure or to use "clone" that calls "copy".

                      > Take e.g. the case that an instance of "Current" may either
                      > be freshly created or has some complex internal state,
                      > with this requirement being new in the child.
                      > Even if creation with "make" is mandatory, an inherited
                      > function that changes some attributes would need to do the
                      > complex initialisation, but has no clue how to do it or even
                      > that it is required at all.

                      But the creation procedure is called polymorphically in this case
                      - for the object of type "like Current". So, the object will be
                      initialized properly.

                      > Along the same lines might a specific change in an attribute might
                      > require complex other changes in other attributes new in this class
                      > that inherited code has no clue about, so that a "clone"d
                      > instance cannot be changed without knowledge of the new
                      > class invariant and new attributes.

                      Again, "clone" calls "copy" and it's the responsibility of the
                      descendant to preserve the class invariant in this one function
                      - not in all "like Current" functions.

                      > This shows that requiring creation via clone, make
                      > or make_empty or the like are not enough to ensure the
                      > correctness even of a carefully implemented function
                      > after inheritence.

                      It's enough for the descendant to implement properly
                      make/make_empty and copy. All the "like Current" functions
                      can rely on them and their result will be in the valid state.

                      The difference is that make/make_empty are not
                      provided with the information about the original object
                      while "copy" has such an opportunity.

                      So in the example I posted earlier, the implementation
                      that uses make/make_empty will return "white" string
                      (the color of the newly created object). The implementation
                      that relies on "clone" will return "red" string
                      (the color of the string for which "substring" is called).

                      My suggestion is to add to the standard the following
                      note:
                      (variant 1) Functions that return "like Current" use the
                      creation procedure to obtain the result object
                      (variant 2) Functions that return "like Current" use
                      "clone" to obtain the result object
                      (variant 3) Functions that return "like Current" use
                      either creation procedure or "clone" to obtain the
                      result object and the portable descendant should
                      redefine all such functions if creation procedure
                      leaves the object in a state different from the
                      state of the object obtained via "clone"

                      Regards,
                      Alexander Kogtenkov
                      Object Tools, Moscow
                    • Arno Wagner
                      ... The result of clkone, make /make_empty does not. But the result of a like Current function might. Thjis can happen if the class invariant of the child is
                      Message 10 of 20 , Dec 21, 2001
                      • 0 Attachment
                        On Fri, Dec 21, 2001 at 11:02:51AM +0300, Alexander Kogtenkov wrote:
                        > Arno Wagner wrote:
                        >
                        > > I think in cases where the class invariant (executable or not)
                        > > has changed, the "like Current" functions have to be reimplemented
                        > > in the general case, as the semantics of the class
                        > > has changed far enough that a function implemented in an
                        > > ancestor usually cannot have anticipated the changes.
                        >
                        > The class invariant is preserved by either clone or
                        > make/make_empty. So the result does not violate the
                        > class invariant.

                        The result of clkone, make /make_empty does not. But the result
                        of a "like Current" function might.

                        Thjis can happen if the class invariant of the child is more
                        restrictive. That is the type of "change" I meant. Especially
                        when you introduce new attributes there might be no choice than
                        to have additional invariants relating them to the old ones
                        (old: defined in the parent; new: defined in the child).

                        > I think, creating the result that violates the class invariant is
                        > not an option. And the only (?) way to do it is to use the
                        > creation procedure or to use "clone" that calls "copy".

                        Right. I was not talking about this, the problem is more
                        complicated, see example below.

                        > > Take e.g. the case that an instance of "Current" may either
                        > > be freshly created or has some complex internal state,
                        > > with this requirement being new in the child.
                        > > Even if creation with "make" is mandatory, an inherited
                        > > function that changes some attributes would need to do the
                        > > complex initialisation, but has no clue how to do it or even
                        > > that it is required at all.
                        >
                        > But the creation procedure is called polymorphically in this case
                        > - for the object of type "like Current". So, the object will be
                        > initialized properly.

                        Seems I didn't express myself too clearly. Yes, the initialisation
                        will leave the object in a proper state. But the function itself
                        might make some changes to this state that mandate other changes
                        in attributes new in this class, so that the inherited implementation
                        does not know about them. Again see example.

                        > > Along the same lines might a specific change in an attribute might
                        > > require complex other changes in other attributes new in this class
                        > > that inherited code has no clue about, so that a "clone"d
                        > > instance cannot be changed without knowledge of the new
                        > > class invariant and new attributes.
                        >
                        > Again, "clone" calls "copy" and it's the responsibility of the
                        > descendant to preserve the class invariant in this one function
                        > - not in all "like Current" functions.

                        Agreed. But if the "like Current" functions does changes
                        this integrity might get violated. [==> Example]

                        > > This shows that requiring creation via clone, make
                        > > or make_empty or the like are not enough to ensure the
                        > > correctness even of a carefully implemented function
                        > > after inheritence.
                        >
                        > It's enough for the descendant to implement properly
                        > make/make_empty and copy. All the "like Current" functions
                        > can rely on them and their result will be in the valid state.

                        No.

                        Example:
                        --------
                        You have an attribute color_rgb in COLOR.
                        Then you inherit COLUR_2 from COLOR and add an attribute color_cmyk
                        and an invariant that requires color_rgb and color_cmyk to
                        allways contain the same color. After initialisation or cloneing
                        the state of an instance of COLOR_2 will be fine.

                        Now if you have a function "as_grey", that clones the current
                        object, then converts the color to the appropriate greyscale,
                        and returns it, you have a problem.

                        The implementation inherited from COLOR will not know about color_cmyk
                        and the result it produces will violate the class invariant of COLOR_2,
                        as color_cmyk of the result will not be adjusted and will usually be
                        different from color_rgb unless the color was monocrome in the first place.

                        Same with every other new attributes that have to be kept consistent
                        with old ones. The inherited code will not know about these
                        consistency requirements and no kind of initialisation
                        will help. (If you have a clean ADT design, the problem
                        will not arise, as every attribute will be "primary" and all
                        "redundant" "attributes" will really be functions of these
                        primary attributes. But speed or other problems can prevent
                        the design to be clean in this sense.)

                        > The difference is that make/make_empty are not
                        > provided with the information about the original object
                        > while "copy" has such an opportunity.
                        >
                        > So in the example I posted earlier, the implementation
                        > that uses make/make_empty will return "white" string
                        > (the color of the newly created object). The implementation
                        > that relies on "clone" will return "red" string
                        > (the color of the string for which "substring" is called).

                        For independent new attributes (i.e. those that are not
                        dependent on some of the old attributes via additional
                        invariants) your approach works. Both wiht creation and
                        with clone. For dependent new attributes it fails, see
                        my example.

                        > My suggestion is to add to the standard the following
                        > note:
                        > (variant 1) Functions that return "like Current" use the
                        > creation procedure to obtain the result object
                        > (variant 2) Functions that return "like Current" use
                        > "clone" to obtain the result object
                        > (variant 3) Functions that return "like Current" use
                        > either creation procedure or "clone" to obtain the
                        > result object and the portable descendant should
                        > redefine all such functions if creation procedure
                        > leaves the object in a state different from the
                        > state of the object obtained via "clone"

                        Looks good to me, but a note should be added that this
                        is sufficient only in cases where all new attributes
                        can be left in their cloned or originally initialized
                        state even when other attributes are changed.

                        I would prefer variant 1, as clone could have undesirable
                        side effects. Same problem with deep_clone. What I mean is
                        that we cannot make general assumptions about the nature of
                        the cloning operation required, while we can certainly
                        require that initialisation is unproblematic.

                        While your solution does not (and cannot) cover the general case,
                        it would be nice if there was this kind of standard initialisation
                        for additional attributes introduced in inheritance. Your concern
                        is certainly valid!

                        Regards,
                        Arno

                        --
                        Arno Wagner Dipl. Inform. ETH Zuerich wagner@...
                        GnuPG: ID: 1E25338F FP: 0C30 5782 9D93 F785 E79C 0296 797F 6B50 1E25 338F

                        Known Plaintext Attack n.:
                        Faking the ability to break a cipher when one already knows the answer.
                      • Alexander Kogtenkov
                        ... Let s look at the code class COLOR feature color_rgb: ... f: like Current is do -- Obtain the new object Result := clone (Current) -- Class invariant is
                        Message 11 of 20 , Dec 21, 2001
                        • 0 Attachment
                          Arno Wagner wrote:

                          > Example:
                          > --------
                          > You have an attribute color_rgb in COLOR.
                          > Then you inherit COLUR_2 from COLOR and add an attribute color_cmyk
                          > and an invariant that requires color_rgb and color_cmyk to
                          > allways contain the same color. After initialisation or cloneing
                          > the state of an instance of COLOR_2 will be fine.
                          >
                          > Now if you have a function "as_grey", that clones the current
                          > object, then converts the color to the appropriate greyscale,
                          > and returns it, you have a problem.
                          >
                          > The implementation inherited from COLOR will not know about color_cmyk
                          > and the result it produces will violate the class invariant of COLOR_2,
                          > as color_cmyk of the result will not be adjusted and will usually be
                          > different from color_rgb unless the color was monocrome in the first place.

                          Let's look at the code

                          class COLOR
                          feature
                          color_rgb: ...
                          f: like Current is
                          do
                          -- Obtain the new object
                          Result := clone (Current)
                          -- Class invariant is valid for Result
                          -- Change color in the result - we can do it only via a call
                          Result.set_color (...)
                          -- Class invariant is valid for Result because it's part of the contract
                          -- of the class COLOR
                          -- (COLOR is a client of itself here)
                          end
                          end

                          class COLOR_2
                          inherit COLOR
                          feature
                          color_cmyk: ...
                          end

                          Any attribute of the result cannot be changed without calling the
                          feature. And it's the responsibility of the descendant to keep the
                          class invariant valid. In this example, COLOR_2 must redefine
                          set_color. Otherwise, COLOR_2 is buggy. But there is no need
                          to redefine "f": whatever class invariant in COLOR_2 is - it will
                          be preserved.

                          Please, correct me if I miss your point.

                          Regards,
                          Alexander Kogtenkov
                          Object Tools, Moscow
                        • Arno Wagner
                          ... You do not miss my point. I think I missed yours for some time. I hope I have it now. In a clean design the problem I describe only happens in procedures,
                          Message 12 of 20 , Dec 23, 2001
                          • 0 Attachment
                            On Fri, Dec 21, 2001 at 07:06:40PM +0300, Alexander Kogtenkov wrote:
                            > Arno Wagner wrote:
                            >
                            > > Example:
                            > > --------
                            > > You have an attribute color_rgb in COLOR.
                            > > Then you inherit COLUR_2 from COLOR and add an attribute color_cmyk
                            > > and an invariant that requires color_rgb and color_cmyk to
                            > > allways contain the same color. After initialisation or cloneing
                            > > the state of an instance of COLOR_2 will be fine.
                            > >
                            > > Now if you have a function "as_grey", that clones the current
                            > > object, then converts the color to the appropriate greyscale,
                            > > and returns it, you have a problem.
                            > >
                            > > The implementation inherited from COLOR will not know about color_cmyk
                            > > and the result it produces will violate the class invariant of COLOR_2,
                            > > as color_cmyk of the result will not be adjusted and will usually be
                            > > different from color_rgb unless the color was monocrome in the first place.
                            >
                            > Let's look at the code
                            >
                            > class COLOR
                            > feature
                            > color_rgb: ...
                            > f: like Current is
                            > do
                            > -- Obtain the new object
                            > Result := clone (Current)
                            > -- Class invariant is valid for Result
                            > -- Change color in the result - we can do it only via a call
                            > Result.set_color (...)
                            > -- Class invariant is valid for Result because it's part of the contract
                            > -- of the class COLOR
                            > -- (COLOR is a client of itself here)
                            > end
                            > end
                            >
                            > class COLOR_2
                            > inherit COLOR
                            > feature
                            > color_cmyk: ...
                            > end
                            >
                            > Any attribute of the result cannot be changed without calling the
                            > feature. And it's the responsibility of the descendant to keep the
                            > class invariant valid. In this example, COLOR_2 must redefine
                            > set_color. Otherwise, COLOR_2 is buggy. But there is no need
                            > to redefine "f": whatever class invariant in COLOR_2 is - it will
                            > be preserved.
                            >
                            > Please, correct me if I miss your point.

                            You do not miss my point. I think I missed yours for some time.
                            I hope I have it now.

                            In a clean design the problem I describe only happens in procedures,
                            and so the implementor has the responsibility to adjust all of them
                            in accordance with the new invariants. I overlooked that, my fault.
                            (Maybe I am working too much with students, and while I do not do
                            sideeffects in functions, I usually expect other people not to be
                            that careful...)

                            But does not the same argument apply to your concerns? If somebody
                            clones a class or creates a new instance and then changes anything
                            about this object, shouldn't the procedures used to make these
                            changes equally respect the new invariamts and shouldn't this
                            solve your problem? I.e. if some change mandates a change in
                            some new attribute this should be formulated as a new invariant and
                            consequently the procedures will have to be changed to change
                            the new attributes accordingly. This should prevent anything being
                            "uninitialised" except where this is not a problem. Of course
                            if somebody reimplements a "copy" such that only attributes knowen
                            at that level are copied, and then forgets to add a postcondition
                            that ensures all possible new attributes are copied, this will not
                            work properly in a descendant and the postcondition will not fail
                            where it should.

                            But anybody doing such a thing is doing unclean programming anyway.
                            So if somebody creates a new object, makes some changes and copies
                            some attributes, we cannot tell whether new attributes in an inherited
                            class, that are not required to change by an invariant or postcondition,
                            actually should be changed or not. It could well be that leaving
                            them in their original state is fine. It could also be that they have
                            to change.

                            To go back to your example with COLOR_STRING: There is no default value
                            for the substring. Substring is defined on a sequence of items, while
                            your color-attribute is defined on strings. The concept of a string is
                            that it has a sequence of items attached, and an (in the default case
                            empty) set of attributes that do not belong to the items, or the
                            item sequence, but the string itself.

                            Substring does not deal with string-properties, only with string-item
                            sequences. The original postcondition says it is fine whenever the
                            new string has a specific subsequence as its item sequence. If there is
                            no invariant saying anything else, sunstring performs completely
                            correct, if it leaves the color attribute in an arbitrary state.
                            This is generally bad, I agree, but there is no generic way to deduce
                            the colour of a substring. True, the items happened to be part of a
                            string with a color, but what about the impact on the items?

                            If you have the items "inherit" the colour of the string they where
                            part of the problem vanishes, as then the colour is an item-property.
                            Then "is_equal" for the items takes care of the problem (this would
                            now be COLOR_CHARACTER).
                            If not, the items do not carry a color and a substring is not
                            a modified copy of a string, but rather a copy of a part of the item
                            sequence of the original string. I am sure other solutions exist.
                            (You also get conflicts when concatenating, searching for substrings,
                            and with other operations). We cannot know whether a colour is
                            something that is a general item property that holds for all items of
                            a string, or whether is is something a string gets because of other
                            reasons.

                            As a consequence there are a number of ways to do this kind of
                            modification and the implementor has to give the complete set
                            of additional semantics, which includes what happens to the
                            new attributes in cases not specified before whenever they
                            matter.

                            To go back to the concrete level, both make_empty and clone
                            (and then modify) can be exactly the right thing, completely
                            wrong, or both completely wrong at the same time.

                            Regards,
                            Arno
                            --
                            Arno Wagner Dipl. Inform. ETH Zuerich wagner@...
                            GnuPG: ID: 1E25338F FP: 0C30 5782 9D93 F785 E79C 0296 797F 6B50 1E25 338F

                            Known Plaintext Attack n.:
                            Faking the ability to break a cipher when one already knows the answer.
                          • Roger Browne
                            Sorry to come into this thread quite late. ... When we worked on making STRING safe in descendants , we based our specifications on the following assumption:
                            Message 13 of 20 , Dec 23, 2001
                            • 0 Attachment
                              Sorry to come into this thread quite late.

                              Alexander Kogtenkov wrote:
                              > It appears that the functions that return "like Current"
                              > can be implemented in at least two different ways:
                              > 1) clone (Current)
                              > 2) create Result.make_empty / create Result.make (...)

                              When we worked on "making STRING safe in descendants", we based our
                              specifications on the following assumption:

                              That the most common requirement is for attributes
                              introduced in descendants to be retained by
                              functions that return "like current".

                              This assumption is best-supported by Alexander's option (1), because in
                              that case features such as 'substring' will not be need to be redefined
                              in descendants.

                              Some applications may require descendants which behave in ways that
                              differ from the assumption above. That's OK, but in that case the author
                              of those descendant classes will need to redefine features such as
                              'substring'.

                              We attempted to capture the desired behaviour in the postcondition of
                              features such as 'substring':

                              substring (start_index, end_index: INTEGER): like Current
                              -- New object containing all characters
                              -- from `start_index' to `end_index' inclusive
                              require
                              valid_start_index: 1 <= start_index
                              valid_end_index: end_index <= count
                              meaningful_interval: start_index <= end_index + 1
                              ensure
                              substring_not_void: Result /= Void
                              substring_count: Result.count = end_index - start_index + 1
                              first_item: Result.count > 0 implies
                              Result.item (1) = item (start_index)
                              recurse:
                              Result.count > 0 implies
                              Result.substring(2, Result.count).is_equal(
                              substring(start_index + 1, end_index))

                              The expectation is that a descendant that adds attributes will normally
                              redefine 'is_equal' to take those attributes into account. Therefore, if
                              Alexander's option (1) has been used in STRING, no redefinition will be
                              required to make 'substring' meet its postcondition in the descendant.

                              In a later message, Alexander wrote:
                              > My suggestion is to add to the standard the following note:
                              > (variant 1) Functions that return "like Current" use the
                              > creation procedure to obtain the result object
                              > (variant 2) Functions that return "like Current" use
                              > "clone" to obtain the result object
                              > (variant 3) Functions that return "like Current" use
                              > either creation procedure or "clone" to obtain the
                              > result object and the portable descendant should
                              > redefine all such functions if creation procedure
                              > leaves the object in a state different from the
                              > state of the object obtained via "clone"

                              As I've stated above, I feel strongly that "variant 2" is the right
                              implementation. But I feel uncomfortable about the wording, which seems
                              to be written in terms of implementation details rather that high-level
                              abstractions.

                              Nevertheless, 'clone' is a magic function in that it must be implemented
                              by the compiler. We can't write 'clone' in Eiffel unless we redefine it
                              for every class. So the only way to get the same benefits for other "like
                              current" functions seems to be to specify a dependency on 'clone'.

                              Regards,
                              Roger

                              PS: I know there are a few "hanging threads" from other recent
                              discussions in this group. I hope to tie up the loose ends soon, but I'm
                              very busy for the next few days.
                              --
                              Roger Browne - roger@... - Everything Eiffel
                              19 Eden Park Lancaster LA1 4SJ UK - Phone +44 1524 32428
                            • Eric Bezault
                              ... In passing, I started to try to rewrite the UC_STRING class from Gobo by making it inherit from STRING. I guess that I am the first one to try to write a
                              Message 14 of 20 , Dec 24, 2001
                              • 0 Attachment
                                Roger Browne wrote:
                                >
                                > When we worked on "making STRING safe in descendants",

                                In passing, I started to try to rewrite the UC_STRING class
                                from Gobo by making it inherit from STRING. I guess that I
                                am the first one to try to write a descendant of STRING using
                                ELKS 2001 specification and I found out that in the sake to
                                make the specification of STRING as complete as possible we
                                ended up having some postconditions which make it impossible
                                for descendants to refine the behavior of the corresponding
                                features. I will try to send to this list a summary of my
                                experience before the end of the year with some suggestions
                                for improvements for STRING ELKS 2002.

                                > This assumption is best-supported by Alexander's option (1), because in
                                > that case features such as 'substring' will not be need to be redefined
                                > in descendants.

                                The reason why this whole thread started is because while
                                implementing the UC_STRING class as described above, I
                                noticed that Visual Eiffel's implementation of `substring'
                                was the only one to use `clone' and I told Alexander that
                                his implementation was inefficient compared to the other
                                implementations using `make' when it comes to call
                                'substring (3, 4)' on a string with 10,000,000 characters
                                because it first copies 10,000,000 characters and then
                                throw out 9,999,998 of them. Note that this example is not
                                so uncommon when a parser needs to extract tokens from a
                                buffer.

                                So I'd rather have an efficient `substring' implementation
                                in STRING using `make' instead of `clone', and let the
                                descendant classes redefine this (and other similar)
                                routine(s). The reason for that is that I think that we
                                will more often call STRING.substring than writing a
                                descendant of STRING.

                                --
                                Eric Bezault
                                mailto:ericb@...
                                http://www.gobosoft.com
                              • Alexander Kogtenkov
                                Arno Wagner wrote: ... Yes, either thing can be wrong, but I would prefer to have one (possibly wrong) thing in all ELKS-compatible implementations rather than
                                Message 15 of 20 , Dec 24, 2001
                                • 0 Attachment
                                  Arno Wagner wrote:
                                  ...
                                  > To go back to the concrete level, both make_empty and clone
                                  > (and then modify) can be exactly the right thing, completely
                                  > wrong, or both completely wrong at the same time.

                                  Yes, either thing can be wrong, but I would prefer to have one
                                  (possibly wrong) thing in all ELKS-compatible implementations
                                  rather than many different ones.

                                  Regards,
                                  Alexander Kogtenkov
                                  Object Tools, Moscow
                                • Alexander Kogtenkov
                                  Roger Browne wrote: ... Yes, I could not find a formal specification yet. Regards, Alexander Kogtenkov Object Tools, Moscow
                                  Message 16 of 20 , Dec 24, 2001
                                  • 0 Attachment
                                    Roger Browne wrote:
                                    ...
                                    > > (variant 2) Functions that return "like Current" use
                                    > > "clone" to obtain the result object
                                    ...
                                    >
                                    > As I've stated above, I feel strongly that "variant 2" is the right
                                    > implementation. But I feel uncomfortable about the wording, which seems
                                    > to be written in terms of implementation details rather that high-level
                                    > abstractions.

                                    Yes, I could not find a formal specification yet.

                                    Regards,
                                    Alexander Kogtenkov
                                    Object Tools, Moscow
                                  • Roger Browne
                                    ... I agree that we want an efficient substring , but I don t think we need to make any tradeoff between convenience and efficiency. Provided STRING.substring
                                    Message 17 of 20 , Dec 24, 2001
                                    • 0 Attachment
                                      Eric Bezault wrote:

                                      > ... I'd rather have an efficient `substring' implementation
                                      > in STRING using `make' instead of `clone', and let the
                                      > descendant classes redefine this (and other similar)
                                      > routine(s). The reason for that is that I think that we
                                      > will more often call STRING.substring than writing a
                                      > descendant of STRING.

                                      I agree that we want an efficient 'substring', but I don't think we need
                                      to make any tradeoff between convenience and efficiency.

                                      Provided STRING.substring gives the same result as an implementation that
                                      uses 'clone', it needn't actually use 'clone'. Many features of class
                                      STRING are implemented in the Eiffel runtime, and an efficient
                                      implementation of 'substring' seems straightforward.

                                      Regards,
                                      Roger
                                      --
                                      Roger Browne - roger@... - Everything Eiffel
                                      19 Eden Park Lancaster LA1 4SJ UK - Phone +44 1524 32428
                                    • Eric Bezault
                                      ... Which is different from what you said earlier: variant 2 suggested by Alexander explicitly states that `clone _should_ be called. ... I for one would
                                      Message 18 of 20 , Dec 24, 2001
                                      • 0 Attachment
                                        Roger Browne wrote:
                                        >
                                        > Provided STRING.substring gives the same result as an implementation that
                                        > uses 'clone', it needn't actually use 'clone'.

                                        Which is different from what you said earlier: variant 2 suggested
                                        by Alexander explicitly states that `clone' _should_ be called.

                                        > Many features of class
                                        > STRING are implemented in the Eiffel runtime, and an efficient
                                        > implementation of 'substring' seems straightforward.

                                        I for one would perfer to have as many routines written in
                                        Eiffel. I think that SmallEiffel is the compiler which contains
                                        the lowest number of routines whose implementation is hidden
                                        in the runtime, and nobody can argue that it is a source of
                                        inefficiency.

                                        I agree that we should not be distracted by efficiency concerns
                                        when we design a class specification, but likewise we should not
                                        have to implement a routine in the runtime when it can be
                                        done in Eiffel just because the specificiation makes the Eiffel
                                        implemenation inefficient. So there is a trade-off to be found,
                                        that's why I was happy with the fact that STRING.substring uses
                                        `make' (and hence provides an efficient 100% Eiffel implementation)
                                        and therefore have to redefine this routine in descendants when
                                        needed (which will happen not that often if we consider the number
                                        of descendants of STRING already there in existing software/libraries).

                                        --
                                        Eric Bezault
                                        mailto:ericb@...
                                        http://www.gobosoft.com
                                      • Arno Wagner
                                        ... I can understand that. The advantage would be that people know they need to pay attention. Regards, Arno -- Arno Wagner Dipl. Inform. ETH Zuerich
                                        Message 19 of 20 , Dec 24, 2001
                                        • 0 Attachment
                                          On Mon, Dec 24, 2001 at 01:02:22PM +0300, Alexander Kogtenkov wrote:
                                          > Arno Wagner wrote:
                                          > ...
                                          > > To go back to the concrete level, both make_empty and clone
                                          > > (and then modify) can be exactly the right thing, completely
                                          > > wrong, or both completely wrong at the same time.
                                          >
                                          > Yes, either thing can be wrong, but I would prefer to have one
                                          > (possibly wrong) thing in all ELKS-compatible implementations
                                          > rather than many different ones.

                                          I can understand that. The advantage would be that
                                          people know they need to pay attention.

                                          Regards,
                                          Arno

                                          --
                                          Arno Wagner Dipl. Inform. ETH Zuerich wagner@...
                                          GnuPG: ID: 1E25338F FP: 0C30 5782 9D93 F785 E79C 0296 797F 6B50 1E25 338F

                                          Known Plaintext Attack n.:
                                          Faking the ability to break a cipher when one already knows the answer.
                                        • Eric Bezault
                                          ... Looking at this assertion: removed: is_equal (old substring (1, i - 1) old substring (i + 1, count)) it is indeed clear that `substring and `is_equal
                                          Message 20 of 20 , Dec 25, 2001
                                          • 0 Attachment
                                            Roger Browne wrote:
                                            >
                                            > The expectation is that a descendant that adds attributes will normally
                                            > redefine 'is_equal' to take those attributes into account. Therefore, if
                                            > Alexander's option (1) has been used in STRING, no redefinition will be
                                            > required to make 'substring' meet its postcondition in the descendant.

                                            Looking at this assertion:

                                            removed: is_equal (old substring (1, i - 1)
                                            old substring (i + 1, count))

                                            it is indeed clear that `substring' and `is_equal' should have
                                            compatible behaviors.

                                            > I agree that we want an efficient 'substring', but I don't think we need
                                            > to make any tradeoff between convenience and efficiency.

                                            But if STRING.substring is too inefficient to be used (by a parser
                                            which extracts tokens from a large string buffer for example), I
                                            will end up writing my own routine in a mixin class. Is that really
                                            more convenient?! So I would rather have an efficient implementation
                                            of `substring' which I would have to redefine in descendants when
                                            the behavior of `is_equal' also changes, rather than having to
                                            reimplement the routines of STRING in a mixin class when they are
                                            too inefficient for some usage. Since we talk about tradeoff, I
                                            do think that we need a tradeoff, and I would prefer the
                                            inconvenience of having to redefine `substring' in descendants when
                                            needed and hence end up with a clean OO polymorphic redefinition
                                            from the client's point of view, rather than the inconvenience of
                                            having to reimplement `susbtring' in a mix class and end up with
                                            a non-00 non-polymorphic mechanism from the client's point of view.
                                            As for the solution of having an efficent implementation provided
                                            by the runtime, as I said yesterday if I had the choice I would
                                            prefer to have as many routines as possible written in Eiffel.
                                            It not only makes it easier to port to new target platforms, but
                                            I think that it is more a philosiphical point of view to write
                                            Eiffel code instead of foreign code whenever possible.

                                            --
                                            Eric Bezault
                                            mailto:ericb@...
                                            http://www.gobosoft.com
                                          Your message has been successfully submitted and would be delivered to recipients shortly.