Le Mon, 05 Nov 2012 21:33:54 +0100, Dmitry A. Kazakov
<mail...@dmitry-kazakov.de> a écrit:
>> A constant is just an easy‑and‑quick function, that's not the same as an
>> object.
> procedure Foo (Object : in T);
> here in T = constant T = immutable subtype of T = T - assignment - some
> other operations.
That's a place‑specific restriction, the client knows. That can't apply to
a derivation hierarchy. That's like a subtype, not a type as a member of a
class (a subtype of Integer is not a member of a fictitious Integer class).
Interesting note anyway. Thanks for that.
-- “Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University
On Monday, November 5, 2012 2:34:40 PM UTC-7, Hibou57 (Yannick Duchêne) wrote:
> a derivation hierarchy. That's like a subtype, not a type as a member of a
> class (a subtype of Integer is not a member of a fictitious Integer class).
But it is, isn't it?
Universal_Integer ⊃ Integer ⊃ Positive.
Therefore, Universal_Integer ⊃ Positive.
Universal integers are a fictitious class of integers and Positive is a subtype of Integer.
Le mardi 6 novembre 2012 00:45:21 UTC+1, Shark8 a écrit :
> On Monday, November 5, 2012 2:34:40 PM UTC-7, Hibou57 (Yannick Duchêne) wrote: > > a derivation hierarchy. That's like a subtype, not a type as a member of a > class (a subtype of Integer is not a member of a fictitious Integer class). But it is, isn't it? Universal_Integer ⊃ Integer ⊃ Positive. Therefore, Universal_Integer ⊃ Positive. Universal integers are a fictitious class of integers and Positive is a subtype of Integer.
Well try, but I pretty sure it's a wrong interpretation. Inclusion relation in a type hierarchy, is precely the opposite way. A type defines a set of possible values or states, a class is a set, but not the same set. Positives indeed belongs to the set of values specified by an Integer, but a Positive does not belong to the set fictitious set of class whose root type would be Integer.
And no, universal integer does not define a class, but a set of values.
More on "Inclusion relation in a type hierarchy, is precely the opposite way": a derived type has to cover a base type, and will probably do more, but in anyway, not less.
Classes and values do not belongs to the same kind of sets.
> Le mardi 6 novembre 2012 00:45:21 UTC+1, Shark8 a écrit :
>> On Monday, November 5, 2012 2:34:40 PM UTC-7, Hibou57 (Yannick Duchêne)
>> wrote: > > a derivation hierarchy. That's like a subtype, not a type as
>> a member of a > class (a subtype of Integer is not a member of a
>> fictitious Integer class). But it is, isn't it? Universal_Integer ⊃
>> Integer ⊃ Positive. Therefore, Universal_Integer ⊃ Positive. Universal
>> integers are a fictitious class of integers and Positive is a subtype
>> of Integer.
> Well try, but I pretty sure it's a wrong interpretation. Inclusion
> relation in a type hierarchy, is precely the opposite way. A type
> defines a set of possible values or states, a class is a set, but not
> the same set. Positives indeed belongs to the set of values specified by
> an Integer, but a Positive does not belong to the set fictitious set of
> class whose root type would be Integer.
> And no, universal integer does not define a class, but a set of values.
> More on "Inclusion relation in a type hierarchy, is precely the opposite
> way": a derived type has to cover a base type, and will probably do
> more, but in anyway, not less.
> Classes and values do not belongs to the same kind of sets.
Back to tell more, and I hop, clearer.
First a summary, then later more details: there's a difference between
reuse inheritance and interface inheritance; both must not be confused
(unfortunately, it often is), then (as already said) there's a set of
values and a set of types; here also, both must not be confused
(unfortunately, due to the use of inheritance for reuse, this confusion
often occurs too).
Personally, I see types only via their interface, so to me the proper
inheritance is the interface inheritance. The following is not personal
opinion: a type is defined by a set of value and a set of operations, with
properties. A derived type must provide at least the same set of
operations, and in the programming area, it must provide all, even the
ones which could be derived from provided ones. Ex. even if the equality
may be derived from some others primitives, if it was specified in a
parent interface it will have to be provided (software design and math
analysis differs a bit here, software design is a bit more strict, as it
does not automatically derives things which could be). Then, with
operations, comes two things: domains and codomains (also known as target
domain). For each operation of a derived type, the domain must be a
superset (at worst, an equal set) of the domain of the corresponding
operation in the parent. Inversely, the codomain of an operation must be a
subset (at worst an equal set). Hence, things cannot be described as set
ownership, except for the set of operations, and the set of values is not
enough for a caracterisation. You have: a set of values, a set of
operations, operation's domain sets, and operation's codomain sets.
Now, when you create a “derived” type from Integer, you are restricting
both the domain and the codomain, which makes it anything you would want,
but not an interface derivation. That's OK with the codomain which become
a subset, but the domain too becomes a subset (domain and codomain are
covariant in this case), which is wrong for an interface derivation.
For a numeric type, say `My_Integer_Type`, to be really derived from
`Integer`, as an example, the signature for the addition should be defined
as:
function "+" (Left, Right: Integer) return My_Integer_Type;
This is actually not the case, and you get instead:
function "+" (Left, Right: My_Integer_Type) return My_Integer_Type;
Conclusion: `My_Integer_Type` does not belong to anything like an
`Integer'Class` (which does not exist in Ada, and Ada is right with).
If there was an universal_integer class to which `Integer` would belong,
then we should have something like:
function "+" (Left, Right: universal_integer) return Integer;
which does not exist as‑is (except for intermediate results).
So, what's this, if not a proper type derivation (interface inheritance)?
That's a reuse inheritance. Strictly speaking, reuse inheritance should
never appears, that's a dangerous practice (from a design point of view),
and composition should be used instead, defining a fully new root type and
root class in the while.
Ada is right with its notion of subtype, like in:
subtype My_Integer_Type is Integer range -10 .. 10;
But Ada is a bit wrong (personal opinion) with this:
type My_Integer_Type is new Integer range -10 .. 10;
It would better be instead:
subtype My_Integer_Type is new Integer range -10 .. 10;
When you do:
type My_Integer_Type is new Integer range -10 .. 10;
you do this just to reuse the Integer type's physical representation and
built‑in primitives, not to define a type belonging to an Integer class.
I said the inclusion relation you gave is the reverse of that of the class
relation, here is why: if there is a proper type derivation, that's not
Integer which derives from universal_integer, but the opposite,
universal_integer which derives from Integer. You can check if you try to
apply the rules of a valid type/interface derivation. The domain of
operation of universal_integer is a superset of that of Integer, the
codomain is not a subset, but equals the same codomain when the input
belongs to the same domain, so that universal_integer could belong to a
class defined by Integer; not the other way. Similarly, Integer belongs to
the class of Positive or any subtype of Positive. With the numeric type
hierarchy, the real type hierarchy is head down feet up: universal_integer
inherits the interface of all Positive subtypes and all Integer subtypes.
All of this also explains why a subtype is not the same as a type
derivation (and is even the opposite), and Ada is nice to provide this
distinction (I know no other language with this, even SML don't have
this). At least, the existence of a notion of subtype, makes things like
constants, parameter modes and others, describable in the own terms of
Ada, properly (Dmitry gave a good example).
-- “Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University
> All of this also explains why a subtype is not the same as a type
> derivation (and is even the opposite), and Ada is nice to provide this
> distinction (I know no other language with this, even SML don't have
> this). At least, the existence of a notion of subtype, makes things
> like constants, parameter modes and others, describable in the own
> terms of Ada, properly (Dmitry gave a good example).
I suppose it's because I trained as a physicist, not a mathematician,
but I find I can use Ada perfectly well without worrying about all these
arcane distinctions.
On 06.11.12 03:17, Yannick Duchêne (Hibou57) wrote:
> When you do:
> type My_Integer_Type is new Integer range -10 .. 10;
> you do this just to reuse the Integer type's physical representation and built‑in primitives, not to define a type belonging to an Integer class.
Actually, one can specify a physical representation of
My_Integer_Type that is different from Integer's. Also,
one may supplant or subtract "primitives".
When I do not need type substitution, e.g. because all
objects do their work well, and locally, then the solution is
to adapt notions of type to the solution at hand as necessary,
and if necessary at all, rather than to force working solutions
to match orthodox notions of type. Nothing wrong with the
latter, globally.
> On 06.11.12 03:17, Yannick Duchêne (Hibou57) wrote:
>> When you do:
>> type My_Integer_Type is new Integer range -10 .. 10;
>> you do this just to reuse the Integer type's physical representation
>> and built‑in primitives, not to define a type belonging to an Integer
>> class.
> Actually, one can specify a physical representation of
> My_Integer_Type that is different from Integer's. Also,
> one may supplant or subtract "primitives".
> When I do not need type substitution, e.g. because all
> objects do their work well, and locally, then the solution is
> to adapt notions of type to the solution at hand as necessary,
> and if necessary at all, rather than to force working solutions
> to match orthodox notions of type. Nothing wrong with the
> latter, globally.
This has nothing to do with orthodoxy, that's proper naming of things.
Confusing both kind of inheritance (and one is not even inheritance),
leads to mixing things with no sense, and that's what I believe had lead
to Python's duck‑typing (personal opinion here). As explained, both
inheritance contradicts in near to everything. When both are mixed, the
only things which seems to remains preserved, is operation's names, and
here you get it: duck‑typing. OOP religion (at least a view of OOP)
contributed to this misunderstanding, as it promoted inheritance as the
Holy Grail good to everything, and it indeed promoted inheritance for
reuse (which is wrong).
I did not want to say the numeric type hierarchy must not be used, just
that it must not be confused with the interface hierarchy, as Shark8 did.
Now, talking about proper naming of things, how would you explain to a
student, that sometime “type” must follow the substitution principle, and
sometime, it do exactly the opposite? That's why I said it would have been
better to have Ada requires to write “subtype XYZ is new” instead of “type
XYZ is new”, in such cases.
> Actually, one can specify a physical representation of
> My_Integer_Type that is different from Integer's. Also,
> one may supplant or subtract "primitives".
Yes, it was to keep it simple. You are still reusing anyway (the primitive
operations, automatically generated checks).
-- “Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University
Le Tue, 06 Nov 2012 20:47:58 +0100, Yannick Duchêne (Hibou57)
<yannick_duch...@yahoo.fr> a écrit:
> OOP religion (at least a view of OOP) contributed to this
> misunderstanding, as it promoted inheritance as the Holy Grail good to
> everything, and it indeed promoted inheritance for reuse (which is
> wrong).
Wrong, except in the very few cases where this is practically unavoidable,
as with the numeric types, and that can remains valid, as we don't have
anything like numeric class wide type.
-- “Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University
On 06.11.12 20:47, Yannick Duchêne (Hibou57) wrote:
> Now, talking about proper naming of things, how would you explain to a
> student, that sometime “type” must follow the substitution principle, and
> sometime, it do exactly the opposite?
The challenge is to explain why the substitution principle is
a valid commandment: A valuable piece of formal theory, it may
not offer sufficient justification in the workplace.
Why? Because the workplace is governed by rules that language
theory/ideology/religion/principles will not normally cover.
A similar example will explain why principles like a theoretically
clean notion may turn out to be pointless, even a hindrance once
they are used outside the clean room:
Sometimes programs would modify themselves in a perfectly,
provably safe way, leading to sufficient performance in
terms of time and storage. And no matter what one might have
to say about their design, only by violating today's principles
could they achieve their stated goals. Today, it may not even
be possible to run such programs, because modifications are
detected, and the program is stopped. Principles have changed.
But are these self-modifying programs not "programs" anymore
because they were "improperly named `programs'"?
Similarly, I'll say that "inheritance" without further adjectives
is just insufficiently defined, and void of purpose (for the
workplace). And any single definition cannot name the "right"
inheritance.
So we have
"Thou shalt follow the substitution principle!"
and
"today's orthodoxy of language theory".
(Well, actually, the 1980s' theory, or even earlier.)
That said, I wish there was more software whose designers had
followed the substitution principle, and not reused hash tables
as parents, say. (Even when that's practical if you have the
source.)
On Wed, 07 Nov 2012 13:03:08 +0100, Georg Bauhaus wrote:
> On 06.11.12 20:47, Yannick Duchêne (Hibou57) wrote:
>> Now, talking about proper naming of things, how would you explain to a
>> student, that sometime “type” must follow the substitution principle, and
>> sometime, it do exactly the opposite?
> The challenge is to explain why the substitution principle is
> a valid commandment:
It is not.
Positive is a legitime subtype of Integer even though violates the LSP.
The valid proposition is that you should not substitute something
non-substitutable, but you cannot enforce that through types. Correctness
cannot be ensured through type checks.
Le Wed, 07 Nov 2012 13:03:08 +0100, Georg Bauhaus
<rm.dash-bauh...@futureapps.de> a écrit:
> On 06.11.12 20:47, Yannick Duchêne (Hibou57) wrote:
>> Now, talking about proper naming of things, how would you explain to a
>> student, that sometime “type” must follow the substitution principle,
>> and
>> sometime, it do exactly the opposite?
> The challenge is to explain why the substitution principle is
> a valid commandment: A valuable piece of formal theory, it may
> not offer sufficient justification in the workplace.
It was never promoted as a commandment in my comments, but said it is not
to be confused to something else, and to be followed when expected, and
not followed when not applicable (like not using it in place of reuse,
because this always gives the illusion of one thing and give another
instead). This find as much justifications as predictability do.
> Why? Because the workplace is governed by rules that language
> theory/ideology/religion/principles will not normally cover.
No religion/ideology was spread, but some basic principle recalled.
> A similar example will explain why principles like a theoretically
> clean notion may turn out to be pointless, even a hindrance once
> they are used outside the clean room:
> Sometimes programs would modify themselves in a perfectly,
> provably safe way, leading to sufficient performance in
> terms of time and storage. And no matter what one might have
> to say about their design, only by violating today's principles
> could they achieve their stated goals. Today, it may not even
> be possible to run such programs, because modifications are
> detected, and the program is stopped. Principles have changed.
And that's precisely because we don't have proved things, we need guidance
to prevent errors. Typing and other rules are kind of minimalist and
default proofs of some properties. And this is there by the lack of better
(there are other techniques, but so tedious and time consuming to apply,
they would prevent many thing to be done, so these techniques are
restricted to some area).
> But are these self-modifying programs not "programs" anymore
> because they were "improperly named `programs'"?
That's unfair, you are drifting too much based on a single definition I
maid. By the way, I would call these ”programs“, so you did not properly
guess.
> Similarly, I'll say that "inheritance" without further adjectives
> is just insufficiently defined, and void of purpose (for the
> workplace). And any single definition cannot name the "right"
> inheritance.
> So we have
> "Thou shalt follow the substitution principle!"
> and
> "today's orthodoxy of language theory".
> (Well, actually, the 1980s' theory, or even earlier.)
You should know some old things are still valid today ;)
-- “Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University
Le Wed, 07 Nov 2012 14:09:47 +0100, Dmitry A. Kazakov
<mail...@dmitry-kazakov.de> a écrit:
> On Wed, 07 Nov 2012 13:03:08 +0100, Georg Bauhaus wrote:
>> On 06.11.12 20:47, Yannick Duchêne (Hibou57) wrote:
>>> Now, talking about proper naming of things, how would you explain to a
>>> student, that sometime “type” must follow the substitution principle,
>>> and
>>> sometime, it do exactly the opposite?
>> The challenge is to explain why the substitution principle is
>> a valid commandment:
> It is not.
> Positive is a legitime subtype of Integer even though violates the LSP.
That's precisely what was said: both must not be confused.
> The valid proposition is that you should not substitute something
> non-substitutable, but you cannot enforce that through types. Correctness
> cannot be ensured through type checks.
Yes, but just like typing fails to ensure all of the correctness in the
large (and in some very few cases, even fails to accept valid things).
That's still the best balance we get between handy and safe.
-- “Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University
> Le Wed, 07 Nov 2012 13:03:08 +0100, Georg Bauhaus
> <rm.dash-bauh...@futureapps.de> a écrit:
>> On 06.11.12 20:47, Yannick Duchêne (Hibou57) wrote:
>>> Now, talking about proper naming of things, how would you explain to a
>>> student, that sometime “type” must follow the substitution principle, and
>>> sometime, it do exactly the opposite?
>> The challenge is to explain why the substitution principle is
>> a valid commandment: A valuable piece of formal theory, it may
>> not offer sufficient justification in the workplace.
> It was never promoted as a commandment in my comments, but said it is not to
> be confused to something else, and to be followed when expected, and not
> followed when not applicable (like not using it in place of reuse, because
> this always gives the illusion of one thing and give another instead). This
> find as much justifications as predictability do.
>> Why? Because the workplace is governed by rules that language
>> theory/ideology/religion/principles will not normally cover.
> No religion/ideology was spread, but some basic principle recalled.
Well, a basic principle about derived types was stated,
"a derived type has to cover a base type, and will probably
do more, but in anyway, not less",
The commandment can be called a basic principle in the light of
the substitution principle, but not necessarily in the light of
correct algorithms at workplace. To show the absence of issues might
be more work. However, if this work makes your algorithm work within
specs, the basic principle is at odds with workplace requirements.
On Wed, 07 Nov 2012 19:06:11 +0100, Georg Bauhaus wrote:
> Well, a basic principle about derived types was stated,
> "a derived type has to cover a base type, and will probably
> do more, but in anyway, not less",
which evidently does not hold in two major cases used in Ada:
1. specialization:
1.1 Ada's subtypes
1.2 Ada's in-mode arguments
1.3 Ada's constants
1.4 Ada's discriminated types
1.5 Ada's specific types as related to the class-wide counterparts, e.g. T
is a specialization of T'Class.
> The commandment can be called a basic principle in the light of
> the substitution principle,
Generalization, the kind of type deviation you are talking about, does not
save LSP. In particular, it breaks in-operations. This is the reason why,
for example, extensible enumerations (which would be a generalization) pose
such a big problem.
It is important to remember that any non-trivial modification of a type
always breaks something. There is no rule expressed in terms of type values
which could ensure LSP. Bijection of domain sets the only mapping which
would unconditionally satisfy the requirement of weakening pre- and
strengthening post-conditions of all operations.
Specifies possible subtypes. That's just user defined subtypes (unlike the
aboves, which are Ada predefined).
> 1.5 Ada's specific types as related to the class-wide counterparts, e.g.
> T is a specialization of T'Class.
Both belong to a different category, can't be compared. Why do you say “T
is a specialization of T'Class”? Anything in T'Class is expected to be
predictable to behave like T, so why is T a specialization compared to
T'Class?
I don't see, and on the contrary, feel extensions is even where it applies
the best.
>> The commandment can be called a basic principle in the light of
>> the substitution principle,
> Generalization, the kind of type deviation you are talking about, does
> not
> save LSP. In particular, it breaks in-operations. This is the reason why,
> for example, extensible enumerations (which would be a generalization)
> pose
> such a big problem.
What do you call generalization here? Something which would be like giving
an ancestor to a type which don't have one? (not sure to understand)
> It is important to remember that any non-trivial modification of a type
> always breaks something. There is no rule expressed in terms of type
> values
> which could ensure LSP. Bijection of domain sets the only mapping which
> would unconditionally satisfy the requirement of weakening pre- and
> strengthening post-conditions of all operations.
Yes, that's why using pre/post requires to be careful, to not break
anything or too much. Especially with preconditions, which may be the most
easy to forget about, due to the disjunction.
-- “Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: Epigrams on Programming — Alan J. — P. Yale University
On Wed, 07 Nov 2012 22:00:14 +0100, Yannick Duchêne (Hibou57) wrote:
> Le Wed, 07 Nov 2012 21:04:27 +0100, Dmitry A. Kazakov
> <mail...@dmitry-kazakov.de> a écrit:
>> 1.5 Ada's specific types as related to the class-wide counterparts, e.g.
>> T is a specialization of T'Class.
> Both belong to a different category, can't be compared. Why do you say “T
> is a specialization of T'Class”? Anything in T'Class is expected to be
> predictable to behave like T, so why is T a specialization compared to
> T'Class?
Because:
1. T is substitutable (considered such by the compiler) for T'Class = T
inherits operations of T'Class (the class-wide operations) = T <: T'Class
(a subtype of T'Class).
2. Some values of T'Class have no corresponding values of T
3. All values of T have corresponding values of T'Class
2+3 = injection. 1+injection = specialization
>> 2. extension = Cartesian product, Ada's tagged types
> I don't see, and on the contrary, feel extensions is even where it applies
> the best.
>>> The commandment can be called a basic principle in the light of
>>> the substitution principle,
>> Generalization, the kind of type deviation you are talking about, does not
>> save LSP. In particular, it breaks in-operations. This is the reason why,
>> for example, extensible enumerations (which would be a generalization)
>> pose such a big problem.
> What do you call generalization here?
S is a generalization of T when S is considered substitutable (no type
errors) and there exists a reverse injective mapping : T->S
> Something which would be like giving
> an ancestor to a type which don't have one? (not sure to understand)
That is supertyping. Sub-/supertyping relation of types S and T is
independent on the nature of mapping defined between values of S and T.
Specialization and generalization are forms of subtyping or supertyping.
>> It is important to remember that any non-trivial modification of a type
>> always breaks something. There is no rule expressed in terms of type values
>> which could ensure LSP. Bijection of domain sets the only mapping which
>> would unconditionally satisfy the requirement of weakening pre- and
>> strengthening post-conditions of all operations.
> Yes, that's why using pre/post requires to be careful, to not break
> anything or too much. Especially with preconditions, which may be the most
> easy to forget about, due to the disjunction.
Precondition of any operation shall be statically true. As simple as that.
Dynamic preconditions make no sense. When precondition is static the case
shall be promoted to a distinct [sub]type. But this is another discussion.
> On Friday, November 2, 2012 8:10:56 AM UTC-6, Georg Bauhaus wrote:
>> Assignment statements for containers have copy semantics. For example,
>> LRM A.18.2 says about vectors:
>> " Implementation Requirements
>> "254/2 The execution of an assignment_statement for a vector shall have
>> the effect of copying the elements from the source vector object to
>> the target vector object."
>> So, backed by the LRM, programmers need not worry about Adjust >> procedures,
>> if any.
> Dang, that is _nice_.
> I'm glad we've got a lot of smart guys on the language-definition group.
Thanks, I think. :-)
Of course, it is always possible for an implementer to screw this (or anything) up. But if they do, you at least have firm ground for a bug report.
Wow, thanks for all the answers and the interesting discussion. :-)
I now feel convinced that it's safe to use the assignment operator for standard ada classes, unless there are pointer types inside the record (I reckon these have to be initialized to new objects if there is no possibility to avoid them).