Page 1 of 1
Aborting an implementation and continue inheritance
Posted: 4 Aug 2015 9:13
by Peter Muraya
Hi,
I often encounter situations when I need to abort an implementation in favor of inheritance as shown in the following code. The gist of the problem is that when the
sex of the child is
female, I want it to exhibit the mother behavior; otherwise it exhibits its own. The mother behavior is rather simple here, but it can be a complex piece of code, so that code repetition is not an option. I have gone round this issue in more ways than one all of which I don't feel are elegant. Is there are formal mechanism in object-oriented programming for achieving this purpose?
Code: Select all
interface mother
predicates
execute:().
end interface
class mother:mother
end class
implement mother
clauses
execute():-console::write("Exhibit the mother "). % step 1.
end implement
interface child supports mother
domains
sex = male; female.
properties
sex:sex.
end interface
class child:child
constructors
new:(sex).
end class
implement child
facts
sex:sex:=erroneous.
clauses
new(Sex):-sex:=Sex.
execute():-execute(sex).
predicates
execute:(sex).
clauses
execute(female):-
/*
How do you abort this implementation and inherit the mother behaviour implemented in step 1?*/
mother::execute(). %invalid option.
execute(male):-
console::write("Exhit other behaviour").
end implement
implement main
open core
clauses
run() :-
X = child::new(child::male),
X:execute().
end implement main
goal
console::runUtf8(main::run),
console::readchar()=_.
Posted: 5 Aug 2015 9:47
by Thomas Linder Puls
In my world it is wrong to let child support mother, because children are not mothers.
The motivation for the question seem to be based on this "wrong" idea.
I find it vey difficult to advise good programming practice for something which is fundamentally bad design.
Your problem/question may be fully reasonable, but it will need another setup for my assistance.
Posted: 5 Aug 2015 10:58
by Martin Meyer
Yep, children are not mothers. We should always try to choose names in example code as intuitive as possible. To improve it, I propose renaming
mother to
legalPerson. Legal persons can be juridical persons (for instance joint-stock companies) or natural persons (as for example children). Assuming this renaming one way to get the example working out would be:
Code: Select all
interface legalPerson
predicates
execute : ().
end interface
class legalPerson : legalPerson
end class
implement legalPerson
clauses
execute() :-
console::write("I am some legal person\n").
end implement
%---
interface child
supports legalPerson
domains
sex = male; female.
properties
sex : sex.
end interface
class child : child
constructors
new : (sex).
end class
implement child
inherits legalPerson % Inherit the implementation from legalPerson
facts
sex : sex.
clauses
new(Sex) :-
sex := Sex.
clauses
execute() :-
execute(sex).
predicates
execute : (sex).
clauses
execute(female):-
legalPerson::execute(). % Call the predicate's implementation inherited from legalPerson
execute(male):-
console::write("I am a male child\n").
end implement
%---
implement main
open core
clauses
run() :-
Child = child::new(child::male), % Create a male child
Child:execute(),
Child:sex := child::female, % Reassign child's gender to female
Child:execute().
end implement main
Many regards
Martin
Posted: 5 Aug 2015 15:23
by Thomas Linder Puls
I am not sure if the example is better now
.
But I am sure it still doesn't help me to understand what kind of construction we are looking for.
The problem seems to be that given some arbitrary property (here whether sex is male or female) we either want to inherit something or use a reimplementation.
But that seems to suggest that we actually want to choose between two completely independent implementations (i.e. where none inherits from the other):
Code: Select all
interface something
predicates
execute : ().
end interface something
class kind1 : something
end class kind1
class kind2 : something
end class kind2
implement kind1
clauses
execute() :- stdio::write("kind1\n").
end implement kind1
implement kind2
clauses
execute() :- doSomehtingDifferent().
end implement kind2
class somethingFactory
predicates
mkSomething : (boolean Condition) -> something Something.
end class somethingFactory
implement somethingFactory
clauses
mkSomething(true) = kind1::new().
mkSomething(false) = kind2::new().
end implement somethingFactory
Posted: 5 Aug 2015 16:56
by Peter Muraya
Thanks Thomas and Martin.
I'm not sure I completely understand the issue Thomas is raising, but I think Martin's example solves my problem elegantly. The key is in the 2 statements:
Code: Select all
implement child inherits legalPerson % Inherit the implementation from legalPerson
and
Code: Select all
legalPerson::execute(). % Call the predicate's implementation inherited from legalPerson
In my code:-
I failed to explicitly state the inheritance (as I had not quite understood its significance for this purpose) and so the compiler raised the error message.
Undeclared identifier 'legalPerson::execute/0', the identifier is known as 'execute/0' in the interface 'legalPerson'
Now I understand it. Thanks again.
Posted: 5 Aug 2015 23:55
by Martin Meyer
The construction I've posted comes most close to your initial example. That's why you are happy with it at first sight. However in most cases in praxis such kinda construction imposes unnecessary complications. That's -I think- the issue Thomas is raising.
The complication, which is suspected of being unnecessary, is, that the child implementation contains explicite programming instructions to (conditionally) redirect calls to execute/0 to its parent-object's implementation. However better is, when the distribution of predicate calls to their implementations is accomplished implicitely, solely through the language's object-oriented features, i.e. mainly through supports and inherits qualifications.
Maybe, if you present the intentions of your code in sufficient detail, Thomas (or might be even me) can come up with a more appropriate object design than that of the version I have posted. In the simplest use case the construction, which Thomas has given above already, will be optimal to do the job.
Best regards
Martin
Posted: 7 Aug 2015 11:40
by Martin Meyer
Below a better version of the example. I suppose the construction is appropriate, provided it's required (for reasons which are not covered by below example code skeleton) that
- execute/0 predicate of class child inherits its implementation from parent object iff sex is female,
- property sex has input and output flow, i.e. sex is changeable after a child object has been created.
Code: Select all
interface legalPerson
predicates
execute : ().
end interface
class legalPerson : legalPerson
end class
implement legalPerson
clauses
execute() :-
console::write("I am some legal person\n").
end implement
%---
interface child
supports legalPerson
domains
sex = male; female.
properties
sex : sex.
end interface
class child : child
constructors
new : (sex).
end class
implement child
inherits legalPerson
delegate execute/0 to executeLegalPerson_fact
facts
executeLegalPerson_fact : legalPerson.
clauses
new(Sex) :-
sex := Sex.
clauses
sex(male) :-
executeLegalPerson_fact := This.
sex(female) :-
executeLegalPerson_fact := erroneous.
clauses
sex() =
if isErroneous(executeLegalPerson_fact) then
female
else
male
end if.
clauses
execute() :-
console::write("I am a ", sex, " child\n").
end implement
%---
implement main
clauses
run() :-
Child = child::new(child::male),
Child:execute(),
Child:sex := child::female,
Child:execute().
end implement main
Best regards
Martin
Posted: 7 Aug 2015 15:06
by Martin Meyer
It's even possible to have a standard object design, i.e. not delegating/redirecting anything, and at the same time (correspondingly) meet the requirements of the two bullets in my prior post, when object types
legalPerson and
child are made persistent. For an example of a modifiable vs. a persistent object type check out
setM vs.
setP in the PFC. This is a version of the example with persistent object types:
Code: Select all
interface legalPersonP
predicates
execute : ().
end interface
class legalPersonP : legalPersonP
end class
implement legalPersonP
clauses
execute() :-
console::write("I am some legal person\n").
end implement
%---
interface childP
supports legalPersonP
domains
sex = male; female.
predicates
setSex : (sex) -> childP.
predicates
getSex : () -> sex.
end interface
%---
class childP_male : childP
end class
implement childP_male
clauses
setSex(male) = This.
setSex(female) = childP_female::new().
clauses
getSex() = male.
clauses
execute() :-
console::write("I am a male child\n").
end implement
%---
class childP_female : childP
end class
implement childP_female
inherits legalPersonP
clauses
setSex(male) = childP_male::new().
setSex(female) = This.
clauses
getSex() = female.
end implement
%---
implement main
clauses
run() :-
Child_0 = childP_male::new(),
Child_0:execute(),
Child_1 = Child_0:setSex(childP::female),
Child_1:execute().
end implement main
Regards
Martin
Posted: 10 Aug 2015 16:59
by Peter Muraya
Hi Martin,
Thanks for the effort you take to understand a partially/poorly specified problem; I think your first example is clearer to me than the alternative, but I always learn something new from your coding, including this construct:-
Code: Select all
sex() =
if isErroneous(executeLegalPerson_fact) then
female
else
male
end if.
I guess this is a shorter form of:-
Code: Select all
sex() =X:-
if isErroneous(executeLegalPerson_fact) then
X=female
else
X=male
end if.
Posted: 11 Aug 2015 7:49
by Martin Meyer
yes, if-the-else expressions came as a new feature with build 7401.
I have learned by Thomas' answers to your questions already too.
Regards
Martin