Conceptual meaning of undefine

43 views
Skip to first unread message

Alexey Kanatov

unread,
Jan 25, 2021, 2:48:38 PM1/25/21
to Eiffel Users
Dear all,

Different people ask me about the practical need of undefinition in case when we have effective class and after undefining of one of its features we come to a child class which will be deferred in such situation. So, conceptually we go down the inheritance hiearchy from the concrete class to some abstraction again. I was not able to find out a solid reason to provide some rationale for that - if one can help. Please. Alexey

r...@amalasoft.com

unread,
Jan 25, 2021, 3:22:56 PM1/25/21
to eiffel...@googlegroups.com
Hi Alexey

In my experience, it is most helpful when there is multiple inheritance and more than one ancestor has an implementation of that feature.  This occurs very commonly when creating custom GUI controls, or when your system has several shared ancestors, but occurs commonly enough elsewhere.
You will find many examples of undefining default_create, copy, and is_equal in such circumstances.  Then, the implementation of the descendent class supplants all of the inherited implementations, but does not use any of the inherited implementations.
When there is need to reuse, and build upon an inherited implementation, the redefine mechanism is used instead.  As such, it is also not uncommon to the see a mix of some undefines along with a single redefine from one of the ancestors.
R
--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/39bdaff4-6159-4261-a86c-3d62ab1fa802n%40googlegroups.com.

Rosivaldo Fernandes Alves

unread,
Jan 25, 2021, 3:32:17 PM1/25/21
to eiffel...@googlegroups.com
Hi Alexey.

What goes below comes from my little experience. Others may add more
examples.

Mostly, undefining will be necessary when a class inherits from two
classes and they have different implementations for the same feature; if
one of those implementation fits your needs, you undefine one of them,
what automatically keeps the other as the effective implementation in
your class. In code:

class PARENT1
feature
foo
do print ("whatever") end
end

class PARENT2
feature
foo
do print ("better") end
end

class CHILD
inherit
PARENT1 undefine foo end
PARENT2 -- {PARENT2}.foo is chosen as the effective implementation in
{CHILD}.
end

But you may have to undefine a feature even in single inheritance. For
example, suppose you have an effective class MY_SET, that implements the
concept of a set; you also have effective descendant classes, e.g.
SET_FAMILY and SUBSET_FAMILY, that are sets whose elements are sets
themselves. So you notice that your descendant classes have common
features that may be factored out to an ancestor class, but that
ancestor can not be MY_SET, because such features apply only to sets of
sets. You may then create a new *deferred* class, say, SET_OF_SETS, that
inherits from MY_SET and becomes the new parent of SET_FAMILY and
SUBSET_FAMILY. Since SET_OF_SETS is deferred, it may have to undefine
some features of MY_SET if such features *require* an effective class to
be valid.

Hope this helps.

Rosivaldo.

Em 25/01/2021 15:51, Alexey Kanatov escreveu:
> Dear all,
>
> Different people ask me about _the practical need_ of undefinition in
> case when we have effective class and after undefining of one of its
> features we come to a child class which will be deferred in such
> situation. So, conceptually we go down the inheritance hiearchy from the
> concrete class to some abstraction again. I was not able to find out a
> solid reason to provide some rationale for that - if one can help.
> Please. Alexey
>
> --
> 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
> <mailto:eiffel-users...@googlegroups.com>.
> <https://groups.google.com/d/msgid/eiffel-users/39bdaff4-6159-4261-a86c-3d62ab1fa802n%40googlegroups.com?utm_medium=email&utm_source=footer>.
OpenPGP_0xA9F13EA59C43EB79.asc
OpenPGP_signature

Gachoud Philippe

unread,
Jan 25, 2021, 3:36:11 PM1/25/21
to eiffel...@googlegroups.com
Hi,
mentioning also that maybe a feature is implemented in a hierarchy and you want it to be deferred for its descendents....



To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/b4c091da-8cdc-d11b-1cd9-204bdb95e7c6%40gmail.com.


--
**********************************************
Philippe Gachoud
Puerto Williams 6657
Las Condes
Santiago de Chile
RUT: 26374747-k
**********************************************

Larry Rix

unread,
Jan 25, 2021, 6:18:48 PM1/25/21
to Eiffel Users
Hey Alex!

I cannot think of a specific example where I have created a new descendant class from a concrete implementation parent and the new class is deferred. However, I know we have done it.

Restricting a descendant to be concrete if the parent(s) are concrete would be a mistake. As others are pointing out, multiple inheritance would be the biggest reason to allow a deferred descendant to inherit from a concrete ancestor. I say this without the need to provide an example.

Kindest regards,

Larry

Alexey Kanatov

unread,
Jan 26, 2021, 9:14:16 AM1/26/21
to Eiffel Users
Hi Rosivaldo - I liked your example about some common class  - " But you may have to undefine a feature even in single inheritance. For

example, suppose you have an effective class MY_SET, that implements the
concept of a set; you also have effective descendant classes, e.g.
SET_FAMILY and SUBSET_FAMILY, that are sets whose elements are sets
themselves. So you notice that your descendant classes have common
features that may be factored out to an ancestor class, but that
ancestor can not be MY_SET, because such features apply only to sets of
sets. You may then create a new *deferred* class, say, SET_OF_SETS, that
inherits from MY_SET and becomes the new parent of SET_FAMILY and
SUBSET_FAMILY. Since SET_OF_SETS is deferred, it may have to undefine
some features of MY_SET if such features *require* an effective class to
be valid.  " - but the thing is that what you need is just to prevent object creation for SET_OF_SETS, undefining is just allows not to put redefine in SET_FAMILY and SUBSET_FAMILY. So, the natural solution is to break the relation between deferred class and the existence of deferred features within the class. Deferred class is the class for which we cannot (it has deferred features) or do not want to have objects created - that is all. So, this does not explain the need for undefining :-)

Alexey Kanatov

unread,
Jan 26, 2021, 9:33:11 AM1/26/21
to Eiffel Users
Guys - please understand me right - my personal experience (being co-author of Visual Eiffel compiler implementing all feature adaptation mechanisms)  and delivering lectures to students about systematic software design and development is one thing but another is talking to Java, C#, C++, JS, Python, Go ... guys (who are the majority) and trying to advocate good Eiffel manners is a very different thing. They just do not buy things that are obvious and natural to me. That is why I am looking for examples that can be valuable for such folks. Tnx, Alexey

Rosivaldo Fernandes Alves

unread,
Jan 26, 2021, 10:03:01 AM1/26/21
to eiffel...@googlegroups.com
Hi Alexey.

My second example has a little twist that I did not mention. I have no
use for SET_OF_SETS apart from factoring out features of SET_FAMILY and
SUBSET_FAMILY. Normally, I would not need to undefine anything for that,
but MY_SET has some class features, and features that use such class
features are invalid within a deferred class like SET_OF_SETS (this was
a surprise to me). So I had to undefine the rogue (invalid) features of
SET_OF_SETS. The net result was that I have to make SET_FAMILY and
SUBSET_FAMILY to inherit SET_OF_SETS and, again, MY_SET, in order to get
back those features undefined at SET_OF_SET level.

Maybe this is not a great design, but I'm satisfied with it for now.

Apart from that, I think that you need advice from the true experts. :-)

Best regards,

Rosivaldo.

Em 26/01/2021 11:12, Alexey Kanatov escreveu:
> Hi Rosivaldo - I liked your example about some common class  - " But you
> may have to undefine a feature even in single inheritance. For
> example, suppose you have an effective class MY_SET, that implements the
> concept of a set; you also have effective descendant classes, e.g.
> SET_FAMILY and SUBSET_FAMILY, that are sets whose elements are sets
> themselves. So you notice that your descendant classes have common
> features that may be factored out to an ancestor class, but that
> ancestor can not be MY_SET, because such features apply only to sets of
> sets. You may then create a new *deferred* class, say, SET_OF_SETS, that
> inherits from MY_SET and becomes the new parent of SET_FAMILY and
> SUBSET_FAMILY. Since SET_OF_SETS is deferred, it may have to undefine
> some features of MY_SET if such features *require* an effective class to
> be valid.  " - but the thing is that what you need is just to prevent
> object creation for SET_OF_SETS, undefining is just allows not to put
> redefine in SET_FAMILY and SUBSET_FAMILY. So, the natural solution is to
> break the relation between deferred class and the existence of deferred
> features within the class. Deferred class is the class for which we
> cannot (it has deferred features) or do not want to have objects created
> - that is all. So, this does not explain the need for undefining :-)
>
> (...)
OpenPGP_0xA9F13EA59C43EB79.asc
OpenPGP_signature

Gachoud Philippe

unread,
Jan 26, 2021, 10:36:43 AM1/26/21
to eiffel...@googlegroups.com
Hi,
I was thinking following the discussions about some inheritance pattern into which the father I am has an ability to write, my children not having it still but inheriting from me. On this case my ability to write is an ability the will have, but in their way so the inheritence of me will undefine->write. Sorry, don't have the time to pass that into a classes model and implementation
Hope that helps...

--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/5a73017a-751c-3efd-14cd-611fc41ba2d2%40gmail.com.

r...@amalasoft.com

unread,
Jan 26, 2021, 11:10:09 AM1/26/21
to eiffel...@googlegroups.com
Hi Alexey

Attached is a "vintage" doc I created and have maintained over the years.  In the "undefine" section, there is a very basic example that _might_ help.
R
-------- Original Message --------
Subject: Re: [eiffel-users] Conceptual meaning of undefine
From: Alexey Kanatov <alexey.v...@gmail.com>
Date: Tue, January 26, 2021 9:33 am
To: Eiffel Users <eiffel...@googlegroups.com>

Guys - please understand me right - my personal experience (being co-author of Visual Eiffel compiler implementing all feature adaptation mechanisms)  and delivering lectures to students about systematic software design and development is one thing but another is talking to Java, C#, C++, JS, Python, Go ... guys (who are the majority) and trying to advocate good Eiffel manners is a very different thing. They just do not buy things that are obvious and natural to me. That is why I am looking for examples that can be valuable for such folks. Tnx, Alexey

On Tuesday, January 26, 2021 at 5:14:16 PM UTC+3 Alexey Kanatov wrote:
Hi Rosivaldo - I liked your example about some common class  - " But you may have to undefine a feature even in single inheritance. For
example, suppose you have an effective class MY_SET, that implements the
concept of a set; you also have effective descendant classes, e.g.
SET_FAMILY and SUBSET_FAMILY, that are sets whose elements are sets
themselves. So you notice that your descendant classes have common
features that may be factored out to an ancestor class, but that
ancestor can not be MY_SET, because such features apply only to sets of
sets. You may then create a new *deferred* class, say, SET_OF_SETS, that
inherits from MY_SET and becomes the new parent of SET_FAMILY and
SUBSET_FAMILY. Since SET_OF_SETS is deferred, it may have to undefine
some features of MY_SET if such features *require* an effective class to
be valid.  " - but the thing is that what you need is just to prevent object creation for SET_OF_SETS, undefining is just allows not to put redefine in SET_FAMILY and SUBSET_FAMILY. So, the natural solution is to break the relation between deferred class and the existence of deferred features within the class. Deferred class is the class for which we cannot (it has deferred features) or do not want to have objects created - that is all. So, this does not explain the need for undefining :-)

But you may have to undefine a feature even in single inheritance. For
example, suppose you have an effective class MY_SET, that implements the
concept of a set; you also have effective descendant classes, e.g.
SET_FAMILY and SUBSET_FAMILY, that are sets whose elements are sets
themselves. So you notice that your descendant classes have common
features that may be factored out to an ancestor class, but that
ancestor can not be MY_SET, because such features apply only to sets of
sets. You may then create a new *deferred* class, say, SET_OF_SETS, that
inherits from MY_SET and becomes the new parent of SET_FAMILY and
SUBSET_FAMILY. Since SET_OF_SETS is deferred, it may have to undefine
some features of MY_SET if such features *require* an effective class to
be valid.

Hope this helps.

Rosivaldo.

Em 25/01/2021 15:51, Alexey Kanatov escreveu:
> Dear all,
>
> Different people ask me about _the practical need_ of undefinition in
> case when we have effective class and after undefining of one of its
> features we come to a child class which will be deferred in such
> situation. So, conceptually we go down the inheritance hiearchy from the
> concrete class to some abstraction again. I was not able to find out a
> solid reason to provide some rationale for that - if one can help.
> Please. Alexey
>
> --
> 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
> To view this discussion on the web visit
--
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.
Adapting_Inherited_Features_in_Eiffel.pdf

Alexey Kanatov

unread,
Jan 26, 2021, 11:35:40 AM1/26/21
to Eiffel Users
Thank you all for your answers. I tried them all many times - the all do not convice single-inheritance minded folks :-)  Sorry ...
last try :-)
class A
    foo do end
end
deferred class
B
inherit A undefine foo end
end
That is the thing they (Java-C#-etc.) do not accept conceptually ...

Louis M

unread,
Jan 26, 2021, 1:13:35 PM1/26/21
to eiffel...@googlegroups.com

I will try an example that I did some time ago.

We all know that every class inherit ANY. Also, we all know that ANY have some mechanism like `is_equal`, `copy`, `twin`, `out`, etc.

Some time ago, I was creating a library that used a lot of C pointers and I create an abstract class to represent every class of the library. I knew that every class had to redefine `copy` because using the one in ANY did not make any sense (because of the way the C pointers were used). But the way this method had to be redefined depends on the final effective class.

So, to force (and be certain not to forget) to redefine the `copy` methods in my classes, I undefined it in the abstract class.

Good day,

Louis M

Bertrand Meyer

unread,
Jan 26, 2021, 2:32:37 PM1/26/21
to eiffel...@googlegroups.com, me...@inf.ethz.ch

Dear Alexey,

 

Very simple. B restarts the abstraction chain from A in a clean(er) slate.

 

In the ideal refinement scheme, abstract concepts come first, then you refine repeatedly. Simplistic textbooks mention only this. (Suggestions for non-simplistic textbooks will be provided on request.) In practice, the design process is often not perfect; more yoyo. You alternatively think of good abstractions and good implementations but not always in that order.

 

There is an illuminating – old but still relevant – article by David Parnas entitled (approximate title from memory, I am writing this offline) “A rational design process, and how to fake it”. Every programmer should have read it. The title is clear enough: it’s OK if your design process is messy and tortuous, as long as you are able to reconstruct a coherent design ex post facto.

 

In the case at hand, sometimes you write a nice concrete class A only later to understand that it is just one implementation of a more general concept B. The generally commendable action at that point is to produce a deferred class B embodying the abstraction, put into it the essential features of A in deferred form, then rewrite A to inherit from B and effect the relevant features. But sometimes you cannot do this. A might be someone else’s class, and you do not have the authority to change it (and you certainly don’t want to clone it, the supreme crime in software development). Even if you could in principle change A, you might not want to, for example out of fear of creating incompatibilities if A is already used in lots of existing software. It would be a pity to restart the refinement chain from scratch. Instead you can  start an upward segment of the yoyo, using undefinition to restore in B some or all of A’s lost virginity. Such  process is less perfect than the one-directional refinement ideal, but can be a good tradeoff between abstraction, reusability and backward compatibility.

 

Although simple, this reasoning may be too subtle for your “single-inheritance minded” friends.

 

The main everyday application of undefinition does remain, as other writers have explained, a tool for multiple inheritance: inheriting two or more competing features in an effective (implemented) form from different parents, and undefining all but one, whose implementation from takes over for the new class and any subsequent refinement of it.

 

-- BM

Peter Gummer

unread,
Jan 26, 2021, 7:12:48 PM1/26/21
to 'Alexander Kogtenkov' via Eiffel Users
Hi Alexey,

This is something that the C# folks should accept, because C# permits it too. I just tried it.

public class A
{
protected virtual void Foo() {}
}

public abstract class B : A
{
protected abstract override void Foo();
}

No complaints from the C# compiler!

https://stackoverflow.com/questions/8905432/what-is-the-use-of-abstract-override-in-c discusses this, including a response from a former member of the C# compiler team which links to an article that he wrote ten years ago:


- Peter

Ian Joyner

unread,
Jan 26, 2021, 8:52:13 PM1/26/21
to Eiffel Users
I was thinking following the discussions about some inheritance pattern into which the father I am has an ability to write, my children not having it still but inheriting from me.”

I think this is a case of over anthropomorphism. The inheritance relationship is much tighter in OO. Perhaps a little like Russian Dolls, except the superclass – being the innermost doll – and other dolls cannot be removed from the outermost doll. So they are not separate entities. Whereas human children as separate entities from parents.

The other difference is that classes and inheritance describe the patterns on which actual objects are instantiated. The concept of the thing needs to be separated from actual things.

Type inheritance is the is-a relationship, but children and parents, the has-a relationship.

Ulrich Windl

unread,
Jan 27, 2021, 2:10:38 AM1/27/21
to eiffel...@googlegroups.com
Hi!

Yes, there are two ways to learn a lot about a language:
1) Listen what the experts say, but that's just spreading knowledge.
2) Gain new insights by writing a language compiler that does things wrong. That's the way to gain new knowledge.

Of course #3 is for the "poor average guys": Make your own design and programming errors ;-)

Regards,
Ulrich

>>> Alexey Kanatov <alexey.v...@gmail.com> schrieb am 26.01.2021 um 15:33 in
Nachricht <eb2c980d-4a0a-4665...@googlegroups.com>:
> email to eiffel-users...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/eiffel-users/eb2c980d-4a0a-4665-acfd-23bf16
> e3edb9n%40googlegroups.com.



Richard

unread,
Jan 27, 2021, 7:14:54 AM1/27/21
to Eiffel Users
In variation to your thoughts, think of the OO superclass as your DNA, which gets inherited by the offspring with variations, and they have multiple inheritance, sharing their mothers DNA too, then on to the grandchildren etc. That makes up for the instantiation.

Alexey Kanatov

unread,
Jan 27, 2021, 11:13:08 AM1/27/21
to Eiffel Users
Gentlemen - thank you very much for your time and feedback! Probably we will not be able to change the world of "single-inheritance-minded" folks but you have strengthened the position of the real engineering approach to the design process. Thank you all once again, Cheers, Alexey

Karsten Heusser

unread,
Jan 27, 2021, 12:20:27 PM1/27/21
to Eiffel Users
Reproduction can be regarded as multiple inheritance.
With 'traditional reproduction' one half of [M]other's code (nc=nuclear DNA)
and one half of [F]ather's code gets undefined.
Furthermore, the father's mitochondrial DNA code (mt) is 'thrown away', i.e. undefined.
1/2 Fnc + 1/2 Mnc + 0 Fmt + 1 Mmt => 1 Baby_nc + 1 Baby_mt

In 'one-father-two-mothers reproduction' (three-parent babies, triple inheritance)
there is an additional undefinition pertaining to the mt code of mother 1:
1/2 Fnc + 1/2 M1nc + 0 Fmt + 0 M1mt + 1 M2mt => 1 Baby_nc + 1 Baby_mt.

There are several techniques that achieve the last result.
One of these, pronuclear transfer, can be seen (approximately)
as single inheritance with undefinition + effecting:
1 Baby_nc + 0 Baby_mt + 1 M2mt => 1 Baby_nc + 1 Baby_mt.

Do not take this post too seriously :-)
Regards,
Karsten

Ulrich Windl

unread,
Jan 28, 2021, 4:54:34 AM1/28/21
to eiffel...@googlegroups.com
>>> Karsten Heusser <karsten...@gmx.de> schrieb am 27.01.2021 um 18:20 in
Nachricht <d7da0168-5696-49c8...@googlegroups.com>:
> Reproduction can be regarded as multiple inheritance.

I'd object (with the little knowledge left from school biology): You don't have all the features of mother and father in your DNA; instead you have "parts of" father's and "part of" mother's DNA, but hopefully you got either DNA feature either from father or from mother. And unlike Eiffel, you can't "join" mother's and father's DNA into a single "DNA feature". So you actually "select" one from either mother or father...

Maybe let's just keep to Eiffel...

> With 'traditional reproduction' one half of [M]other's code (nc=nuclear DNA)
> and one half of [F]ather's code gets undefined.

It's not one half; it's "some proportion" AFAIK.

> Furthermore, the father's mitochondrial DNA code (mt) is 'thrown away',
> i.e. undefined.
> 1/2 Fnc + 1/2 Mnc + 0 Fmt + 1 Mmt => 1 Baby_nc + 1 Baby_mt

I don't know about that.

>
> In 'one-father-two-mothers reproduction' (three-parent babies, triple
> inheritance)
> there is an additional undefinition pertaining to the mt code of mother 1:
> 1/2 Fnc + 1/2 M1nc + 0 Fmt + 0 M1mt + 1 M2mt => 1 Baby_nc + 1 Baby_mt.
>
> There are several techniques that achieve the last result.
> One of these, pronuclear transfer, can be seen (approximately)
> as single inheritance with undefinition + effecting:
> 1 Baby_nc + 0 Baby_mt + 1 M2mt => 1 Baby_nc + 1 Baby_mt.
>
> Do not take this post too seriously :-)
> Regards,
> Karsten
>
>>
>
> --
> 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.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/eiffel-users/d7da0168-5696-49c8-8eb3-99bb8c
> 8eabb0n%40googlegroups.com.




Karsten Heusser

unread,
Jan 28, 2021, 6:38:41 AM1/28/21
to Eiffel Users
> It's not one half; it's "some proportion" AFAIK.
You are 50% right :-D
Girls get their nuclear DNA 50/50 from their parents.
Boys get a tiny amount less than 50% from their father
(and a little bit more from their mother)
as the Y chromosome is much smaller than the X chromosome.

> let's just keep to Eiffel
Agreed. I will shut up :-)
Best,
Karsten

Ian Joyner

unread,
Jan 28, 2021, 7:21:45 AM1/28/21
to Eiffel Users
> let's just keep to Eiffel
Agreed. I will shut up :-)”

Yes, the problem here is that in genetics, an object is inheriting characteristics in a random way from two other objects (children, irrespective of sex can look like father or mother).

However, in OO classes inherit from other classes, and objects are instantiated from those classes. Inherited characteristics are either inherited in entirety, or in the case of MI deliberately chosen.

So be careful of anthropomorphic analogies – they mislead rather than enlighten.

Ian

Larry Rix

unread,
Jan 28, 2021, 7:43:34 AM1/28/21
to Eiffel Users
In my little ole opinion, inherit was not the best word to use to describe the mechanics of what one class gets from another. There are a number of words that might work better to describe it.

For me, the far better word would have been DERIVE.

verb (used with object), de·rived, de·riv·ing.

  • to receive or obtain from a source or origin (usually followed by from).
  • to trace from a source or origin: English words derived from German.
  • to reach or obtain by reasoning; deduce; infer.
  • Chemistry. to produce or obtain (a substance) from another.
  • Grammar. to create (a new linguistic form) by adding affixes to or changing the shape of a root or base: The word “runner” is derived from “run.”
Look at the "grammar" definition (last one). isn't this fitting?

image.png

Reply all
Reply to author
Forward
0 new messages