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?
interface mother
predicates
execute:().
end interfaceclass mother:motherend classimplement mother
clauses
execute():-console::write("Exhibit the mother "). % step 1.end implementinterface child supports mother
domains
sex = male; female.
properties
sex:sex.
end interfaceclass child:childconstructors
new:(sex).
end classimplement 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 implementimplement main
open core
clauses
run():-X= child::new(child::male),X:execute().
end implement main
goal
console::runUtf8(main::run),
console::readchar()=_.
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:
interface legalPerson
predicates
execute :().
end interfaceclass legalPerson :legalPersonend classimplement 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 interfaceclass child :childconstructors
new :(sex).
end classimplement child
inherits legalPerson % Inherit the implementation from legalPersonfacts
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 childChild:execute(),Child:sex:= child::female,% Reassign child's gender to femaleChild:execute().
end implement main
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):
interface something
predicates
execute :().
end interface something
class kind1 :somethingend class kind1
class kind2 :somethingend 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
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:
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'
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.
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.
interface legalPerson
predicates
execute :().
end interfaceclass legalPerson :legalPersonend classimplement 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 interfaceclass child :childconstructors
new :(sex).
end classimplement child
inherits legalPerson
delegate execute/0to 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
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:
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:-