classes a and b are defined as follows:
as you see both classes have the axiom :prop2 some rdfs:literal
I need to define class c based on a and b (e.g by using and , or, not) so that has this axiom as its definition.
You could define c as a and b - because the class prop2 some rdfs:Literal will always belong to the intersection of the two classes.
However it would be a lot more intuitive to declare c subclass of prop2 some rdfs:Literal and then a subclass of c and b subclass of c. Is there a reason that forces you to define c in terms of a and b and not the opposite?
Related
How do you declare a variable to be the same type as a type parameter used to instantiate a generic class? The following code does not compile:
class
TEST [G, H -> INTEGER]
feature
f (i: INDEXABLE [G, H])
local
y: H
do
y := i.lower -- Type error here.
end
end
The compiler says that the source of the assignment is not compatible with target.
In the current implementation, INDEXABLE [G, H] inherits from TABLE [G, INTEGER]. As a result, lower is of type INTEGER, not H. And INTEGER does not conform to the formal generic type H of the class TEST. This explains the error.
To me, it looks like a mistake in the declaration of class INDEXABLE. It should inherit from TABLE [G, H] instead. Then, the example code would compile.
Type anchoring can be used in those cases:
feature
f (i: INDEXABLE [G, H])
local
y: like i.lower
do
y := i.lower
end
Sometimes a generic type is not used as return type of any accessible feature on a class, so in those cases I like to declare a fake feature specifically to allow anchoring:
class SOME_CLASS [G]
feature
generic_type_anchor: G
do
check
for_anchoring_only: False
-- This method should never actually be called, only used as an anchor in type declarations
end
end
This is particularly useful with complex inheritance trees or when descendant classes close the generics, in which case the correct type is not apparent from the declared type. Personally I tend to use type anchoring whenever values are semantically related as this helps expressing intent, simplifies refactoring (as there are fewer repetitions of types which by definition must match) and facilitates covariance.
Also as a side-note, expanded types (like INTEGER) cannot be used polymorphically (you need a reference for that; if class A is expanded and class B [expanded or reference] inherits A, you could not assign a value of type B to a variable of type A; inheritance from expanded types is implicitly non-conforming), and moreover the compiler disallows inheriting from basic expanded types (INTEGER, BOOLEAN, REAL_64, etc.), therefore the generic constraint in your example makes no sense because H could never be anything but INTEGER.
Repeatedly inheriting from 2 classes having the same parent, I fall into the classic case of inheriting 2 times of the same attribute. I'd like to merge the 2 attributes into one and tried to do it with an undefine, but it gets me a compile error.
The other solution I see is renaming the attribute from one of both parents, but as I understand each instance of my D class would have an useless attribute which is not what I want...
Error: Undefine subclause lists name of frozen feature or attribute or
C external.
What to do: unless you can change the status of the feature in the parent,
remove its name from Undefine subclause since it cannot be undefined.
How to merge 2 attributes from repeatedly inherited classes
class A
serial: STRING
end -- class A
class B
inherit
A
end -- class B
class C
inherit
A
end -- class C
class D
inherit
B
undefine
serial -- error seems to appear here in that case
end
C
end -- class D
In case it's two unrelated attributes (not coming from the same parent) that you want to merge, you should redefine both of them:
class A
feature
serial: STRING
end
class B
feature
serial: STRING
end
class C
inherit
A
redefine
serial
end
B
redefine
serial
end
feature
serial: STRING
end
As you already saw, the compiler will not let you undefine an attribute, even when the goal is to merge it with another attribute.
There is no reason to undefine a feature that is going to be merged with the same version coming from a different inheritance path. In the example, the attribute serial is not changed in B, C, and D. Therefore, inheriting from B and C without any adaptation is OK:
class D inherit
B
C
end
Suppose I have
:hasParent rdfs:subPropertyOf :hasAncestor .
:hasAncestor rdf:type owl:TransitiveProperty .
This has the satisfying result of inferring all true ancestor relationships given the parentage. But I'm surprised it doesn't have the negative side-effect of making :hasParent effectively transitive too. Doesn't p rdfs:subPropertyOf q mean p "inherits" q's meta-properties, including a owl:TransitiveProperty?
Seemingly asymmetrically, we see with A rdfs:subClassOf B and B :hasFriend C that A :hasFriend C also since A rdf:type B. Why doesn't this happen with sub-properties too?
Stanislav has already given a good answer to this question. What I want to address here is the idea mentioned in the comment that "inheritance of classes" are asymmetric with "inheritance of properties".
Object Orientation
(1) In object oriented programming languages, when class A inherits from class B, it means that the set of all the instances of class A is a subset of the set of all the instances of class B. Moreover, because attributes belong to a specific class, it means class A will have all the attributes of class B (i.e.
class A inherits all the attributes of class B).
(2) When class A has an attribute c of type C, it states (more or less) that there is an association c between classes A and C.
OWL/RDFS
(1) A big difference with OWL/RDFS is that properties do not belong to a class. When we say that A rdfs:subClassOf B, we say that the set A is a subset of B. It says nothing more. As an example if we have
B a rdfs:Class .
B rdfs:label "Label for class B" .
A a rdfs:Class .
A rdfs:subClassOf B .
class A will not "inherit" the label of class B.
(2) Properties in OWL/RDFS are specified between instances, not between classes. I have written about this in detail on my blog. When you state that P rdfs:subProperty R it means that the set of pairs of individuals in P is a subset of the set of pairs of individuals in R.
But Functional Properties are inherited...
No, they are not. It just seems so due to the semantics of functional properties. If we have a property R that is functional it means a satisfying assignment for R can be {(a,1), (b,2)}. That is the same subject cannot be linked to 2 different objects. I.e. you cannot have {(a,1), (a,2)}.
Now, if you have that P rdfs:subPropertyOf R, P is subset of R and thus P will be functional as well. I.e. if R = {(a,1), (b,2)} any subset of R will be functional as well.
Doesn't P rdfs:subPropertyOf Q mean P "inherits" Q's meta-properties,
including a owl:TransitiveProperty?
In general, no.
P rdfs:subPropertyOf Q means that ∀x∀y(P(x,y) → Q(x,y)) (1)
Q a owl:TransitiveProperty means that ∀x∀y∀z(Q(x,y) ∧ Q(y,z) → Q(x,z)) (2)
Unfortunately, (1) and (2) do not entail ∀x∀y∀z(P(x,y) ∧ P(y,z) → P(x,z)).
You can find a countermodel online:
By the way, a subproperty of a functional property is also functional.
I have a base class of which there are two subclasses. Let say, Base is the base class and A and B are subclasses. Let us have an individual, I, belongs to class A initially. Is it possible in OWL that the same individual starts belonging to class B (and stops belonging to class A) after satisfying the attributes of class B? Note that class A and B are disjoint.
If a class A is in composition relationship with class B , does it mean that the specific instance of B got via A should only be modifiable through class A not to break the data encapsulation of class A? Or, does composition imply only life-time bind, not the data encapsulation ?
class A
{
B itsB;
B* getB() {return &itsB);
}
void AnotherClass::anyOperation()
{
itsA->getB()->function(); // is this legal ?
}
Composition does not strictly specify the rules concerning whether a composed object should be allowed to be modified outside the composing class or not.
Encapsulation has to do with controlling access to the members defined in a class to outside world. In general ,fields of a class should not be directly accessible by outside code , if this tenet is followed , then the question of allowing it to be modifeid by outside code does not arise. Encapsulation and composition are not related in principle , so in your example , the fact that B is a composed into A itself does not dictate the rule that itsB should not be modifiable outside A.
However , you should think in terms of 1. Who owns the object itsB ? 2. Is it thread-safe to allow it to be modified outside A ? Is it breaking encapsulation ?
If B has public setter functions, the only way in C++ to ensure that nobody retrieves A's B through getB() and changes its value is for getB() to return a constant reference. If it returned a constant pointer, that just ensures that you don't change the pointer; you can still change the values inside the B that the pointer points to.
To mention my problem with different words:
The class A has mB and mC members , where A and B, A and C are in composition relationships.
B and C classes are in association relationship.
What would you say, if I want to link specific instance "mB" to specific instance "mC" (of class A), allowing them to communicate between themselves.
Would it mean to break the encapsulation provided by A for mB and mC ?