No automatic extraction RE: [eiffel-users] 3 small questions

32 views
Skip to first unread message

Bertrand Meyer

unread,
Feb 6, 2019, 8:21:29 AM2/6/19
to eiffel...@googlegroups.com

Dear Alexey,

 

 >  class A end

 >  class B inherit A end

    ....

  >  a: expanded A

   > b: expanded B

   > ...

    > a:= b -- validity rule violation - why? What is wrong with polymorphism for expanded objects?

 

A class is not just a record type. It comes from an abstract data type, with semantic properties. Were the assignment permitted, you would want it (as I understand) to copy just the common fields. But assignment of objects is not field-by-field copy. It is only that by default (standard_copy). It applies `copy’, which every class can redefine to yield specific copy semantics fine-tuned to the needs of the class. Which version of `copy’ do you want to apply, A’s or B’s? Presumably the A version. But that does not work.

 

First, `copy’ requires the source and target to have identical (not just conforming) types. In fact standard_copy has exactly the same requirements. So the assignment, were it to be permitted, would need special rules. Change the semantics of assignment for just a very special case? I don’t think anyone would vote for that.

 

This requirement of identical types is there for good reasons but assume we drop it. The rule still doesn’t work. There are many catastrophe scenarios; here is just one. Assume a secret (non-exported) integer attribute xx in A. A also has a function x that returns xx, and a procedure set_x that assigns to xx. The procedure requires a positive argument and the function ensures a positive result. All fine and consistent. In B we always use 0 for xx, we add an attribute yy, and we change the implementation of x and xx so that they work on yy rather than xx., keeping their original properties (positive argument, positive result). Semantically this is fine, the rules are respected. But if we copy the xx field from an instance of B to an instance of A the resulting xx field has value 0 and x returns the wrong result.

 

Personally I don’t recall ever running into the need that you describe; that doesn’t mean it cannot happen but certainly it is not common. The case is delicate enough that we should not go for some possibly deceptive (“gotcha”) special semantic rule. Instead it is so easy if you really run into this need to write a procedure set_from_B (u: B) in A, or its function counterpart in B, defining the exact semantics that you want, respectful of course of the contracts. Then you can even declare the routine as a conversion procedure or conversion function, so that your desired assignment syntax

 

            a := b

 

works. But not with some murky effect. With one that you have explicitly define to implement your desired behavior.

 

I think this is another example in which the design of Eiffel has considered issues that in other languages are completely overlooked, leaving individual programmers to grapple with the consequences. I know we should explain all of this more.

 

-- BM

 

 

From: eiffel...@googlegroups.com <eiffel...@googlegroups.com> On Behalf Of Alexey Kanatov
Sent: Tuesday, February 5, 2019 17:03
To: Eiffel Users <eiffel...@googlegroups.com>
Subject: [eiffel-users] 3 small questions

 

Hi all, just wonder 

 

1. why () are prohibted in ISE Eiffel 

 

make () do 

   foo ()

end

 

is no longer a valid syntax ? 

 

2. What is wrong with a: expanded A - why is it treated as obsolete?

 

3. Expanded conformance

 

   class A end

   class B inherit A end

 

    ....

    a: expanded A

    b: expanded B

    ...

 

     a:= b -- validity rule violation - why? What is wrong with polymorphism for expanded obejcts?

 

Tnx, Alexey

 

 

P.S. I did not use Eiffel for years and not aware of latest changes ... so, just wonder ...

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
Visit this group at https://groups.google.com/group/eiffel-users.
For more options, visit https://groups.google.com/d/optout.

Alexey Kanatov

unread,
Feb 8, 2019, 2:56:35 AM2/8/19
to Eiffel Users
Bertrand,

Have I captured example you've described correctly?

local

     a: expanded A

    b: expanded B

     i: INTEGER

do

….

              a := b -- Let’s assume it is allowed

              i :=  a.x -- Will it be postcondition violation or not? yes it will ! But if we remove 'expanded' from declarations of a and b will we get the same effect?

-- a.x will invoke A version of x as there is no dynamic disptach for expanded types - so, the trick is that creation procedure for B is absent which should set field xx into the state which corresponds to postcondition of x ... 

-- With 'reference' semantics relies on the body of redefined x and as it retrun yy which is 0 teh same postcondition inherited from A version will trigger alarm ...

-- So, this example shows that skipping invaraints  or better say replacing invariants with postconditions is very obscure and danguerous pattern of programming ...

end

 

class A

create

                make

feature {NONE}

                xx: INTEGER

                make do

                                xx := 1

                end

feature

                x: like xx do

Result := xx

ensure

                Result > 0

end

                set_x (a: like xx)

                require

                                a > 0

do

xx := a

end

end

 

class B

inherit

A redefine x, set_x end

feature

                yy: Integer         

x: like xx do

Result := yy

end

                set_x (a: like xx)

                do

                                yy := a

                end

end

 

Bertrand Meyer

unread,
Feb 8, 2019, 4:40:55 AM2/8/19
to eiffel...@googlegroups.com, me...@inf.ethz.ch

Dear Alexey,

 

If I understand you right you are saying that my example is bad style. In fact I think that the example, not itself but as an abstraction of things that people do, is completely reasonable. I am sure I could build a realistic example, and transpose the problem to invariants from postconditions.

 

But the point here is not about style. What I believe I showed  through the example is that the “partial extraction” semantics of expanded-to-expanded polymorphic assignment, whose absence in Eiffel you deplore, leads to incorrect behavior, which does not occur with standard reference-to-reference polymorphism.

 

The task of a programming language design is to define consistent semantics for programs. The language design cannot be judgmental: it is not its business, or the compiler’s, to decide that certain patterns of programming are “very obscure and dangerous”. More precisely, if the language designers make such a determination and are sure of the obscurity and dangerosity, they change the language design to make them invalid, hence rejected at compile-time. For programs that the language definition and hence the compilers accept, they should guarantee well-defined processing according to general and clear rules. Between the designers and the users of the language this is a kind of, if I may use that term, contract.

 

That aspect has always shocked me in the design of languages other than Eiffel. Java, for example, followed C++ in mistaking the notion of exporting an attribute for the notion of exporting it read-write. Then the official language description warned readers about using this scheme, saying it’s bad and the attribute should be shadowed by a function. It seems schizophrenic, hypocritical or both to include a feature in a language that you have built yourself (no one forced you either to design the language or include the feature) and in the same breadth tell people not to use it. Eiffel stays away from any such situation. If we put something in the language, it’s for people to use it.

 

Of course there remains room for style advice, as illustrated by the code analyzer (ex-“Eiffel Inspector”) of EiffelStudio, which warns programmers of code elements of sub-par style. But that’s to help them improve their code, not as an excuse for deficiencies in the language.

Alexey Kanatov

unread,
Feb 12, 2019, 2:41:29 AM2/12/19
to Eiffel Users
Dear Bertrands, please see below


On Friday, February 8, 2019 at 12:40:55 PM UTC+3, Bertrand Meyer wrote:

Dear Alexey,

 

If I understand you right you are saying that my example is bad style. In fact I think that the example, not itself but as an abstraction of things that people do, is completely reasonable. I am sure I could build a realistic example, and transpose the problem to invariants from postconditions.


based on the example I've created I've got two things - first that redefined function x does nothing to preserve the inherited postcondition which leads to postcondition violation (IMHO regardsless of expanded or reference entity is used as target for the call). Second was my attempt to fix it thru proper creation procedure and making the postcondition on the value of class attribute to become class invariant. That is why I put the comment that the semantics of the function which does nothing to preserve inherited postcondition is dangerous. 


 

But the point here is not about style. What I believe I showed  through the example is that the “partial extraction” semantics of expanded-to-expanded polymorphic assignment, whose absence in Eiffel you deplore, leads to incorrect behavior, which does not occur with standard reference-to-reference polymorphism.


Frankly speaking I do not see that if we remove keyword 'expanded' from local attributes declarations we will get different run-time behavior - IMHO we will get the same postcondition violation. Could you please to explain how the example I made will work correctly in case of reference entities or any other example which will highlight that hypotheses allowance of polymorphic assignment for expanded entities will break the consistency of the software. 
 

 

The task of a programming language design is to define consistent semantics for programs. The language design cannot be judgmental: it is not its business, or the compiler’s, to decide that certain patterns of programming are “very obscure and dangerous”. More precisely, if the language designers make such a determination and are sure of the obscurity and dangerosity, they change the language design to make them invalid, hence rejected at compile-time. For programs that the language definition and hence the compilers accept, they should guarantee well-defined processing according to general and clear rules. Between the designers and the users of the language this is a kind of, if I may use that term, contract.


Fully agree and support!
Reply all
Reply to author
Forward
0 new messages