Re: LSP and subtype
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Mon, 31 Oct 2005 20:43:32 GMT
Responding to Kazakov...
Responding to Kazakov...
Turing-completeness is the context where the "software design" has meaning.
Only if one defines software as a Turing program. B-)
Care to give an alternative definition? (:-))
A Turing program is software designed to execute on a Turing Machine. So any software designed to work on a different sort of machine would qualify. For example, any multi-processor system with built-in hardware for synchronization where one doesn't treat each processor as an independent Turing Machine and leave it to the software to coordinate them would qualify.
Any "fuzzy" system where a viable computation result is Maybe.
By the time one is at the UML level one is so far removed from the hardware that the issue of Turing-completeness just isn't relevant to the application developer.
That is irrelevant. Design decisions of known problems are based on less fundamental premises, but that by no means devaluates the fundamentals. The difference is between "what" and "how":
1. What is the class of problems solvable using UML?
Actually UML has been used to solve non-computational problems.
Maybe, but these aren't my problems. My problem is software. In my view software is about computation.
The point is simply that UML has broader problem solving capability than Turing-based computation.
2. How can the problems above be solved using it?
You cannot design a car violating the law of energy conservation, no matter which tools you might wish to apply. Perpetuum mobile is in the class of problems, the language of physics cannot describe.
Ah, but Physics isn't in question here. Turing is only relevant if one wants to solve the problem on a Turing machine.
Nope. Turing completeness is about a definite class of computational problems one can solve.
A definite class of computational problems that is /defined/ based on whether they can be solved on a Turing Machine. B-)
There are other alternative ways of solving a given problem that don't involve Turing machines.
Do you mean analogue computing, quantuum computing? Anyway that's outside the scope of what presently is understood under "software." And I doubt that UML would be any great for those...
One can't tell until a Quantum Machine is defined with the same rigor (and utility) of a Turing Machine. However, once such a definition is available, a priori I see no bar since UML is independent of the computing environment. That is, whatever paradigm equivalent to 2GL/3GL programs that one ends up using for quantum logic, I suspect an OOA solution will be mappable into it.
[Caveat: I have no clue what the current state of quantum machine theory is today. AFAIK it is still an academic curiosity. However, I would not expect to get a lot of rigorously useful mathematical models to appear until somebody actually builds the equivalent of Babbage's machine that actually uses something resembling the basic principles.]
That was my original point about Turing being about How one implements the solution. UML could provide problem descriptions for implementations in /either/ Turing or non-Turing environments.
That is irrelevant here. Either UML can precisely define any algorithm a Turing machine is able to run or not. I can describe anything and everything using single word "eh". So what?
You cannot ride on two horses. Either UML is a language for computations or not.
It isn't a language for computation in the sense of a 3GL; it is a language for OO problem solving. If I then implement the solution in a Turing environment, then the implementation must solve it in a Turning manner. But if I implement the solution in some other environment, then the implementation must solve it in the manner of that environment. That's the point of having a 4GL that describes the solution in a manner that is abstract enough to be independent of the computing environment.
BUT. That holds no longer you needed to look *into* these blocks. You cannot, if your language is weak. The beauty and power of 3GLs is that you can descend the abstraction ladder down to bits and triggers within the *same* language. The problem of 4GLs is that there is a firewall between abstraction layers, the designer cannot bridge. 4GLs are sufficiently weaker than 3GLs. It is a systematic defect, especially for modern software systems which represents a wild mix of dozens application domains.
Turn that around. Why would anyone want to look into those blocks if the transformation was correct and optimal?
Because it is not! We have clarified that UML is not Turing-complete. That explicitly means that there exist problems which cannot be solved in UML. Period. A direct implication from this is that if I wished to use UML (as a language) to solve such problem I would be forced to look into the blocks.
Not quite. I said I didn't know whether UML was Turing-complete or not and, furthermore, that I didn't care because I never have to think about Turing-completeness at the application development level in UML.
In a translation environment it is the job of the transformation engine to optimize for nonfunctional requirements in the computing environment in hand. That's what it does -- just like a 3GL compiler. Since the late '90s the commercial transformation engines do a pretty good job. That may imply Turing-completeness for UML but I don't see that it proves anything.
However, it is a fait accompli that transformation engines do produce correct code and they do optimize even though the UML model is essentially devoid of 3GL type systems. So my question still stands: why would one want to look inside their "blocks"?
For example, consider an asynchronous OOA/D solution that is implemented as a synchronous solution. Synchronous communication is, indeed, a special case of asynchronous and the conversion is unambiguous. However, the actual implementation is correct only provided certain conditions are met in the implementation environment (e.g., external stimuli are serialized and can be "popped" when the software solution is ready). It is those conditions that ensure correctness of the synchronous solution. Thus it would be futile to argue that the original asynchronous solution was synchronous just because it /might/ be implemented synchronously. If the execution conditions are different, then the asynchronous solution is still correct but it is no longer compliant with the notion of synchronous processing (i.e., it is not "synchronous-complete").
This is a good example which illustrates my point. The key question here is in which language the constraints making asynchronous synchronous are described? Note also that this is a substitutability issue again: when the class of models A is pretended to be invariant to T, then you have to leave the safe ground of specific A and judge about a set of all possible combinations {A,T}.
In translation, that is done automatically by the transformation engine in the same general way that a 3GL compiler optimizes the platform instruction set.
This cannot be done automatically.
You keep saying things like this but the fact is that commercial transformation engines do such optimization once the nonfunctional requirements are defined. And the resulting code will work correctly. And they have been doing it for nearly two decades.
That is nontrivial because of the complexity of the computing space but there is no theoretical bar to doing so; it's just a representation mapping problem that is similar to a 3GL compiler's.
First you have to be able to get just any solution. Continuing my example, let's do Gauss method first. Iterations and sparse matrices will follow later. (:-))
Again, those sorts of mathematically defined algorithms would never be directly addressed in an OO application because they are defined outside the domain of the problem in hand.
[ OO application? Do we OO for the sake of OO? ]
The primary goal of the OO paradigm is to provide maintainability.
It is to have better way of handling growing complexity.
That applies to all software development paradigms; it is like saying that the most important characteristic of OO programs is that they should execute correctly. I am talking about what distinguishes the OO paradigm from other software development paradigms (i.e., the decision criteria for using OO development rather than some other paradigm).
Maintainability is only an issue for requirements that are volatile over the life of the application. The volatile requirements are those that are unique to a specific problem. (Requirements that are common to many problems are less volatile because then stability is of value in in coordinating the problem spaces themselves so volatility is already avoided in the problem space.)
I disagree.
1. Most volatile requirements are observed for most trivial and common problems. It is a question of customer expectations, education level, business models etc.
Only when it is the local business rules, which is my point here. F=ma is about as simple as one gets but it is independent of any particular ME problem one might face. And one can incorporate complexities like coefficients of friction in to the problem in a systematic way that is also independent of any particular ME problem. The volatile requirements only enter the picture when one needs to deal with specifics of the problem in hand, such as determining what masses and accelerations are involved.
2. Even negligible variations of the requirements on the solutions of universal problems have a much greater impact. Example: Y2K, 32->64 bit shift etc.
The issue is /whether/ there will be changes in requirements and how likely they are, not the impact (per se). If such changes are likely, then one wants to design the software so that the impact is minimal when they occur, regardless of the magnitude of the impact. That's because one wants to make /all/ changes easy. OTOH, if the requirements are not going to change, then one does not care about the impact of change, regardless of how vast it would be IF it occurred. [Within limits; one still has Pascal's Wager to worry about. B-)]
But for encoding individual mathematical algorithms themselves the OO paradigm is overkill. Since the algorithms are stable by mathematical definition, the main benefit of OO development, maintainability, is irrelevant.
Even if algorithms were stable (they are not), in numerical applications there is still a great need for reuse and generic programming. This is exactly what OO is good for, and it is exactly the realm where substitutability problems become real ones. The very notion of "numerical algorithm" in computational context is unthinkable without ADTs. This is an excellent example of object-procedural dualism. [ It was long time believed that generic programming should be done using templates. Unfortunately STL contributed much to that wrong belief. ]
That's only true if one needs to make choices among individual algorithms. If I want to provide a general optimization package, it would have an assortment of operations research techniques at its disposal (linear programming, dynamic programming, monte carlo, etc.). Deciding which approach was the best to use _for a particular problem_ is a complex decision based on the nature of the problem in hand. Can it be expressed as a network flow problem? Is enough physical memory available? Does the problem involve PDFs? And whatever. That sort of decision making based on the specific problem details -- which can change from one execution to the next -- is a fine task for an OO development.
But the OR algorithms themselves are completely invariant WRT to the specific problem because they are mathematically defined. They will execute exactly the same way regardless of which particular problem one has in hand. So one wants to encapsulate the algorithm itself and reuse it across many problems. For that sort of pure, invariant computation other software development paradigms are more intuitive and less verbose, so one should realize those algorithms outside the OO paradigm.
There is simply no alternative than to make Matrix an ADT. Further there is
no opposition between functional and OO approaches. One should just realize
that the idea of only stateful objects was wrong.
Au contraire! As soon as one makes functions first class objects one has broken the OO paradigm severely. There is a huge difference between an object that happens to have only behavior responsibilities and a function that is a first class object.
Any object can be viewed as a function. As I said it is dual.
Never, ever in an OOA/D context! Imposing that view on an OO application just invites the traditional implementation specification dependencies that plagued procedural programming. One can write procedural programs without such dependencies but it is very tough to do and depends to a great degree on the developer skill level. The OOA/D paradigm eliminates those dependencies by focussing on a different construction mindset where one does not think in terms of functions at all.
To the extent that both the OO and procedural paradigms provide quite different solutions to the same problem, they are duals. But the developer must choose one up front and stick to it. This is quite analogous to the Primal/Dual Revised Simplex linear programming algorithm. The algorithm alternates between manipulating primal and dual solutions. But /all/ manipulations are done in one view or the other; in effect the algorithm completely converts one representation to the other before doing manipulations. (In practice the package maintains both views and just transfers results between them.) For software development, one doesn't get to hop that easily between views because the entire construction paradigm is based upon a single view.
The core of the OO paradigm is problem space abstraction based on /identifiable/ problem space entities. Those entities may have knowledge or behavior or both, but the object abstraction must be based on the entity as a whole, not individual properties.
So? Function is indivisible. You can consider it as an object with one message "call me." In modern languages you cannot say whether X(Y) is an object (dual to a call to constructor) or a function call (dual to the result object.) It is the types which matter. In 2GL languages functions were singletons, that excluded them from OO, not the fact that they are functions.
You're got to get out of the mud of 3GL type systems; there's a whole other world beyond them. B-) It doesn't matter what is /possible/ to do with a 3GL type system. In the OOA/D paradigm one abstracts problem space entities, not functions.
[The mapping to functions can only exist at the object property level. In fact, using the traditional distinction between 'function' and 'procedure', at the OOA/D level only knowledge attribute accessors can even map to functions; behavior responsibilities map to procedures.]
[Logical indivisibility also comes into play. In the OO paradigm ones has a very flexible view of logical indivisibility whose granularity shifts with context. However, at a fundamental level there are three levels of abstraction for logical indivisibility: subsystems, which are implemented with multiple objects; objects, which are characterized with multiple responsibilities; and responsibilities, which capture atomic, self-contained properties. So the expectation is that at the object level of abstraction the entity will have multiple responsibilities. That provides a systematic mechanism for managing complexity through decomposition, but it is a very different mechanism than the traditional functional decomposition as employed in procedural or functional programming. Among other things any OO application only has three levels of decomposition.]
What you have described is actually 2.5GL! Data decomposition and procedural decomposition are notions of the past. IMO, OO is about "type decomposition." Responsibilities are associated with abstract instances of types, rather than with individual procedures or data members.
I don't think so. 3GLs are based upon indefinite nesting of behavior through functional decomposition where logical indivisibility is only resolved at the language operator level. The OOPLs wrap more sophisticated types around that, but the basic paradigm is still procedural block structuring and scoping.
What I described above is conceptually a quite different and much more flexible view of logical indivisibility. One can map it unambiguously into 3GL implementations but it requires a fundamentally different intellectual approach to construction.
----------- Now I think I can formulate our disagreements, as I see it. The key issue is that you in your framework are trying to get rid of types. In my eyes this effectively moves you back to 2GLs, actually away from OO.
I'm not trying to get rid of types; in OOA/D they are already gone. That, among other reasons, is why UML is a 4GL rather than a 3GL. (The only appearance of types in OOA/D lies in knowledge attribute ADTs.) Type systems just represent a particular implementation mechanism for abstract 4GL OOA/D solutions at the 3GL level.
FSM is an important indicator here. Naming individual states "objects", is not enough to be OO. It is OO only when groups of states are. Further when groups of groups are identified as abstractions. [ Important note: all this is considered in the narrow context of programming languages. I didn't mean OO as a religion, philosophy or even methodology. ]
FYI, one does not name FSM states as objects in OOA/D. One employs an FSM to describe the sequencing constraints among /all/ of an object's behavior responsibilities. That is, one creates one FSM per object.
The problem with your parenthetical remark is that it depends upon a restricted definition of 'programming language'. UML is also a programming language; it is just at a much higher level of abstraction than the 3GLs where type systems aren't very relevant.
************* There is nothing wrong with me that could not be cured by a capful of Drano.
H. S. Lahman hsl@xxxxxxxxxxxxxxxxx Pathfinder Solutions -- Put MDA to Work http://www.pathfindermda.com blog: http://pathfinderpeople.blogs.com/hslahman (888)OOA-PATH
.
- Follow-Ups:
- Re: LSP and subtype
- From: Dmitry A. Kazakov
- Re: LSP and subtype
- Next by Date: Re: Message-based vs. method-based interaction [was: Re: LSP and subtype]
- Next by thread: Re: LSP and subtype
- Index(es):
Relevant Pages
|
|