In the UML specification there are plenty occurrences of the word "redefine". Not a single mention of what redefinition means. Perhaps it's too simple? Anyway, if someone could explain it even simpler that'd be just great.
Snapshot from UML 2.5.1, Intervals:
I found a clue to what it does using a modelling tool (Sparx Enterprise Architect). If having an interface sub-class of another interface, I get the option to "redefine" operations and attributes of that interface.
I made a wild guess on what it might be used for and redefined it with more parameters. The extra parameter represented the "number of output arguments" added by the Matlab compiler when compiling a Matlab function to a C# library. Then I went ahead and made another sub-class for CLI and redefined arguments accordingly (int return value, all inputs are strings).
The UML 2.5.1 defines redefinition in section 9.2.3.3 (page 100):
Any member (that is a kind of RedefinableElement) of a generalization of a specializing Classifier may be redefined instead of being inherited. Redefinition is done in order to augment, constrain, or override the redefined member(s) in the context of instances of the specializing Classifier.
For a feature such as an attribute, a property, or an operation:
Feature redefinitions may either be explicitly notated with the use of a {redefines <x>} property string on the Feature or implicitly by having a Feature which cannot be distinguished using isDistinguishableFrom() from another Feature in one of the owning Classifier’s more general Classifiers.
Suppose for example that you have a class Node with two attributes: from: Node[*] and to[*]: Node. You could then have a specialization FamilyMember (a node in your genealogy) and you could redefine the members: parent : FamilyMember[*] {redefines from} and child : FamilyMember[*] {redefines from}
Another example: you have a polymorphic class Shape with an abstract operation draw(). You can specialize that class into a class Circle that will have its own draw(). You could leave the redefinition implicit (just mentioning the operation), or you could be very explicit with draw() {redefines draw()}.
The abstract syntax diagrams apply UML to the UML metamodel. The redefinition have the same meaning, but it is explained in a shorter manner in section 6.
Let's take an example in your diagram: let's take IntervalConstraint:
IntervalConstraint inherits from Contraint. A Constraint is composed of a property specification:ValueConstraint (page 36), so IntervalConstraint inherits this property.
Your diagram tells that IntervalConstraint is composed of a property specialization: Interval that redefines the more general specification of the constraint. It's a redefinition, because it narrows down its type (fortunately, Interval inherits from ValueSpecification so there's no risk of inconsistency).
Related
How can I know if class A is an interface, an abstract class or a concrete class (super class)?
According to answers, there are no direct instances of A so I assume that is an abstract class.
However, in this second image :
B should also be an abstract, if the first theory is right... but it can't because in the last answer there are direct instances of B class.
If A would be abstract in image1 it would be shown with the name in italics and/or the string {abstract} next to it. This is not the case here. Therefore A can have direct instances. I guess there is a mistake in image1.
Please note that even if B in image2 would be abstract, it is meaningful to specify an instance of B. An instance specification is not an instance, and as such can be incomplete and abstract. An object will have complete features and a concrete class. For example I could have a red Basketball. In the model I might have an instance specification classified by Ball{abstract} and without a slot for the color, because I don't care which type and color it is. So any instance of Basketball or Handball will fit this instance specification.
As per UML specification, Section 9.2.3.2:
The isAbstract property of Classifier, when true, specifies that the Classifier is abstract, i.e., has no direct instances: every instance of the abstract Classifier shall be an instance of one of its specializations.
The notation is described a bit further, in Section 9.2.4.1:
The name of an abstract Classifier is shown in italics, where permitted by the font in use. Alternatively or in addition, an abstract Classifier may be shown using the textual annotation {abstract} after or below its name.
Neither of the two is indicated in the first diagram, so the answer is simply erroneous.
Note, one more indirect indication of the abstract class (though it is not directly mentioned, just comes from the general description) could be using a Generalization Set. There are a couple of notations used here, you can read about them in Section 9.7.4 (the entire Section 9.7 is about Generalization Sets). This notation also isn't used so still - there is nothing to indicate class A is abstract.
First diagram
You cannot deduct from the diagram if A is an interface, an abstract class or a concrete class:
A could be a concrete class that is further specialized by B and C
A could be an abstract class and B and C be abstract or concrete specializations. One would expect A to be in italic or followed with an {abstract} adornment, but these are not mandatory.
A could even be an interface under some circumstances. In this case, B and C would be specialized interfaces. This possibility has however a low probability because the «interface» keyword would be expected above A. This notation was not mandatory in earlier UML 2 versions but the current UML 2.5 requires it (see Axel's comment).
So if the UML notation would be used with all possible accuracy, A would be a concrete class, but you can objectively not be 100% certain.
Important note: the provided answer claiming that "there is no instance for A" is hearsay. No element in the diagram allows to draw this conclusion
Second diagram
We have seen that the answers to the first questions are flawed, and likewise, B is not necessarily an abstract class.
Important revelation: you need to know that b : B is possible even if B was abstract, because in an object diagram you may chose arbitrarily to show membership to one class, event if the object would be more specialized:
UML 2.5 - Section 9.8.3: An InstanceSpecification represents the possible or actual existence of instances in a modeled system and completely or partially describes those instances.
In case of doubt, a few lines later, you'll read:
The InstanceSpecification may represent: - Classification of the instance by one or more Classifiers, any of which may be abstract.
Keeping this in mind, the answers to the second diagram are all correct, whether B is abstract or not.
I am learning OOP concepts, which do not really have well-established definitions.
I heard different things about polymorphism and can not decide what is right.
Most people will say that it is a type-theory. Meaning that a function is able to accept multiple types of parameters that have something in common.
Ad hoc polymorphism is about different overloads of the same function.
Parametric polymorphism is generic functions.
Subtyping polymorphism is that if a function accepts a certain class as parameter, it can also accept its subclasses. (Of course only those can be passed as parameter which are not abstract but concrete).
There is a seemingly different definition. There are those who say polymorphism means that a function can have different implementations (morphs/forms).
In that sense...
- interface functions,
- abstract classes’ abstract functions,
- and virtual functions that can be overridden by the subtype
...are all considered polymorphic.
As I was told, polymorphism in this sense can be defined as having different results if the same function is called on different objects.
And adding to the confusion, someone said only virtual functions are polymorphic because they already have an implementation.
For me the first way I presented polymorphism and the second seem completely different, but maybe they both fit the definition of polymorphism and it is just me being unable to understand it.
So what is polymorphism in programming? Is it just a type-theory?
In this question I would like to refer to this question:
https://stackoverflow.com/questions/25163683/polymorphism-and-interfaces-clarification#=
It raises almost the same problem, but I could not really make out the conclusion.
Yes and No.
Yes, in classic inherited languages it works that way.
No, since in other languages the calling of a method on an object might be dynamically resolved. (e.g. by runtime code searching in a list of objects as a field, so called aggregate in COM terms)
IOW that that method exists in the type of the object is not defined in type theory. At least not universal. The language might not even be typed.
For a statically inherited object model, it is however true. IOW Typing (subtyping/inheritance, de concept of virtual methods) is an implementation of polymorphism in languages with such object model. But not all languages do.
Some have dispatch polymorphism, and can add methods runtime (like objective C) or figure out of the method exists at all (e.g. COM IDispatch )
The classic test of polymorphism is the "the duck quacks". Where you have a generic "animal" and call a method for "makesound", and if you assigned a duck it "quacks". So you call a method (pass a message in old OO jargon) on an generic object, and you get the behaviour of the more specialized object assigned to it.
What constitutes a "generic" object depends on the language. In statically inherited languages the generic object must have the method declared, sometimes with special modifiers (virtual) to signal overridability.
In other languages the generic object can be the root object, and the runtime will figure out if it has a makesound method.
I'm using Visual Paradigm for UML
I'm drawing a class diagram and I want to mark a struct (instead of a class). There is no such thing there, but instead I found smt called <<primitive>>.
What is it?
Is it a dumb-data-holder?
Kind regards
The «primitive» stereotype means the type has no internal structure, and is defined externally to UML. An integer would be a primitive; its operations are defined by the implementation language.
The «datatype» stereotype is analogous to a C# struct or a value type - instances of the type may have internal structure, but do not have identity and are considered equal if the values of all their properties are equal. A complex number, with real and imaginary parts, would be a data type.
In Martin Odersky's recent post about levels of programmer ability in Scala, in the Expert library designer section, he includes the term "early initializers".
These are not mentioned in Programming in Scala. What are they?
Early initializers are part of the constructor of a subclass that is intended to run before its superclass. For example:
abstract class X {
val name: String
val size = name.size
}
class Y extends {
val name = "class Y"
} with X
If the code was written instead as
class Z extends X {
val name = "class Z"
}
then a null pointer exception would occur when Z got initialized, because size is initialized before name in the normal ordering of initialization (superclass before class).
As far as I can tell, the motivation (as given in the link above) is:
"Naturally when a val is overridden, it is not initialized more than once. So though x2 in the above example is seemingly defined at every point, this is not the case: an overridden val will appear to be null during the construction of superclasses, as will an abstract val."
I don't see why this is natural at all. It is completely possible that the r.h.s. of an assignment might have a side effect. Note that such code structure is completely impossible in either C++ or Java (and I will guess Smalltalk, although I can't speak for that language). In fact you have to make such dual assignments implicit...ticilpmi...EXplicit in those languages via constructors. In the light of the r.h.s. side effect uncertainty, it really doesn't seem like much of a motivation at all: the ability to sidestep superclass side effects (thereby voiding superclass invariants) via ASSIGNMENT? Ick!
Are there other "killer" motivations for allowing such unsafe code structure? Object-oriented languages have done without such a mechanism for about 40 years (30-odd years, if you count from the creation of the language), why include it now?
It...just...seems...dangerous.
On second thought, a year layer...
This is just cake. Literally.
Not an early ANYTHING. Just cake (mixins).
Cake is a term/pattern coined by The Grand Pooh-bah himself, one that employs Scala's trait system, which is halfway between a class and an interface. It is far better than Java's decoration pattern.
The so-called "interface" is merely an unnamed base class, and what used to be the base class is acting as a trait (which I frankly did not know could be done). It is unclear to me if a "with'd" class can take arguments (traits can't), will try it and report back.
This question and its answer has stepped into one of Scala's coolest features. Read up on it and be in awe.
Structural types are one of those "wow, cool!" features of Scala. However, For every example I can think of where they might help, implicit conversions and dynamic mixin composition often seem like better matches. What are some common uses for them and/or advice on when they are appropriate?
Aside from the rare case of classes which provide the same method but aren't related nor do implement a common interface (for example, the close() method -- Source, for one, does not extend Closeable), I find no use for structural types with their present restriction. If they were more flexible, however, I could well write something like this:
def add[T: { def +(x: T): T }](a: T, b: T) = a + b
which would neatly handle numeric types. Every time I think structural types might help me with something, I hit that particular wall.
EDIT
However unuseful I find structural types myself, the compiler, however, uses it to handle anonymous classes. For example:
implicit def toTimes(count: Int) = new {
def times(block: => Unit) = 1 to count foreach { _ => block }
}
5 times { println("This uses structural types!") }
The object resulting from (the implicit) toTimes(5) is of type { def times(block: => Unit) }, ie, a structural type.
I don't know if Scala does that for every anonymous class -- perhaps it does. Alas, that is one reason why doing pimp my library that way is slow, as structural types use reflection to invoke the methods. Instead of an anonymous class, one should use a real class to avoid performance issues in pimp my library.
Structural types are very cool constructs in Scala. I've used them to represent multiple unrelated types that share an attribute upon which I want to perform a common operation without a new level of abstraction.
I have heard one argument against structural types from people who are strict about an application's architecture. They feel it is dangerous to apply a common operation across types without an associative trait or parent type, because you then leave the rule of what type the method should apply to open-ended. Daniel's close() example is spot on, but what if you have another type that requires different behavior? Someone who doesn't understand the architecture might use it and cause problems in the system.
I think structural types are one of these features that you don't need that often, but when you need it, it helps you a lot. One area where structural types really shine is "retrofitting", e.g. when you need to glue together several pieces of software you have no source code for and which were not intended for reuse. But if you find yourself using structural types a lot, you're probably doing it wrong.
[Edit]
Of course implicits are often the way to go, but there are cases when you can't: Imagine you have a mutable object you can modify with methods, but which hides important parts of it's state, a kind of "black box". Then you have to work somehow with this object.
Another use case for structural types is when code relies on naming conventions without a common interface, e.g. in machine generated code. In the JDK we can find such things as well, like the StringBuffer / StringBuilder pair (where the common interfaces Appendable and CharSequence are way to general).
Structural types gives some benefits of dynamic languages to a statically linked language, specifically loose coupling. If you want a method foo() to call instance methods of class Bar, you don't need an interface or base-class that is common to both foo() and Bar. You can define a structural type that foo() accepts and whose Bar has no clue of existence. As long as Bar contains methods that match the structural type signatures, foo() will be able to call.
It's great because you can put foo() and Bar on distinct, completely unrelated libraries, that is, with no common referenced contract. This reduces linkage requirements and thus further contributes for loose coupling.
In some situations, a structural type can be used as an alternative to the Adapter pattern, because it offers the following advantages:
Object identity is preserved (there is no separate object for the adapter instance, at least in the semantic level).
You don't need to instantiate an adapter - just pass a Bar instance to foo().
You don't need to implement wrapper methods - just declare the required signatures in the structural type.
The structural type doesn't need to know the actual instance class or interface, while the adapter must know Bar so it can call its methods. This way, a single structural type can be used for many actual types, whereas with adapter it's necessary to code multiple classes - one for each actual type.
The only drawback of structural types compared to adapters is that a structural type can't be used to translate method signatures. So, when signatures doesn't match, you must use adapters that will have some translation logic. I particularly don't like to code "intelligent" adapters because in many times they are more than just adapters and cause increased complexity. If a class client needs some additional method, I prefer to simply add such method, since it usually doesn't affect footprint.