Do you know of any coding method that would help the compiler to warn me if I might have forgotten to implement some EXPECTED predicate or fact -- rather than wait until run time to report a message to that effect?
Consider the following code:-
interface reproduction
properties
type:string.
predicates
perform:().
end interface reproduction
class reproduction:reproductionend classimplement reproduction
facts
type:string:="UNDEFINED".
clauses/*
The use of This keyword allows the general method of reproduction to behave differently for
ford different stages of reproduction -- which is great*/
perform():- stdio::write("The process being performed is ",This:type).
end implement reproduction
/*
***************************************************************/interface fertilization supports reproduction end interfaceclass fertilization:fertilizationend classimplement fertilization inherits reproduction
facts
type:string:="FERTILIZATION".
clauses
new():-reproduction::new().
end implement fertilization
/*
***************************************************************/interface incubation supports reproduction end interfaceclass incubation:incubationend classimplement incubation inherits reproduction
facts/*
I HAVE FORGOTTEN TO IMPLEMENT THE PROPERTY reproduction::type:string FOR THE
INCUBATION CLASS*/clauses
new():-reproduction::new().
end implement incubation
/*
***************************************************************/implement main
clauses
run():-
console::init(),Process= incubation::new(),Process:perform(),
console::readchar()=_.
end implement main
goal
mainExe::run(main::run).
The code will run correctly but with the message that "The process being performed is UNDEFINED" and no warning at all. I understand the behavior, resulting from inheritance. However, I would like some sort of warning as early as compile time. Any help?
Thanks Martin; your input has helped me to code the following situation (which is part of a large project).....
Expressions of all types must be able to make copies of themselves, i.e., all must implement predicated copy()->expression. A secondary expression is made of children, which are expressions too. To make a copy of a secondary expression, you first make copies of the children; then use the children to make a copy of the secondary. So, all secondary expressions must implement these 2 predicates:-
children()->expression* and
copy(expression*)->expression.
Here is the code, including the magic statement I learnt from Martin.
interface expression
predicates
copy:()->expression.
end interface expression
class expression :expressionend class expression
implement expression
clauses
copy()=_:-errorexit(0).
end implement expression
interface secondary supports expression
/*
All classes that support the secondary interface must implement these predicates*/predicates
children:()->expression*.
copy:(expression*)->expression.
end interface secondary
class secondary :secondaryend class secondary
implement secondary inherits secondary_support
clauses
children()=_:-errorexit(0).
copy(_)=_:-errorexit(0).
end implement secondary
interface range supports expression
end interface range
class range :rangeend class range
implement range
clauses
copy()=range::new().
end implement range
interface function supports secondary
end interface function
class function :functionend class function
implement function inherits secondary_support
/*
You will get a compile error if you forget to implement any of the secondary predicates here*/end implement function
interface secondary_support supports expression
end interface secondary_support
class secondary_support :secondary_supportend class secondary_support
implement secondary_support
clauses
copy()=Copy:-/*
This conversion is the magic I have learnt from Martin*/Secondary= convert(secondary,This),Children= list::map(Secondary:children(),{(Child)=Child:copy()}),Copy=Secondary:copy(Children).
end implement secondary_support
interface reproduction
predicates
perform :().
properties
type :string.
end interface reproduction
/****************************************************************/interface reproductionSite
propertiesfrom reproduction
type
end interface reproductionSite
/****************************************************************/interface reproductionSupport
predicatesfrom reproduction
perform/0end interface reproductionSupport
class reproductionSupport:reproductionSupportconstructors
new :(reproductionSite Site).
end classimplement reproductionSupport
facts
site :reproductionSite.
clauses
new(Site):-
site :=Site.
clauses
perform():-
stdio::write("The process being performed is ", site:type).
end implement reproductionSupport
/****************************************************************/interface fertilization
supports reproduction
end interfaceclass fertilization:fertilizationend classimplement fertilization
supports reproductionSite
inherits reproductionSupport
facts
type:string:="FERTILIZATION".
clauses
new():-
reproductionSupport::new(This).
end implement fertilization
/****************************************************************/interface incubation
supports reproduction
end interfaceclass incubation:incubationend classimplement incubation
supports reproductionSite
inherits reproductionSupport
facts
type:string:="INCUBATION". % When this line is commented out, compiler throws errors.clauses
new():-
reproductionSupport::new(This).
end implement incubation
/****************************************************************/implement main
clauses
run():-Reproduction= incubation::new(),Reproduction:perform(),_= console::readchar().
end implement main
goal
console::runUtf8(main::run).
Yes, very good. You have got the pattern absolutely correct.
I have taken this mail as a discussion of principles. Because actually the "reproduction" example is far to simple to require such a complex solution at all: You may notice that you can also move the type fact into the support class, and once you have done that the only thing left in the "fertilization" and "incubation" classes is the different initialization of the base class.
All in all, this example is better solved with a single class having two different constructors:
interface reproduction
predicates
perform :().
properties
type :string.
end interface reproduction
class reproduction :reproductionconstructors
newFertilization :().
newIncubation :().
end class reproduction
implement reproduction
facts
type :string.
clauses
newFertilization():-
type :="FERTILIZATION".
clauses
newIncubation():-
type :="INCUBATION".
clauses
perform():-
stdio::write("The process being performed is ", type).
end implement reproduction
I now appreciate the value of "predicates from xxx" for implementing the Support pattern, but I don't understand the use of "supports" as used by Martin in the following code.
implement incubation
supports reproductionSite %What does this do?inherits reproductionSupport
facts
type:string:="INCUBATION". % When this line is commented out, compiler throws errors.clauses
new():-
reproductionSupport::new(This).
end implement incubation