comp.lang.ada
 help / color / mirror / Atom feed
* Ada Interfaces and the Liskov Substitution Principle
@ 2007-05-23 19:47 Stefan Lucks
  2007-05-23 20:32 ` Ludovic Brenta
                   ` (2 more replies)
  0 siblings, 3 replies; 81+ messages in thread
From: Stefan Lucks @ 2007-05-23 19:47 UTC (permalink / raw)


Hi all,

to me, it seems as if Ada 2005 is bluntly violating the Liskov 
Substitution Prinicple. E.g., define

---Start---
package Parents is
    type Parent is Interface;

    -- primitive operation
   procedure Do_Something(Self: in out Parent) is abstract;

    -- class-wide operations
    procedure Do_Nothing(From: in Parent'Class;
                         To:  out Parent'Class);
    procedure Convert(From: in Parent'Class;
                      To:  out Parent'Class);
end Parents;
----End----

with the primitve operations defined in

---Start---
package body Parents is

    procedure Do_Nothing(From: in Parent'Class;
                         To:  out Parent'Class) is
    begin
       null;
       -- warning: "To" is never assigned a value.
    end Do_Nothing;

    procedure Convert(From: in Parent'Class;
                      To:  out Parent'Class) is
    begin
       To := From;
    end Convert;

end Parents;
----End----

Now, Do_Nothing is harmless (except for generating a compiler warning). 
But Convert uses the assignment ":=", which seems OK, as the interface
Parents.Parent is not limited.

Now there are two children to inherit from Parents. The first one is 
Child.Object:

---Start---
with Parents;

package Child is

    type Object is new Parents.Parent with private;

    procedure Do_Something (Self: in out Object);

private

    ... doesn't matter ...

end Child;
----End----

Child.Object gets everything there are no limits to using 
Parents.Parent'Class. But look at Stepchild.Object:

---Start---
with Parents, Ada.Finalization;

package Stepchild is

    type Object is
      new Ada.Finalization.Limited_Controlled
      and Parents.Parent
      with private;

    procedure Do_Something (Self: in out Object);

private

    ... doesn't really matter ...

end Stepchild;
----End----

Stepchild.Object is really a poor cousin, prohibited from using 
Parent.Convert:

---Start---
with Ada.Text_IO, Parents, Child, Stepchild;

procedure Family is

    procedure All_Well(X: in out Parents.Parent'Class) is
    begin
       X.Do_Something;
    end All_Well;

    Procedure Not_So_Well(X, Y: in out Parents.Parent'Class) is
    begin
       Parents.Convert (X,Y);
    end Not_So_Well;

    Alice, Charles: Child.Object;
    Bob, Eve: Stepchild.Object;

begin
    All_Well(Alice);
    All_Well(Bob);
    All_Well(Charles);
    All_Well(Eve);
    Ada.Text_IO.Put("first OK ");
    Not_So_Well(Alice, Charles);
    Ada.Text_IO.Put("second OK ");
    Not_So_Well(Bob, Eve); -- this raises Eception Constraint_Error
                           -- with "... tag check failed".
    Ada.Text_IO.Put("will we ever get here?"); -- no, nay, never!!!
end Family;
----End----

My understanding of the Liskov substitution principle, see
   http://en.wikipedia.org/wiki/Liskov_substitution_principle
is that as Partens.Parent implicitely (by not being limited) provides 
certain primitve operations, such as ":=" and "=", and Stepchild.Object 
takes away these primitive operations, Stepchild.Object should not be in
Parents.Parent'Class, i.e.,
    Not_So_Well(Bob, Eve);
and even
    All_Well(Bob);
and
    All_Well(Eve);
ought to be a syntax error.

I think, it is a flaw that when calling Not_So_Well(X,Y) you need to 
know
   (a) of what type X and Y actually are (instead of just knowing that
       these are of type Parents.Parent'Class) and
   (b) and the implementation details of Not_So_Well (here the fact that
       it uses the assignment over Parents.Parent'Class).

What do you guys think about this?






-- 
Stefan Lucks      (moved to Bauhaus-University Weimar, Germany)
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-23 19:47 Ada Interfaces and the Liskov Substitution Principle Stefan Lucks
@ 2007-05-23 20:32 ` Ludovic Brenta
  2007-05-23 22:00   ` Randy Brukardt
  2007-05-24  6:57   ` Stefan Lucks
  2007-05-23 20:54 ` Maciej Sobczak
  2007-05-24  7:39 ` Dmitry A. Kazakov
  2 siblings, 2 replies; 81+ messages in thread
From: Ludovic Brenta @ 2007-05-23 20:32 UTC (permalink / raw)


Stefan Lucks <lucks@th.informatik.uni-mannheim.de> writes:
> package Parents is
>    type Parent is Interface;
>
>    -- primitive operation
>   procedure Do_Something(Self: in out Parent) is abstract;
>
>    -- class-wide operations
>    procedure Do_Nothing(From: in Parent'Class;
>                         To:  out Parent'Class);
>    procedure Convert(From: in Parent'Class;
>                      To:  out Parent'Class);
> end Parents;

> with Parents, Ada.Finalization;
>
> package Stepchild is
>
>    type Object is
>      new Ada.Finalization.Limited_Controlled
>      and Parents.Parent
>      with private;
>
>    procedure Do_Something (Self: in out Object);
>
> private
>
>    ... doesn't really matter ...
>
> end Stepchild;

> What do you guys think about this?

I think the declaration of Stepchild.Object is illegal because ARM
3.9.4(12/2) states: "A type derived from a nonlimited interface shall
be nonlimited."

Since GNAT is currently the only compiler with Ada 2007 features, I
presume it must be a bug in GNAT.  What version are you using?

-- 
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-23 19:47 Ada Interfaces and the Liskov Substitution Principle Stefan Lucks
  2007-05-23 20:32 ` Ludovic Brenta
@ 2007-05-23 20:54 ` Maciej Sobczak
  2007-05-23 21:58   ` Randy Brukardt
  2007-05-24  7:39 ` Dmitry A. Kazakov
  2 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-23 20:54 UTC (permalink / raw)


On 23 Maj, 21:47, Stefan Lucks <l...@th.informatik.uni-mannheim.de>
wrote:

> to me, it seems as if Ada 2005 is bluntly violating the Liskov
> Substitution Prinicple. E.g., define

[...]

Interesting.

My humble opinion: assignment of class-wide types should be prohibited
in the first place. I mean - at compile time.
It's just asking for troubles.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-23 20:54 ` Maciej Sobczak
@ 2007-05-23 21:58   ` Randy Brukardt
  2007-05-24  7:29     ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Randy Brukardt @ 2007-05-23 21:58 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message
news:1179953657.839272.160320@a26g2000pre.googlegroups.com...
> On 23 Maj, 21:47, Stefan Lucks <l...@th.informatik.uni-mannheim.de>
> wrote:
>
> > to me, it seems as if Ada 2005 is bluntly violating the Liskov
> > Substitution Prinicple. E.g., define
>
> [...]
>
> Interesting.
>
> My humble opinion: assignment of class-wide types should be prohibited
> in the first place. I mean - at compile time.
> It's just asking for troubles.

That doesn't make much sense. Yes, it is a bit weird that assignment is
potentially a dispatching operation, but otherwise there is no semantic
problem with it. (The OP having an illegal example, thus proving nothing.)
It might be a bit hard to use usefully, but that's no reason for banning it.

                     Randy.





^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-23 20:32 ` Ludovic Brenta
@ 2007-05-23 22:00   ` Randy Brukardt
  2007-05-24  0:56     ` Anh Vo
  2007-05-24 18:27     ` Pascal Obry
  2007-05-24  6:57   ` Stefan Lucks
  1 sibling, 2 replies; 81+ messages in thread
From: Randy Brukardt @ 2007-05-23 22:00 UTC (permalink / raw)


"Ludovic Brenta" <ludovic@ludovic-brenta.org> wrote in message
news:871wh7i8lq.fsf@ludovic-brenta.org...
> Stefan Lucks <lucks@th.informatik.uni-mannheim.de> writes:
...
> > What do you guys think about this?
>
> I think the declaration of Stepchild.Object is illegal because ARM
> 3.9.4(12/2) states: "A type derived from a nonlimited interface shall
> be nonlimited."

Right. The most general type of interface is a limited interface; every
interface should be declared limited if possible. (We didn't make that the
default solely because it would be inconsistent with the rest of the
language.) And if it is not possible to declare the interface limited (as in
the example), then all types that include it must be nonlimited. At least
interfaces don't have the rather limiting rule that regular tagged types do,
where the limitedness can't be changed at all.

                           Randy.





^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-23 22:00   ` Randy Brukardt
@ 2007-05-24  0:56     ` Anh Vo
  2007-05-24 18:27     ` Pascal Obry
  1 sibling, 0 replies; 81+ messages in thread
From: Anh Vo @ 2007-05-24  0:56 UTC (permalink / raw)


On May 23, 3:00 pm, "Randy Brukardt" <r...@rrsoftware.com> wrote:
> "Ludovic Brenta" <ludo...@ludovic-brenta.org> wrote in message
>
> news:871wh7i8lq.fsf@ludovic-brenta.org...
>
> > Stefan Lucks <l...@th.informatik.uni-mannheim.de> writes:
> ...
> > > What do you guys think about this?
>
> > I think the declaration of Stepchild.Object is illegal because ARM
> > 3.9.4(12/2) states: "A type derived from a nonlimited interface shall
> > be nonlimited."
>
> Right. The most general type of interface is a limited interface; every
> interface should be declared limited if possible. (We didn't make that the
> default solely because it would be inconsistent with the rest of the
> language.) And if it is not possible to declare the interface limited (as in
> the example), then all types that include it must be nonlimited. At least
> interfaces don't have the rather limiting rule that regular tagged types do,
> where the limitedness can't be changed at all.

Indeed, GNAT-GPL-2007 complains that "stepchild.ads:12:04: progenitor
interface "Parent" of limited type must be limited". In addition, if
the Object is changed Controlled type instead, there is no problem
with compilation.

AV




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-23 20:32 ` Ludovic Brenta
  2007-05-23 22:00   ` Randy Brukardt
@ 2007-05-24  6:57   ` Stefan Lucks
  1 sibling, 0 replies; 81+ messages in thread
From: Stefan Lucks @ 2007-05-24  6:57 UTC (permalink / raw)


> I think the declaration of Stepchild.Object is illegal because ARM
> 3.9.4(12/2) states: "A type derived from a nonlimited interface shall
> be nonlimited."

Many thanks to you and to the other guys for pointing that out! I am 
pleased to hear this.

> Since GNAT is currently the only compiler with Ada 2007 features, I
> presume it must be a bug in GNAT.  What version are you using?

gnat GPL 2006 (I have not yet switched to 2007).



-- 
Stefan Lucks   (moved to Bauhaus-University Weimar, Germany)
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-23 21:58   ` Randy Brukardt
@ 2007-05-24  7:29     ` Maciej Sobczak
  2007-05-24  8:02       ` Dmitry A. Kazakov
  2007-05-24 10:42       ` Georg Bauhaus
  0 siblings, 2 replies; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-24  7:29 UTC (permalink / raw)


On 23 Maj, 23:58, "Randy Brukardt" <r...@rrsoftware.com> wrote:

> > My humble opinion: assignment of class-wide types should be prohibited
> > in the first place. I mean - at compile time.
> > It's just asking for troubles.
>
> That doesn't make much sense. Yes, it is a bit weird that assignment is
> potentially a dispatching operation, but otherwise there is no semantic
> problem with it.

Can it be dispatching on both arguments?
If not, how can you reasonably implement it?

And even if it could, still, how can you *reasonably* implement it?

Let's take a classic example with the hierarchy of geometric objects
(Object, Rectlangle, Triangle, Circle, and so on) and this:

procedure Do_Something(X : in Object'Class; Y : out Object'Class) is
begin
  Y := X; -- ?
end Do_Something;

> (The OP having an illegal example, thus proving nothing.)

The OP did not prove that Ada violates LSP, but he did point out where
the problems can hide.

Coming from C++, I have never seen any single example where assignment
made sense with polymorphic hierarchies.

Do you know any such example? Can you show it?

> It might be a bit hard to use usefully, but that's no reason for banning it.

C programmers can use the same logic to justify everything. ;-)

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-23 19:47 Ada Interfaces and the Liskov Substitution Principle Stefan Lucks
  2007-05-23 20:32 ` Ludovic Brenta
  2007-05-23 20:54 ` Maciej Sobczak
@ 2007-05-24  7:39 ` Dmitry A. Kazakov
  2007-05-24 11:12   ` Stefan Lucks
  2 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-24  7:39 UTC (permalink / raw)


On Wed, 23 May 2007 21:47:32 +0200, Stefan Lucks wrote:

> to me, it seems as if Ada 2005 is bluntly violating the Liskov 
> Substitution Prinicple.

Huh, as well as Ada 83 did. There is no need in much code, just write

   subtype Non_LSP_Subtype is String (1..80);

or

   subtype Positive is Integer range 1..Integer'Last;

or, for that matter  "constant", "in", "out", "not null", etc. All these
are examples of non-LSP subtypes.

> My understanding of the Liskov substitution principle, see
>    http://en.wikipedia.org/wiki/Liskov_substitution_principle
> is that as Partens.Parent implicitely (by not being limited) provides 
> certain primitve operations, such as ":=" and "=", and Stepchild.Object 
> takes away these primitive operations,

It is illegal, but if it were legal, then yes, disallowing operations
breaks LSP. However, see above, mere passing a variable as "in" does it as
well in the sense that "in T" is not an LSP-subtype of T.

> What do you guys think about this?

LPS is totally irrelevant as long as substitutability violation can be
detected at compile time. This is why "constant" does not worry anybody. A
method disallowing is perfectly OK, if you cannot call it.

LSP violation becomes a problem when substitutability is indeterminable
until run-time. In may cases we still choose to live with that. Constrained
Ada subtypes is an example of. Another is multi-methods Foo (X, Y : T),
when called on different children of T. In such cases Ada adds
Constraint_Error to the interface of each subprogram and things become
"substitutable" again.

LSP violation is catastrophic when undetected. I think that renaming array
objects with changing bounds falls under this category. (Apart from
"unchecked" stuff)

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24  7:29     ` Maciej Sobczak
@ 2007-05-24  8:02       ` Dmitry A. Kazakov
  2007-05-24 12:58         ` Maciej Sobczak
  2007-05-24 10:42       ` Georg Bauhaus
  1 sibling, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-24  8:02 UTC (permalink / raw)


On 24 May 2007 00:29:29 -0700, Maciej Sobczak wrote:

> On 23 Maj, 23:58, "Randy Brukardt" <r...@rrsoftware.com> wrote:
> 
>>> My humble opinion: assignment of class-wide types should be prohibited
>>> in the first place. I mean - at compile time.
>>> It's just asking for troubles.
>>
>> That doesn't make much sense. Yes, it is a bit weird that assignment is
>> potentially a dispatching operation, but otherwise there is no semantic
>> problem with it.
> 
> Can it be dispatching on both arguments?

It shall be. It is a pity that Ada does not have MD.

> If not, how can you reasonably implement it?
> 
> And even if it could, still, how can you *reasonably* implement it?
> 
> Let's take a classic example with the hierarchy of geometric objects
> (Object, Rectlangle, Triangle, Circle, and so on) and this:
> 
> procedure Do_Something(X : in Object'Class; Y : out Object'Class) is
> begin
>   Y := X; -- ?
> end Do_Something;

In the current version of Ada Y is constrained to its actual type. So in
all cases of different types you will get Constraint_Error - no full MD.
But if there were MD, then you could call Do_Something (Circle, Ellipse).
And don't forget:

declare
   X : T'Class := Read_From_File; -- T is non-limited, Adjust is called
begin
   ...

> Coming from C++, I have never seen any single example where assignment
> made sense with polymorphic hierarchies.

Real-life example. Consider a threaded library. Let you have an Ada-like
rendezvous. You wanted to propagate an exception raised in the callee to
the caller. Similarly, let an exception is propagated out of a child
thread. You want to continue its propagation to the parent.

> Do you know any such example? Can you show it?

Marshaling objects.

(All types of, like in the example above, like in view change of a small
by-value object, like in making an object persistent or broadcasting it
over the network)

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24  7:29     ` Maciej Sobczak
  2007-05-24  8:02       ` Dmitry A. Kazakov
@ 2007-05-24 10:42       ` Georg Bauhaus
  2007-05-24 13:41         ` Dmitry A. Kazakov
  2007-05-25 16:59         ` Markus E Leypold
  1 sibling, 2 replies; 81+ messages in thread
From: Georg Bauhaus @ 2007-05-24 10:42 UTC (permalink / raw)


On Thu, 2007-05-24 at 10:02 +0200, Dmitry A. Kazakov wrote:

> > Coming from C++, I have never seen any single example where assignment
> > made sense with polymorphic hierarchies.
...
> 
> > Do you know any such example? Can you show it?
> 
> Marshaling objects.

In fact, Eiffel has a relative, the assignment attempt
(written "?="). And the Eiffel arguments versus Liskov/Wing
are that the principles guiding program design should come
from the solution to a problem, not from models when these
cannot capture the solution. In a sense, it is argued that
that L/W substitution (and also co/contra-variance) violate
programming principles!

For example, you can make a primitive operation abstract
("deferred", "take it away") in a derived type. This might
make sense when for some good reasons, a *real* *world* heir
cannot
(a) have the inherited operation
(b) change its parents.





^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24  7:39 ` Dmitry A. Kazakov
@ 2007-05-24 11:12   ` Stefan Lucks
  2007-05-24 13:56     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Stefan Lucks @ 2007-05-24 11:12 UTC (permalink / raw)



Dmitry A. Kazakov wrote:

> [...] mere passing a variable as "in" does it as
> well in the sense that "in T" is not an LSP-subtype of T.

You are using a very broad and generalised interpretation of the LSP. My 
interpretation -- and I believe this is the common and usual one -- is 
that "X: in T" in the parameterlist of a subprogram does not deal with 
some "artificial" type "in T", just with "T". The "in" is part of the 
subprogram's contract, not a part of X's contract. So there is no conflict 
with LSP.

> LPS is totally irrelevant as long as substitutability violation can be
> detected at compile time. This is why "constant" does not worry anybody. A
> method disallowing is perfectly OK, if you cannot call it.

So your very broad and generalised interpretation of the LSP is totally 
irrelevant, except for the special case where it overlaps with the more 
narrow usual interpretation. Perhaps you should follow the crowd and 
narrow your interpretation as well?

Whatever interpretation, the stuff below is right.

> LSP violation becomes a problem when substitutability is indeterminable
> until run-time. In may cases we still choose to live with that. Constrained
> Ada subtypes is an example of. Another is multi-methods Foo (X, Y : T),
> when called on different children of T. In such cases Ada adds
> Constraint_Error to the interface of each subprogram and things become
> "substitutable" again.

Yes, that is an ugly patch. But it appears tricky to come up with a better 
solution ...

> LSP violation is catastrophic when undetected. [...]

It is bad enough if detected after lengthy testing and debugging sessions.



-- 
Stefan Lucks      (moved to Bauhaus-University Weimar, Germany)
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------





^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24  8:02       ` Dmitry A. Kazakov
@ 2007-05-24 12:58         ` Maciej Sobczak
  2007-05-24 13:42           ` Dmitry A. Kazakov
                             ` (2 more replies)
  0 siblings, 3 replies; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-24 12:58 UTC (permalink / raw)


On 24 Maj, 10:02, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > Can it be dispatching on both arguments?
>
> It shall be. It is a pity that Ada does not have MD.

Yes, but that would not automatically solve the problem, see below.

> > Coming from C++, I have never seen any single example where assignment
> > made sense with polymorphic hierarchies.
>
> Real-life example. Consider a threaded library. Let you have an Ada-like
> rendezvous. You wanted to propagate an exception raised in the callee to
> the caller. Similarly, let an exception is propagated out of a child
> thread. You want to continue its propagation to the parent.
>
> > Do you know any such example? Can you show it?
>
> Marshaling objects.

No, I'm not convinced. This is more like cloning.

Assignment of class-wide type is strange/dangerous, beucause it might
require dynamic change of the object's type.
Assigning Circle to Triangle (through Object'Class) cannot reasonably
work with preserving the types of each object. The Triangle would need
to become Circle - and this action might change the ability of the
object to respond to messages that are supposedly in its interface. Or
change the invariants in the original type.

declare
  C : Circle;
  T : Triangle;
begin
  Do_Something(C, T); -- T := C; inside

  -- and here some code still thinks that T is a Triangle,
  -- which according to its declaration in the same scope
  -- must be true (but isn't!)
end;

There is no way to change the type of T in the code above and without
it there is no way to execute the assignment.
You can restrict the operation so that the arguments must have the
same tag (and then MD is not needed anymore), but such restriction can
be run-time only and cannot be expressed in the signature of
Do_Something.

Your marshalling example is interesting, but actually works
differently: you don't have the left-hand object before assignment;
you just make a copy of something and give the copy some identity.
It's just a copy-construction basically, or cloning (if polimorphic).
You can do this either with access variables or with initialization of
class wide type (which is *not* an assignment).

I was talking about real assignment - and this assumes that two
objects already exist and we make one to be equal to the other. There
is no way to do it right.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 10:42       ` Georg Bauhaus
@ 2007-05-24 13:41         ` Dmitry A. Kazakov
  2007-05-25 16:59         ` Markus E Leypold
  1 sibling, 0 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-24 13:41 UTC (permalink / raw)


On Thu, 24 May 2007 12:42:16 +0200, Georg Bauhaus wrote:

> In fact, Eiffel has a relative, the assignment attempt
> (written "?="). And the Eiffel arguments versus Liskov/Wing
> are that the principles guiding program design should come
> from the solution to a problem, not from models when these
> cannot capture the solution. In a sense, it is argued that
> that L/W substitution (and also co/contra-variance) violate
> programming principles!

Actually [absolute] LSP violates common sense.

IF A were fully and unconditionally substitutable for B in all possible
contexts, then As and Bs would be equivalent in any thinkable sense.
Because then they would be indistinguishable without magic.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 12:58         ` Maciej Sobczak
@ 2007-05-24 13:42           ` Dmitry A. Kazakov
  2007-05-24 22:08           ` Robert A Duff
  2007-05-24 22:58           ` Randy Brukardt
  2 siblings, 0 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-24 13:42 UTC (permalink / raw)


On 24 May 2007 05:58:27 -0700, Maciej Sobczak wrote:

> On 24 Maj, 10:02, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> Can it be dispatching on both arguments?
>>
>> It shall be. It is a pity that Ada does not have MD.
> 
> Yes, but that would not automatically solve the problem, see below.
> 
>>> Coming from C++, I have never seen any single example where assignment
>>> made sense with polymorphic hierarchies.
>>
>> Real-life example. Consider a threaded library. Let you have an Ada-like
>> rendezvous. You wanted to propagate an exception raised in the callee to
>> the caller. Similarly, let an exception is propagated out of a child
>> thread. You want to continue its propagation to the parent.
>>
>>> Do you know any such example? Can you show it?
>>
>> Marshaling objects.
> 
> No, I'm not convinced. This is more like cloning.
> 
> Assignment of class-wide type is strange/dangerous, beucause it might
> require dynamic change of the object's type.

No it cannot, because otherwise it weren't dispatching in the left
argument. But you have explained it later on.

> Assigning Circle to Triangle (through Object'Class) cannot reasonably
> work with preserving the types of each object. The Triangle would need
> to become Circle - and this action might change the ability of the
> object to respond to messages that are supposedly in its interface. Or
> change the invariants in the original type.
> 
> declare
>   C : Circle;
>   T : Triangle;
> begin
>   Do_Something(C, T); -- T := C; inside
>   -- and here some code still thinks that T is a Triangle,
>   -- which according to its declaration in the same scope
>   -- must be true (but isn't!)
> end;
> 
> There is no way to change the type of T in the code above and without
> it there is no way to execute the assignment.

No, you presume some meaning in the name ":=", but there is no one. It just
is an operation to call as any other. Whatever Circle := Triangle might
mean, is up to the designer of this types hierarchy.

> You can restrict the operation so that the arguments must have the
> same tag (and then MD is not needed anymore), but such restriction can
> be run-time only and cannot be expressed in the signature of
> Do_Something.
> 
> Your marshalling example is interesting, but actually works
> differently: you don't have the left-hand object before assignment;
> you just make a copy of something and give the copy some identity.
> It's just a copy-construction basically, or cloning (if polimorphic).
> You can do this either with access variables or with initialization of
> class wide type (which is *not* an assignment).
> 
> I was talking about real assignment - and this assumes that two
> objects already exist and we make one to be equal to the other. There
> is no way to do it right.

OK, for this the use case is [semi-]"equivalent" types hierarchies. They
often appear when you have concurrent representations of the same thing.
Typical example (poorly designed in Ada) is:

String, UTF8_String, Wide_String, Wide_Wide_String, Unbounded_String,
Unbounded_UTF8_String ...

Surely you wanted to cross-assign each other of them.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 11:12   ` Stefan Lucks
@ 2007-05-24 13:56     ` Dmitry A. Kazakov
  2007-05-24 14:41       ` Stefan Lucks
  2007-05-24 15:00       ` Georg Bauhaus
  0 siblings, 2 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-24 13:56 UTC (permalink / raw)


On Thu, 24 May 2007 13:12:56 +0200, Stefan Lucks wrote:

> Dmitry A. Kazakov wrote:
> 
>> [...] mere passing a variable as "in" does it as
>> well in the sense that "in T" is not an LSP-subtype of T.
> 
> You are using a very broad and generalised interpretation of the LSP. My 
> interpretation -- and I believe this is the common and usual one -- is 
> that "X: in T" in the parameterlist of a subprogram does not deal with 
> some "artificial" type "in T", just with "T".

If it dealt with T, then the following program were legal:

   procedure Foo (X : in out T);

   procedure Bar (X : in T) is
   begin
      Foo (X):  -- Fortunately illegal in Ada
   end Bar;

> The "in" is part of the 
> subprogram's contract, not a part of X's contract. So there is no conflict 
> with LSP.

But:

1. either the subprogram is a primitive operation then its contract is a
part of the type contract => subject of LSP.

2. or it is not, and then substitutability does not apply (the type does
not change) => absolutely substitutable anyway.

> Perhaps you should follow the crowd and 
> narrow your interpretation as well?

Yes, but then LSP should be re-formulated appropriately. And there is
nothing automatically wrong in disallowing operations. I would like to see
it in Ada.

>> LSP violation becomes a problem when substitutability is indeterminable
>> until run-time. In may cases we still choose to live with that. Constrained
>> Ada subtypes is an example of. Another is multi-methods Foo (X, Y : T),
>> when called on different children of T. In such cases Ada adds
>> Constraint_Error to the interface of each subprogram and things become
>> "substitutable" again.
> 
> Yes, that is an ugly patch. But it appears tricky to come up with a better 
> solution ...

Yes, this is a problem. In particular, when some property (like
Constraint_Error propagation because of substitutability violation) becomes
determinable in some, but all context. The language designer has no choice
to make it illegal. The best thing he can do is to spill a warning. This is
a way too little.

There should be a way to have a finer grained classification of
substitutability contexts than everywhere vs nowhere, such that the
programmer could help the compiler by specifying the contexts where
indeterminable substitutability were an error.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 13:56     ` Dmitry A. Kazakov
@ 2007-05-24 14:41       ` Stefan Lucks
  2007-05-24 15:46         ` Dmitry A. Kazakov
  2007-05-24 15:00       ` Georg Bauhaus
  1 sibling, 1 reply; 81+ messages in thread
From: Stefan Lucks @ 2007-05-24 14:41 UTC (permalink / raw)


On Thu, 24 May 2007, Dmitry A. Kazakov wrote:

> On Thu, 24 May 2007 13:12:56 +0200, Stefan Lucks wrote:

>> You are using a very broad and generalised interpretation of the LSP. My
>> interpretation -- and I believe this is the common and usual one -- is
>> that "X: in T" in the parameterlist of a subprogram does not deal with
>> some "artificial" type "in T", just with "T".
>
> If it dealt with T, then the following program were legal:
>
>   procedure Foo (X : in out T);
>
>   procedure Bar (X : in T) is
>   begin
>      Foo (X):  -- Fortunately illegal in Ada
>   end Bar;

The "X: in T" part in Bar's contract means "I (Bar) will abstain from 
using certain properties X might have" (where "certain properties" are 
well defined, but I am too lazy to describe them explicitely).

When calling "Foo(X)", Bar is trying to break this contract -- and 
fortunately, the compiler stops that attemtped fraud.

Note that ther is a difference between "I will abstain from using" and "I 
don't provide", and the LSP is all about the second. The fact that inside 
Bar, the programmer is forced to obey the promise made in the parameter 
list is not in violation of the LSP.

> Yes, but then LSP should be re-formulated appropriately. And there is
> nothing automatically wrong in disallowing operations. I would like to see
> it in Ada.

Is there any language that allows that? I am dreaming of something like

   type Base is new Some_Tagged_Type with ...;
     procedure Primitive_1(...);
     procedure Primitive_2(...);

   type Super is new Base with out Primitive_2; -- this is not Ada!
     -- Super "inherits" Primitive_1 from Base, but not Primitive_2.

   B: Base;
   S: Super;

   procedure Class_Wide_Base (Object: Base'Class);
   procedure Class_Wide_Super(Object: Super'Class);

   Class_Wide_Base(B);   -- legal, of course;
   Class_Wide_Super(S);  -- also legal, of course;
   Class_Wide_Super(B);  -- this should be legal!!
   Class_Wide_Base(S);   -- this should be illegal!

This would allow to "take away" operations without actually violating LSP 
(as I understand LSP). Perhaps the following would in also do the job (of 
course, I could not define S of type Super, but well ...):

   type Super is interface Base with out Primitive_2;



-- 
Stefan Lucks      (moved to Bauhaus-University Weimar, Germany)
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------





^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 13:56     ` Dmitry A. Kazakov
  2007-05-24 14:41       ` Stefan Lucks
@ 2007-05-24 15:00       ` Georg Bauhaus
  1 sibling, 0 replies; 81+ messages in thread
From: Georg Bauhaus @ 2007-05-24 15:00 UTC (permalink / raw)


On Thu, 2007-05-24 at 16:41 +0200, Stefan Lucks wrote:
> On Thu, 24 May 2007, Dmitry A. Kazakov wrote:

> > Yes, but then LSP should be re-formulated appropriately. And there is
> > nothing automatically wrong in disallowing operations. I would like to see
> > it in Ada.
> 
> Is there any language that allows that? I am dreaming of something like
> 
>    type Base is new Some_Tagged_Type with ...;
>      procedure Primitive_1(...);
>      procedure Primitive_2(...);

Interesting. Not exactly the same, but
http://www.lisp.org/HyperSpec/Body/sec_7-2.html

I guess many of the dynamically typed languages have similar
features.






^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 14:41       ` Stefan Lucks
@ 2007-05-24 15:46         ` Dmitry A. Kazakov
  0 siblings, 0 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-24 15:46 UTC (permalink / raw)


On Thu, 24 May 2007 16:41:45 +0200, Stefan Lucks wrote:

> On Thu, 24 May 2007, Dmitry A. Kazakov wrote:
> 
>> On Thu, 24 May 2007 13:12:56 +0200, Stefan Lucks wrote:
> 
>>> You are using a very broad and generalised interpretation of the LSP. My
>>> interpretation -- and I believe this is the common and usual one -- is
>>> that "X: in T" in the parameterlist of a subprogram does not deal with
>>> some "artificial" type "in T", just with "T".
>>
>> If it dealt with T, then the following program were legal:
>>
>>   procedure Foo (X : in out T);
>>
>>   procedure Bar (X : in T) is
>>   begin
>>      Foo (X):  -- Fortunately illegal in Ada
>>   end Bar;
> 
> The "X: in T" part in Bar's contract means "I (Bar) will abstain from 
> using certain properties X might have" (where "certain properties" are 
> well defined, but I am too lazy to describe them explicitely).
> 
> When calling "Foo(X)", Bar is trying to break this contract -- and 
> fortunately, the compiler stops that attemtped fraud.
> 
> Note that ther is a difference between "I will abstain from using" and "I 
> don't provide",

A contract is imposed on both sides. It would be ridiculous to abstain from
anything without another party being informed, to get something in return.

> and the LSP is all about the second. The fact that inside 
> Bar, the programmer is forced to obey the promise made in the parameter 
> list is not in violation of the LSP.

It makes no sense to consider type contracts which are a subject of LSP and
ones that don't. What is the type of an in T parameter? It leaks, you
couldn't save it.

>> Yes, but then LSP should be re-formulated appropriately. And there is
>> nothing automatically wrong in disallowing operations. I would like to see
>> it in Ada.
> 
> Is there any language that allows that? I am dreaming of something like
> 
>    type Base is new Some_Tagged_Type with ...;
>      procedure Primitive_1(...);
>      procedure Primitive_2(...);
> 
>    type Super is new Base with out Primitive_2; -- this is not Ada!

Some years ago I proposed the syntax:

   procedure Primitive_2 (...) is null;

>      -- Super "inherits" Primitive_1 from Base, but not Primitive_2.
> 
>    B: Base;
>    S: Super;
> 
>    procedure Class_Wide_Base (Object: Base'Class);
>    procedure Class_Wide_Super(Object: Super'Class);
> 
>    Class_Wide_Base(B);   -- legal, of course;
>    Class_Wide_Super(S);  -- also legal, of course;
>    Class_Wide_Super(B);  -- this should be legal!!
>    Class_Wide_Base(S);   -- this should be illegal!
> 
> This would allow to "take away" operations without actually violating LSP 
> (as I understand LSP). Perhaps the following would in also do the job (of 
> course, I could not define S of type Super, but well ...):
> 
>    type Super is interface Base with out Primitive_2;

Yep, looks like supertyping.

Apart from disallowing operations one also need an ability to drop the
implementation (representation). So that you could make Super having
members you wished, or none. The latter is stripping interfaces from
concrete types. Also if the language allowed abstract record members, then
that again would become just disallowing:

   type X is record
      I : Integer;
      ...
   end record;

   type Y is new X with ...;
   function Y.I return Integer is null;
   procedure Y.I (I : Integer) is null; -- Down with it!

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-23 22:00   ` Randy Brukardt
  2007-05-24  0:56     ` Anh Vo
@ 2007-05-24 18:27     ` Pascal Obry
  2007-05-24 18:39       ` Dmitry A. Kazakov
  1 sibling, 1 reply; 81+ messages in thread
From: Pascal Obry @ 2007-05-24 18:27 UTC (permalink / raw)
  To: Randy Brukardt

Randy Brukardt a �crit :
> Right. The most general type of interface is a limited interface; every
> interface should be declared limited if possible. (We didn't make that the
> default solely because it would be inconsistent with the rest of the
> language.) 

Well a task type is limited by default, idem for a protected object types.

Pascal.

-- 

--|------------------------------------------------------
--| Pascal Obry                           Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--|              http://www.obry.net
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 18:27     ` Pascal Obry
@ 2007-05-24 18:39       ` Dmitry A. Kazakov
  2007-05-24 18:51         ` Pascal Obry
  2007-05-24 22:44         ` Randy Brukardt
  0 siblings, 2 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-24 18:39 UTC (permalink / raw)


On Thu, 24 May 2007 20:27:25 +0200, Pascal Obry wrote:

> Randy Brukardt a �crit :
>> Right. The most general type of interface is a limited interface; every
>> interface should be declared limited if possible. (We didn't make that the
>> default solely because it would be inconsistent with the rest of the
>> language.) 
> 
> Well a task type is limited by default, idem for a protected object types.

Randy probably meant that If it were limited then one would need to
introduce "not limited" qualifier to be able to declare a non-limited
interface. (In addition to awful "not null")

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 18:39       ` Dmitry A. Kazakov
@ 2007-05-24 18:51         ` Pascal Obry
  2007-05-24 22:44         ` Randy Brukardt
  1 sibling, 0 replies; 81+ messages in thread
From: Pascal Obry @ 2007-05-24 18:51 UTC (permalink / raw)
  To: mailbox

Dmitry A. Kazakov a �crit :
> On Thu, 24 May 2007 20:27:25 +0200, Pascal Obry wrote:
> 
>> Randy Brukardt a �crit :
>>> Right. The most general type of interface is a limited interface; every
>>> interface should be declared limited if possible. (We didn't make that the
>>> default solely because it would be inconsistent with the rest of the
>>> language.) 
>> Well a task type is limited by default, idem for a protected object types.
> 
> Randy probably meant that If it were limited then one would need to
> introduce "not limited" qualifier to be able to declare a non-limited
> interface. (In addition to awful "not null")

Yep, reading the message again I think you're right.

Thanks,
Pascal.

-- 

--|------------------------------------------------------
--| Pascal Obry                           Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--|              http://www.obry.net
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 12:58         ` Maciej Sobczak
  2007-05-24 13:42           ` Dmitry A. Kazakov
@ 2007-05-24 22:08           ` Robert A Duff
  2007-07-01  1:00             ` David Thompson
  2007-05-24 22:58           ` Randy Brukardt
  2 siblings, 1 reply; 81+ messages in thread
From: Robert A Duff @ 2007-05-24 22:08 UTC (permalink / raw)


Maciej Sobczak <see.my.homepage@gmail.com> writes:

> You can do this either with access variables or with initialization of
> class wide type (which is *not* an assignment).

Well, actually, in Ada terminology, an initialization is an assignment.
There are two kinds of assignment: initialization, and
assignment_statement.  I don't particularly like that terminology, but
it's what the RM says.

> I was talking about real assignment ...

You're talking about an assignment_statement.  Best to stick to the
terms "initialization" and "assignment_statement" to avoid confusion.
And avoid the term "assignment" entirely.  ;-)

I'm just nitpicking your terminology -- I agree with your point that
there's a big difference between initialization (which creates a new
object out of whole cloth) and assign_stm (which overwrites the
left-hand side).

- Bob



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 18:39       ` Dmitry A. Kazakov
  2007-05-24 18:51         ` Pascal Obry
@ 2007-05-24 22:44         ` Randy Brukardt
  1 sibling, 0 replies; 81+ messages in thread
From: Randy Brukardt @ 2007-05-24 22:44 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1202 bytes --]

"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
news:tii7nk5e3998$.1xfer2lqmixvy.dlg@40tude.net...
> On Thu, 24 May 2007 20:27:25 +0200, Pascal Obry wrote:
>
> > Randy Brukardt a �crit :
> >> Right. The most general type of interface is a limited interface; every
> >> interface should be declared limited if possible. (We didn't make that
the
> >> default solely because it would be inconsistent with the rest of the
> >> language.)
> >
> > Well a task type is limited by default, idem for a protected object
types.
>
> Randy probably meant that If it were limited then one would need to
> introduce "not limited" qualifier to be able to declare a non-limited
> interface. (In addition to awful "not null")

Correct, that's what I meant. When Ada has a choice between non-limited and
limited, it makes you write "limited" if you meant that. That's annoying in
this case, but it's less annoying than having:

    type A is tagged record...
    type B is tagged limited record ...
    type C is tagged private;
    type D is tagged limited private;
    type E is not limited interface;
    type F is interface;

which would be forever confusing.

                          Randy.





^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 12:58         ` Maciej Sobczak
  2007-05-24 13:42           ` Dmitry A. Kazakov
  2007-05-24 22:08           ` Robert A Duff
@ 2007-05-24 22:58           ` Randy Brukardt
  2007-05-25  7:52             ` Maciej Sobczak
  2 siblings, 1 reply; 81+ messages in thread
From: Randy Brukardt @ 2007-05-24 22:58 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message
news:1180011507.159515.46920@o5g2000hsb.googlegroups.com...
...
> I was talking about real assignment - and this assumes that two
> objects already exist and we make one to be equal to the other. There
> is no way to do it right.

(Using the *correct* terminology as Bob noted)

Given the current Ada rules, what classwide assignment is good for is
*re*construction:

     procedure Do_Something(Y : out Object'Class) is
     begin
         Y :=  Constructor_Func (<some details of Y>);
     end Do_Something;

that is, the replacement of an object with different one of the same type.
The Constructor_Func is dispatching on the real type of the LHS object, so
the new object will be constructed with the proper attributes of that type.
Admittedly, this is not a common need, although I think I used it once in
the Claw builder to change properties on the fly that Claw doesn't support
changing on the fly. (Ultimately, though, we changed Claw to be more
flexible.)

                                          Randy.





^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 22:58           ` Randy Brukardt
@ 2007-05-25  7:52             ` Maciej Sobczak
  2007-05-25  8:21               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-25  7:52 UTC (permalink / raw)


On 25 Maj, 00:58, "Randy Brukardt" <r...@rrsoftware.com> wrote:

> > I was talking about real assignment - and this assumes that two
> > objects already exist and we make one to be equal to the other. There
> > is no way to do it right.
>
> (Using the *correct* terminology as Bob noted)

Yes, thank you both for explaining it - I was using the C++
terminology.

> Given the current Ada rules, what classwide assignment is good for is
> *re*construction:
>
>      procedure Do_Something(Y : out Object'Class) is
>      begin
>          Y :=  Constructor_Func (<some details of Y>);
>      end Do_Something;
>
> that is, the replacement of an object with different one of the same type.
> The Constructor_Func is dispatching on the real type of the LHS object

Interesting. In most of the cases, the factory function creates the
object of whatever type *it* decides (based on its parameters or some
other input values) and initializes the class-wide type accordingly.
The one above means "remake me, please", but it's applicability must
be greatly limited - you neatly write <some details of Y>, but it
should be really <some details of whatever-Y-happens-to-be which we
don't know here>.
That complicates this scheme a bit.

There is a very simple rule of thumb for checking whether any given OO
pattern makes sense - try to stick it to the classical geometry
example.
If it falls off, beware. :-)

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-25  7:52             ` Maciej Sobczak
@ 2007-05-25  8:21               ` Dmitry A. Kazakov
  2007-05-25 20:27                 ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-25  8:21 UTC (permalink / raw)


On 25 May 2007 00:52:21 -0700, Maciej Sobczak wrote:

> On 25 Maj, 00:58, "Randy Brukardt" <r...@rrsoftware.com> wrote:
> 
>> Given the current Ada rules, what classwide assignment is good for is
>> *re*construction:
>>
>>      procedure Do_Something(Y : out Object'Class) is
>>      begin
>>          Y :=  Constructor_Func (<some details of Y>);
>>      end Do_Something;
>>
>> that is, the replacement of an object with different one of the same type.
>> The Constructor_Func is dispatching on the real type of the LHS object
> 
> Interesting. In most of the cases, the factory function creates the
> object of whatever type *it* decides (based on its parameters or some
> other input values) and initializes the class-wide type accordingly.

Not necessarily. In one case, I generate nodes of a graph. The nodes can be
of different types regarding their persistence. For example, there are
nodes resident in the database and nodes resident in the memory etc. Now,
when creating a new node a factory moves along two axes: the standard
root/branch/leaf hierarchy and persistence stuff. For the latter the
factory receives an already existing node, to create "a new node like
this." This is not copying. Ideally it should double dispatching along both
axes. I have implemented it as:

   New_Node := Create (Get_Factory (Some_Existing_Node), ...);

> There is a very simple rule of thumb for checking whether any given OO
> pattern makes sense - try to stick it to the classical geometry
> example.
> If it falls off, beware. :-)

You certainly mean the circle-ellipse LSP controversy... (:-))

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 10:42       ` Georg Bauhaus
  2007-05-24 13:41         ` Dmitry A. Kazakov
@ 2007-05-25 16:59         ` Markus E Leypold
  2007-05-28  9:52           ` Georg Bauhaus
  1 sibling, 1 reply; 81+ messages in thread
From: Markus E Leypold @ 2007-05-25 16:59 UTC (permalink / raw)




> On Thu, 2007-05-24 at 10:02 +0200, Dmitry A. Kazakov wrote:
>
>> > Coming from C++, I have never seen any single example where assignment
>> > made sense with polymorphic hierarchies.
> ...
>> 
>> > Do you know any such example? Can you show it?
>> 
>> Marshaling objects.
>
> In fact, Eiffel has a relative, the assignment attempt
> (written "?="). And the Eiffel arguments versus Liskov/Wing
> are that the principles guiding program design should come
> from the solution to a problem, not from models when these
> cannot capture the solution. In a sense, it is argued that
> that L/W substitution (and also co/contra-variance) violate
> programming principles!

Actually I'm a strong disbeliever in your approach. I doubt, that a
solution that isn't mathematically beautiful and simple (i.e. fits a
model) is viable in the long run. Intellectual friction will hampoer
maintenance and optimization.

Regards -- Markus




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-25  8:21               ` Dmitry A. Kazakov
@ 2007-05-25 20:27                 ` Maciej Sobczak
  2007-05-26  7:48                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-25 20:27 UTC (permalink / raw)


On 25 Maj, 10:21, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > Interesting. In most of the cases, the factory function creates the
> > object of whatever type *it* decides (based on its parameters or some
> > other input values) and initializes the class-wide type accordingly.
>
> Not necessarily. In one case, I generate nodes of a graph. The nodes can be
> of different types regarding their persistence. For example, there are
> nodes resident in the database and nodes resident in the memory etc. Now,
> when creating a new node a factory moves along two axes: the standard
> root/branch/leaf hierarchy and persistence stuff. For the latter the
> factory receives an already existing node, to create "a new node like
> this." This is not copying. Ideally it should double dispatching along both
> axes. I have implemented it as:
>
>    New_Node := Create (Get_Factory (Some_Existing_Node), ...);

Above, it is the factory function that is "parameterized" on the left-
hand type - this is still much different from assignment_statement
(wow!) between two class-wide types. I'm still for banning it.

> > There is a very simple rule of thumb for checking whether any given OO
> > pattern makes sense - try to stick it to the classical geometry
> > example.
> > If it falls off, beware. :-)
>
> You certainly mean the circle-ellipse LSP controversy... (:-))

Ontological relationships have nothing to do with behavioral
substitutability. There is no controversy there, only confusion. ;-)

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-25 20:27                 ` Maciej Sobczak
@ 2007-05-26  7:48                   ` Dmitry A. Kazakov
  2007-05-27  8:30                     ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-26  7:48 UTC (permalink / raw)


On 25 May 2007 13:27:47 -0700, Maciej Sobczak wrote:

> On 25 Maj, 10:21, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> Interesting. In most of the cases, the factory function creates the
>>> object of whatever type *it* decides (based on its parameters or some
>>> other input values) and initializes the class-wide type accordingly.
>>
>> Not necessarily. In one case, I generate nodes of a graph. The nodes can be
>> of different types regarding their persistence. For example, there are
>> nodes resident in the database and nodes resident in the memory etc. Now,
>> when creating a new node a factory moves along two axes: the standard
>> root/branch/leaf hierarchy and persistence stuff. For the latter the
>> factory receives an already existing node, to create "a new node like
>> this." This is not copying. Ideally it should double dispatching along both
>> axes. I have implemented it as:
>>
>>    New_Node := Create (Get_Factory (Some_Existing_Node), ...);
> 
> Above, it is the factory function that is "parameterized" on the left-
> hand type

and the right-hand one, which was the point. But it would be enough to give
just two examples, one for LHS, another for RHS:

   X : T;
begin
   X := Read_From_File;  --- LHS
  return  X; -- RHS in the caller

> - this is still much different from assignment_statement
> (wow!) between two class-wide types.

How is it different? Note that there is little room for how to define
assignment. Within a type hierarchy there are only four variants:

T'Class x T'Class  -- non-dispatching
T x T'Class  -- dispatches on the target (C++)
T'Class x T' -- dispatches on the source
T x T -- Fully dispatching (Ada*)

In all cases X:=Y will be legal on two class-wide objects.

> I'm still for banning it.

For this you have to make assignment contravariant (non-primitive
operation) in one of its arguments. That would be a total mess, because it
would require overloading assignment for each derived type.

For the same reason all signatures with a class-wide parameter are bad,
because they lead to ambiguities in trivial cases:

type S is new T with ...;
X, Y : S;

X := Y;  -- S'Class x S'Class vs T'Class x T'Class?

You will need some sort of dominance rules to resolve that.

P.S. Probably you have in mind a "stratified" assignment which statically
checks that LHS and RHS are of the same type. Ada has it as well. This is
achieved by types cloning upon derivation:

type My_Float is new Float range ...;
-- equivalent to
-- subtype Anonymous is My_Float range ...; -- Same hierarchy
-- type My_Float is new Anonymous; -- Clone it

Unfortunately, which IMO was a big mistake, this mechanism war prohibited
for tagged types.

-----------
*  Ada's assignment is doubly dispatching. The dispatching table is a
square, the diagonal of consists of thunks:

   Finalize (LHS);
   bit-copy (LHS, RHS);
   Adjust (LHS);

Non-diagonal elements are:

   raise Constraint_Error;

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-26  7:48                   ` Dmitry A. Kazakov
@ 2007-05-27  8:30                     ` Maciej Sobczak
  2007-05-27 10:04                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-27  8:30 UTC (permalink / raw)


On 26 Maj, 09:48, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > I'm still for banning it.
>
> For this you have to make assignment contravariant (non-primitive
> operation) in one of its arguments. That would be a total mess, because it
> would require overloading assignment for each derived type.

I don't get it. I said I would ban it. There is no "for this". :-)

> For the same reason all signatures with a class-wide parameter are bad,
> because they lead to ambiguities in trivial cases:
>
> type S is new T with ...;
> X, Y : S;
>
> X := Y;  -- S'Class x S'Class vs T'Class x T'Class?
>
> You will need some sort of dominance rules to resolve that.

Why? Both X and Y are of the same type above and it is not a class
wide type in the sense that no dispatching is needed here.
In other words, the above assignment can be bound statically.

> P.S. Probably you have in mind a "stratified" assignment which statically
> checks that LHS and RHS are of the same type.

Not necessarily. I would allow different types if the
assignment_statement is overloaded for them for those who like to
introduce sort of implicit conversions.
What I worry about is the situation where *both* dynamic types are not
known statically. This is a mess.

> -----------
> *  Ada's assignment is doubly dispatching. The dispatching table is a
> square, the diagonal of consists of thunks:
>
>    Finalize (LHS);
>    bit-copy (LHS, RHS);
>    Adjust (LHS);
>
> Non-diagonal elements are:
>
>    raise Constraint_Error;

Which is a run-time thingy. It's good if it's there, but I want
stricter guarantees. You can get them by just banning
assignment_statement between class-wide types.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-27  8:30                     ` Maciej Sobczak
@ 2007-05-27 10:04                       ` Dmitry A. Kazakov
  2007-05-29  8:03                         ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-27 10:04 UTC (permalink / raw)


On 27 May 2007 01:30:36 -0700, Maciej Sobczak wrote:

> On 26 Maj, 09:48, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> I'm still for banning it.
>>
>> For this you have to make assignment contravariant (non-primitive
>> operation) in one of its arguments. That would be a total mess, because it
>> would require overloading assignment for each derived type.
> 
> I don't get it. I said I would ban it. There is no "for this". :-)

To ban something in the language you have to translate the ban into
language terms. That could be either by syntax or by semantic rules.
Because syntactically banned assignments are indistinguishable from legal
ones, the only mechanics you could use for this is matching types. The
types in question are from the same hierarchy (covariant). This lets mixing
such types. So it *must* be contravariant to be banned = the operation
(":=") will not be inherited in the argument of interest upon inheritance.

>> For the same reason all signatures with a class-wide parameter are bad,
>> because they lead to ambiguities in trivial cases:
>>
>> type S is new T with ...;
>> X, Y : S;
>>
>> X := Y;  -- S'Class x S'Class vs T'Class x T'Class?
>>
>> You will need some sort of dominance rules to resolve that.
> 
> Why?

Per definition/meaning of class-wide operations: they apply to *all* types
from the class.

> Both X and Y are of the same type above and it is not a class
> wide type in the sense that no dispatching is needed here.

Dispatching is about primitive operations acting on class-wide objects.
Class-wide operations acting on specific objects is a way different story.

>> P.S. Probably you have in mind a "stratified" assignment which statically
>> checks that LHS and RHS are of the same type.
> 
> Not necessarily. I would allow different types if the
> assignment_statement is overloaded for them for those who like to
> introduce sort of implicit conversions.
> What I worry about is the situation where *both* dynamic types are not
> known statically. This is a mess.

You cannot express it in terms of the types system. So you have to roll up
another formal types framework.

And I don't see why it is a mess. What is wrong in assignment of
UTF8_String to Wide_String, both from String'Class?

The very definition of a class says that types there share class-wide and
primitive operations. If that is not the case: ":=" is not shared, then
either it is not a class (= don't derive! if need not) or there is no ":="
(= make it limited! if unsure). Looks much like a design problem.

>> -----------
>> *  Ada's assignment is doubly dispatching. The dispatching table is a
>> square, the diagonal of consists of thunks:
>>
>>    Finalize (LHS);
>>    bit-copy (LHS, RHS);
>>    Adjust (LHS);
>>
>> Non-diagonal elements are:
>>
>>    raise Constraint_Error;
> 
> Which is a run-time thingy. It's good if it's there, but I want
> stricter guarantees. You can get them by just banning
> assignment_statement between class-wide types.

No, because that would be inconsistent. A doubly dispatching operation
*has* a square table. There is nothing to do about it. You have to make it
something else instead, I have listed possible variants earlier. These
alternatives are mess. Hardwired rules imposed on assignments were an even
bigger mess. It is bad enough that Ada has assignment defined as an
statement, rather than a procedure call. There is nothing special in
assignments. So your mechanism, if any, should be universally applied to
all operations with multiple arguments from the same types hierarchy.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-25 16:59         ` Markus E Leypold
@ 2007-05-28  9:52           ` Georg Bauhaus
  2007-05-28 11:50             ` Dmitry A. Kazakov
                               ` (2 more replies)
  0 siblings, 3 replies; 81+ messages in thread
From: Georg Bauhaus @ 2007-05-28  9:52 UTC (permalink / raw)


Markus E Leypold wrote:
>  the Eiffel arguments versus Liskov/Wing
>> are that the principles guiding program design should come
>> from the solution to a problem, not from models when these
>> cannot capture the solution. In a sense, it is argued that
>> that L/W substitution (and also co/contra-variance) violate
>> programming principles!
> 
> Actually I'm a strong disbeliever in your approach. I doubt, that a
> solution that isn't mathematically beautiful and simple (i.e. fits a
> model) is viable in the long run. Intellectual friction will hampoer
> maintenance and optimization.

There is nothing wrong with a mathematically "beautiful"
and simple solution. But when

(1) there is a perfectly simple, straight forward, working
    solution,

(2) the solution matches the problem specification 1:1,

(3) the solution is partially incongruent with a mathematical
    model,

(4) because of (3), the solution (1)+(2) is discarded,

there is something wrong. First, because a belief in the model as
a conditio sine qua non is not justifiable, neither on
business terms, nor on technical terms (both because of (1)+(2)).
Second, while the existing solution suggests that there might be
a better model still the other model is preferred, and the existing
solution runs the risk of being discarded.

I bet that as soon as someone popularizes a mathematical model
that does away with variance issues for example, then people will
stop fighting over contravariance versus covariance.
Until then, only this or that kind of variance is allowed to exist,
for either mathematical or problem domain reasons, because the
other solution cannot but create an unmaintainable mess...

If I had the money, I'd put up a challange that triggers some
programming oriented model research (as opposed to research that
will move the focus of modelling to formal properties of models
only.)



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-28  9:52           ` Georg Bauhaus
@ 2007-05-28 11:50             ` Dmitry A. Kazakov
  2007-05-28 23:32               ` Georg Bauhaus
  2007-05-28 13:47             ` Markus E Leypold
  2007-05-28 13:56             ` Markus E Leypold
  2 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-28 11:50 UTC (permalink / raw)


On Mon, 28 May 2007 11:52:22 +0200, Georg Bauhaus wrote:

> There is nothing wrong with a mathematically "beautiful"
> and simple solution. But when
> 
> (1) there is a perfectly simple, straight forward, working
>     solution,
> 
> (2) the solution matches the problem specification 1:1,
> 
> (3) the solution is partially incongruent with a mathematical
>     model,
> 
> (4) because of (3), the solution (1)+(2) is discarded,
> 
> there is something wrong.

Nothing is wrong except naive LSP. When understood naively it is
mathematically unsound. The problem of is that it tries to make very strong
statements about sets (of values) as whole rather than individual elements
of.

A mathematical interpretation of naive LSP is:

Any true proposition involving the name of the set T stays true when this
name is substituted by the name of another set S

This is extremely strong. Controversies like Circle-Ellipse are
predictable:

   forall X,Y exists Ellipse with the axis X,Y

"Circle" cannot substitute "Ellipse" in above. All usual ways to save LSP
are about limiting the substitution context and protecting some appearances
of the type from substitution (e.g. contravariance). 

> If I had the money, I'd put up a challange that triggers some
> programming oriented model research (as opposed to research that
> will move the focus of modelling to formal properties of models
> only.)

Difference?

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-28  9:52           ` Georg Bauhaus
  2007-05-28 11:50             ` Dmitry A. Kazakov
@ 2007-05-28 13:47             ` Markus E Leypold
  2007-05-28 23:12               ` Georg Bauhaus
  2007-05-28 13:56             ` Markus E Leypold
  2 siblings, 1 reply; 81+ messages in thread
From: Markus E Leypold @ 2007-05-28 13:47 UTC (permalink / raw)



> Markus E Leypold wrote:
>>  the Eiffel arguments versus Liskov/Wing
>>> are that the principles guiding program design should come
>>> from the solution to a problem, not from models when these
>>> cannot capture the solution. In a sense, it is argued that
>>> that L/W substitution (and also co/contra-variance) violate
>>> programming principles!
>> Actually I'm a strong disbeliever in your approach. I doubt, that a
>> solution that isn't mathematically beautiful and simple (i.e. fits a
>> model) is viable in the long run. Intellectual friction will hampoer
>> maintenance and optimization.
>
> There is nothing wrong with a mathematically "beautiful"
> and simple solution. But when
>
> (1) there is a perfectly simple, straight forward, working
>     solution,
>
> (2) the solution matches the problem specification 1:1,
>
> (3) the solution is partially incongruent with a mathematical
>     model,
>
> (4) because of (3), the solution (1)+(2) is discarded,
>
> there is something wrong. 


But now you're arguing quite another case. You said

>>> that the principles guiding program design should come from the
>>> solution to a problem, not from models

(But perhaps I'm reading even that quote wrongly). You've been
basically advocating to invent new program architectures for every
problem/solution pair, i.e. have a solution first than fit the "model"
(language architecture, whatever) on your solution. If you can afford
to design a domain language for every problem you have -- fine. If
not, I suggest that the language designers hae

Basically the language design is a contract: If you can fit your
programming in a certain conceptual pattern (be it typing, OO or
functional programming) the compiler builder promises that the
compiler will produce a correct and (often) fast or efficient program
with the advertised semantics.

If you don't want that contract, I don't know what you get. Probably
C, but even that has a "model" of sorts. Or SAP ...

Bashing theory and inisiting on "fudged" ad hoc solutions ("it just
works, so why not" has brought programming to the place where it is
today: A mess. "If you do this you will get that, but we don't know
why that is so and how that fits in with the rest which follows a
different perhaps not even contradicting rule".

I repeat, that I'm a strong believer in complete, consistent and
"closed" solutions in programming language or system design without
"undefined" borderline cases. Only such a design guarantees that you
know where you stand, are prepared for the next step in evolution and
can take it without breaking everything from the past.

Regards -- Markus






^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-28  9:52           ` Georg Bauhaus
  2007-05-28 11:50             ` Dmitry A. Kazakov
  2007-05-28 13:47             ` Markus E Leypold
@ 2007-05-28 13:56             ` Markus E Leypold
  2007-05-28 23:00               ` Georg Bauhaus
  2 siblings, 1 reply; 81+ messages in thread
From: Markus E Leypold @ 2007-05-28 13:56 UTC (permalink / raw)




> I bet that as soon as someone popularizes a mathematical model
> that does away with variance issues for example, then people will
> stop fighting over contravariance versus covariance.
> Until then, only this or that kind of variance is allowed to exist,
> for either mathematical or problem domain reasons, because the
> other solution cannot but create an unmaintainable mess...
>
> If I had the money, I'd put up a challange that triggers some
> programming oriented model research (as opposed to research that
> will move the focus of modelling to formal properties of models
> only.)


Somehow you seem to think, we can just do away with the models, if we
just approach it right. That ignores (a) historical experience -- see
structured programming which has become so commonplace that we don't
percieve it as exceptional any more, and (b) that there is no
alternative[tm]: As you can't do quantum mechnics without a certain
amount of a certain sort of mathematics you cannot state a contract or
specify a design without some sort of logical and basically
mathematical model behind. Without you don't even have a language to
complain to your compiler writer about bugs.

Progress, well, progresses. We get used to it, but it usually doesn't
go away. The hope to get rid of "the variance issue" (which actually
is just a point in how contracts can be stated precisely) after we
discovered it, is just misguided.

Regards -- Markus





^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-28 13:56             ` Markus E Leypold
@ 2007-05-28 23:00               ` Georg Bauhaus
  0 siblings, 0 replies; 81+ messages in thread
From: Georg Bauhaus @ 2007-05-28 23:00 UTC (permalink / raw)


Markus E Leypold wrote:
> 
>> I bet that as soon as someone popularizes a mathematical model

>> If I had the money, I'd put up a challange that triggers some
>> programming oriented model research

> Somehow you seem to think, we can just do away with the models, if we
> just approach it right.

No. We might profit from mathematical models that are even better
because they better reflect what programming staff needs. (Reminds me of
the intent that has led to Ada.)

Perhaps this was misleading:
>> Until then, only this or that kind of variance is allowed to exist,
>> for either mathematical or problem domain reasons, because the
>> other solution cannot but create an unmaintainable mess...

WRT variance, one of Meyer's examples is the allocation of boys and
girls to dormitories.(*)
  Boys and girls are two sexes of the human kind, hence Boy and
Girl are derived from the type Human. Girls' dormitories
and boys' dormitories are two derived types of domitories.
There is a procedure for each Human object, say Person,

  Person.Accomodate(dorm => ?Dormitory?);

that will place a person in a dormitory, such that girls sleep
in the girls' dormitory and boys sleep in the boys' dormitory.
  Shall we have a procedure for boys (or girls) that just takes
a person of the respective sex and places the person in a
dormitory'class?

  procedure Accomodate(who: Boy; dorm: Dormitory'class);

(Of course, the "moral rule" depends on who you ask, but this example
presumes gender segregation in any sexual sense.)

There is a subsection in the corresponding section (OOSC2, �17) entitled
"Polymorphic perversity". It alludes to the consequences of
different "co/contravariance policies", speaking about a procedure that
expresses "sharing a room".

  type Boy is new Human with private;
  overriding
  procedure Share(self: in out Boy; other: in out Boy);

This definition meets the requirement that a boy and a girl shall not
share a room.
OTOH, there are also technical arguments in favor of defining a
procedure that doesn't vary in the same "direction" as the type,
thus

  type Boy is new Human with private;
  overriding
  procedure Share(self: in out Boy; other: in out Human'class);

Which co/contravariance policy is right? And therefore, can we
decide which model is the right one if all that we can say about a
model is that it is mathematically sound in some sense?
  Of course it is, but soundness is very likely just a necessary
precondition. Whether a model is sufficient, and more precisely,
in which cases it is sufficient, these are the more interesting
questions (to me, at least).

(*) (There are certainly other solutions that do not
involve inheritance, but this is the illustration given. I'm varying it
slightly.)



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-28 13:47             ` Markus E Leypold
@ 2007-05-28 23:12               ` Georg Bauhaus
  0 siblings, 0 replies; 81+ messages in thread
From: Georg Bauhaus @ 2007-05-28 23:12 UTC (permalink / raw)


Markus E Leypold wrote:

>>>> that the principles guiding program design should come from the
>>>> solution to a problem, not from models
> 
> (But perhaps I'm reading even that quote wrongly). You've been
> basically advocating to invent new program architectures for every
> problem/solution pair, i.e. have a solution first than fit the "model"
> (language architecture, whatever) on your solution. 

No, not at all. Rather, much like biology starts from collecting
observations of living things, "prographology" may again
start from collecting observations of source texts and their authors.
Then we will see a number of cases

(1)  the source texts do not solve the problems
(2)  the source texts do solve the problems, but we can't see how
(3)  the source texts solve the problems and we discover a pattern

Now, if a model contradicts (3), are you saying that the model is
right nevertheless and (3) is not relevant?



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-28 11:50             ` Dmitry A. Kazakov
@ 2007-05-28 23:32               ` Georg Bauhaus
  2007-05-29 12:05                 ` Dmitry A. Kazakov
  2007-05-29 13:33                 ` Georg Bauhaus
  0 siblings, 2 replies; 81+ messages in thread
From: Georg Bauhaus @ 2007-05-28 23:32 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

>> If I had the money, I'd put up a challange that triggers some
>> programming oriented model research (as opposed to research that
>> will move the focus of modelling to formal properties of models
>> only.)
> 
> Difference?

The idealized difference between programming oriented (model) research
and researching formal properties of models is that, in the first case,
you do not start from models only and then find different models,
refine existing models etc.. You start in the programming shop, so to
speak.
  In fact, this is happening. For example, timing properties of
co-operating procedures are captured in mathematical models. This is
different from the ubiquitously alleged mathematicality of programming:
that programs model mathematical functions. Some programs do, but is this
all that matters? Shouldn't the relation between programs and mathematical
functions be reversed? Wait, it is!



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-27 10:04                       ` Dmitry A. Kazakov
@ 2007-05-29  8:03                         ` Maciej Sobczak
  2007-05-29 13:18                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-29  8:03 UTC (permalink / raw)


On 27 Maj, 12:04, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> To ban something in the language you have to translate the ban into
> language terms. That could be either by syntax or by semantic rules.
> Because syntactically banned assignments are indistinguishable from legal
> ones, the only mechanics you could use for this is matching types. The
> types in question are from the same hierarchy (covariant). This lets mixing
> such types. So it *must* be contravariant to be banned = the operation
> (":=") will not be inherited in the argument of interest upon inheritance.

OK, now I see your point. I have nothing against following this path -
assignment statement *is* special anyway. What could go wrong if we
say that assignment is not inherited?

> And I don't see why it is a mess. What is wrong in assignment of
> UTF8_String to Wide_String, both from String'Class?

Probably design issue. Character encoding can/should be a strategy
inside a String, you don't need to subclass the whole thing just for
it. There are many aspects on which you could parameterize String and
with some of them being orthogonal you could quickly end up with
milion leaf classes.

> The very definition of a class says that types there share class-wide and
> primitive operations. If that is not the case: ":=" is not shared, then
> either it is not a class (= don't derive! if need not) or there is no ":="
> (= make it limited! if unsure). Looks much like a design problem.

Yes. That's why I say that I have never seen any reasonable hierarchy
that supports assignments.

> There is nothing special in
> assignments.

Yes, there is - they are generated. This is deceptive, because it
makes one think that it should all work by magic.
Another reason why they are special is that they are intuitively
associated with some particular effects and these effects cannot be
reasonably provided in an automated way. That's why I think that
assignments of class-wide types should be forbidden.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-28 23:32               ` Georg Bauhaus
@ 2007-05-29 12:05                 ` Dmitry A. Kazakov
  2007-05-29 13:33                 ` Georg Bauhaus
  1 sibling, 0 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-29 12:05 UTC (permalink / raw)


On Tue, 29 May 2007 01:32:50 +0200, Georg Bauhaus wrote:

> Dmitry A. Kazakov wrote:
> 
>>> If I had the money, I'd put up a challange that triggers some
>>> programming oriented model research (as opposed to research that
>>> will move the focus of modelling to formal properties of models
>>> only.)
>> 
>> Difference?
> 
> The idealized difference between programming oriented (model) research
> and researching formal properties of models is that, in the first case,
> you do not start from models only and then find different models,
> refine existing models etc.. You start in the programming shop, so to
> speak.

But an application program is always a model of some physical reality.

>   In fact, this is happening. For example, timing properties of
> co-operating procedures are captured in mathematical models. This is
> different from the ubiquitously alleged mathematicality of programming:
> that programs model mathematical functions. Some programs do, but is this
> all that matters?

Yes, because application programming deals with mathematical models of the
reality. I doubt you could skip this abstraction layer.

> Shouldn't the relation between programs and mathematical
> functions be reversed? Wait, it is!

You can consider mathematics or parts of as programming on some "axiomatic
hardware". But this is not programming in usual, narrow sense, which
applies only to physical hardware.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-29  8:03                         ` Maciej Sobczak
@ 2007-05-29 13:18                           ` Dmitry A. Kazakov
  2007-05-29 13:32                             ` Dmitry A. Kazakov
  2007-05-29 15:34                             ` Maciej Sobczak
  0 siblings, 2 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-29 13:18 UTC (permalink / raw)


On 29 May 2007 01:03:23 -0700, Maciej Sobczak wrote:

> On 27 Maj, 12:04, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>> To ban something in the language you have to translate the ban into
>> language terms. That could be either by syntax or by semantic rules.
>> Because syntactically banned assignments are indistinguishable from legal
>> ones, the only mechanics you could use for this is matching types. The
>> types in question are from the same hierarchy (covariant). This lets mixing
>> such types. So it *must* be contravariant to be banned = the operation
>> (":=") will not be inherited in the argument of interest upon inheritance.
> 
> OK, now I see your point. I have nothing against following this path -
> assignment statement *is* special anyway. What could go wrong if we
> say that assignment is not inherited?

Then you will have a messy bunch of overloaded ones. There are two variants
of:

1. Use of T'Class, I considered this in a previous post, it is ambiguous.

2. Non-primitive operation (ugly hack). This will not work on class-wide
arguments:

   X : T'Class := Y; -- Illegal, ":=" isn't defined on LHS T'Class

>> And I don't see why it is a mess. What is wrong in assignment of
>> UTF8_String to Wide_String, both from String'Class?
> 
> Probably design issue. Character encoding can/should be a strategy
> inside a String, you don't need to subclass the whole thing just for
> it. There are many aspects on which you could parameterize String and
> with some of them being orthogonal you could quickly end up with
> milion leaf classes.

So? This is exactly the reason why I want to keep them all in one class.
Encoding is a constraint put on the object. It is mapped to a type to be
able to implement string operations independently, for each encoding
through dispatching rather than by ugly nested case-statements.

And what about fixed vs. bounded vs. unbounded axis? Why a fixed string
shouldn't be assigned to an unbounded one and reverse? How are you going to
design such stuff without polymorphism? By cut'n'paste, as RM does? At some
point they too had got tired:

"... For each of the packages Strings.Fixed, Strings.Bounded,
Strings.Unbounded, and Strings.Maps.Constants the corresponding wide string
package has the same contents except that 

� Wide_Space replaces Space 

� Wide_Character replaces Character 

� Wide_String replaces String ..." (:-))

>> The very definition of a class says that types there share class-wide and
>> primitive operations. If that is not the case: ":=" is not shared, then
>> either it is not a class (= don't derive! if need not) or there is no ":="
>> (= make it limited! if unsure). Looks much like a design problem.
> 
> Yes. That's why I say that I have never seen any reasonable hierarchy
> that supports assignments.

Strings above.

>> There is nothing special in
>> assignments.
> 
> Yes, there is - they are generated. This is deceptive, because it
> makes one think that it should all work by magic.

It means that the language is unable to express assignments in its own
terms. I don't want such language. In fact, the rules you propose for
assignments can be expressed in Ada terms:

type X is private;
type Y is new Y;  -- Done

Don't use classes if you don't want to assign them.

> Another reason why they are special is that they are intuitively
> associated with some particular effects and these effects cannot be
> reasonably provided in an automated way. That's why I think that
> assignments of class-wide types should be forbidden.

No, it is much simpler to provide multi-methods and make it consistent. The
only problem Ada has with assignment is that it is a fake MD. If it were a
true MD, then upon inheritance (per extension) from a tagged private T, the
compiler would complain: "hey, I don't know how to assign T to S!" This
would force you to override S := T in a reasonable way (existing for
String) or else to rethink your allegedly wrong design. Presently Ada
silently generates raise Constraint_Error, which is not good.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-29 13:18                           ` Dmitry A. Kazakov
@ 2007-05-29 13:32                             ` Dmitry A. Kazakov
  2007-05-29 15:34                             ` Maciej Sobczak
  1 sibling, 0 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-29 13:32 UTC (permalink / raw)


On Tue, 29 May 2007 15:18:58 +0200, Dmitry A. Kazakov wrote:

> type X is private;
> type Y is new Y;  -- Done

type Y is new X;  -- Done

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-28 23:32               ` Georg Bauhaus
  2007-05-29 12:05                 ` Dmitry A. Kazakov
@ 2007-05-29 13:33                 ` Georg Bauhaus
  2007-05-29 17:29                   ` Dmitry A. Kazakov
  1 sibling, 1 reply; 81+ messages in thread
From: Georg Bauhaus @ 2007-05-29 13:33 UTC (permalink / raw)


On Tue, 2007-05-29 at 14:05 +0200, Dmitry A. Kazakov wrote:

> > The idealized difference between programming oriented (model) research
> > and researching formal properties of models is that, in the first case,
> > you do not start from models only and then find different models,
> > refine existing models etc.. You start in the programming shop, so to
> > speak.
> 
> But an application program is always a model of some physical reality.

Yes. I just think that programs should be written with (a model
of) physical reality in mind, but employ Off-the-Shelf standard
models only if applicable.

> >   In fact, this is happening. For example, timing properties of
> > co-operating procedures are captured in mathematical models. This is
> > different from the ubiquitously alleged mathematicality of programming:
> > that programs model mathematical functions. Some programs do, but is this
> > all that matters?
> 
> Yes, because application programming deals with mathematical models of the
> reality. I doubt you could skip this abstraction layer.

Programming deals with models of reality and, empirically, most of the
time these models have properties that can be described using
mathematics. Which is a good thing.
However, asking for *mathematical* models of reality is asking for
a clean room definition of the physical model in terms of mathematics.
Many programs just happen to be a model of reality, and they still
work well, even though they were not mathematically designed.
The programmers are hardly aware of every conceivable mathematical
property of their model. Still, they write sound programs.
Can mathematics capture this process?

Next, how much detail can you reasonably place in a formal
specification of a model? Programming in UML seems to be over the
top, IMHO, whereas modeling in UML using a reasonably small set
of L isn't, of course.

> > Shouldn't the relation between programs and mathematical
> > functions be reversed? Wait, it is!
> 
> You can consider mathematics or parts of as programming on some "axiomatic
> hardware".

What I want is the mathematics of program models, more than programming
to satisfy mathematics. BTW, what is the best suited mathematical
structure that (minimally) describes the loop

   while k < 100 loop
     k := Integer'succ(k);
   end loop;

and how does it help?





^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-29 13:18                           ` Dmitry A. Kazakov
  2007-05-29 13:32                             ` Dmitry A. Kazakov
@ 2007-05-29 15:34                             ` Maciej Sobczak
  2007-05-29 17:07                               ` Dmitry A. Kazakov
  1 sibling, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-29 15:34 UTC (permalink / raw)


On 29 Maj, 15:18, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > OK, now I see your point. I have nothing against following this path -
> > assignment statement *is* special anyway. What could go wrong if we
> > say that assignment is not inherited?
>
> Then you will have a messy bunch of overloaded ones.

If I need them and can reasonably implement them, yes.
The design complexity of this will be somewhere there anyway.

> There are two variants
> of:
>
> 1. Use of T'Class, I considered this in a previous post, it is ambiguous.

I would ban it. :-)

> 2. Non-primitive operation (ugly hack). This will not work on class-wide
> arguments:
>
>    X : T'Class := Y; -- Illegal, ":=" isn't defined on LHS T'Class

This is not assignment_statement. This is initialization and I have
nothing against it. Actually, it is no different from initialization
of subprogram parameters and as such is not only harmless, it is
essential.

We are talking about real:

X := Y;

:-)

> >> And I don't see why it is a mess. What is wrong in assignment of
> >> UTF8_String to Wide_String, both from String'Class?
>
> > Probably design issue.
[...]
> So? This is exactly the reason why I want to keep them all in one class.

That's what I'm talking about (but then, we might be using different
terminology).
I say that you need one type String, that possibly uses strategy
internally to delegate details like encoding. You don't need encoding
to "leak out" at the level of types that the final user operates on.

> Encoding is a constraint put on the object. It is mapped to a type to be
> able to implement string operations independently, for each encoding
> through dispatching rather than by ugly nested case-statements.

You can (and should) have dispatching internally in the implementation
of operations of String. I'm not proposing any case statements here!

> And what about fixed vs. bounded vs. unbounded axis?

This is also interesting, but in a different way. :-)
Treating everything in pure OO way, these might be again internal
strategies of a single String type. Think of stream buffers in streams
(C++, Java).
On the other hand, purity is not always beneficial and from the
performance point of view fixed string provides the opportunity to get
rid of dynamic allocation. But to benefit from this opportunity, you'd
better not mess with OO but distinguish them using compile-time
polymorphism. In C++ we have policy-based class design for it.

> Why a fixed string
> shouldn't be assigned to an unbounded one and reverse?

Of course it should! What about template methods? ;-)
(hint: constructors and assignments in STL containers are templated
exactly to allow freedom in this aspect)

> How are you going to
> design such stuff without polymorphism?

Compile-time polymorphism works just fine and if you really need run-
time parameterization, you can get it with internal strategies (again,
think streambuf in streams in C++).

> By cut'n'paste, as RM does? At some
> point they too had got tired:
[...]

Yes, I have noticed. :-)
Looks like you guys need *real* templates. ;-)

> > Another reason why they are special is that they are intuitively
> > associated with some particular effects and these effects cannot be
> > reasonably provided in an automated way. That's why I think that
> > assignments of class-wide types should be forbidden.
>
> No, it is much simpler to provide multi-methods and make it consistent.

But then the compiler would need to either force you to implement the
whole square of assignment operations, or use run-time checks to
discover whether the assignment within a given pair of leaf types is
provided.
The former is unrealistic with evolving or open-ended hierarchies, the
latter smells more like Python than Ada.

> Presently Ada
> silently generates raise Constraint_Error, which is not good.

Agreed.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-29 15:34                             ` Maciej Sobczak
@ 2007-05-29 17:07                               ` Dmitry A. Kazakov
  2007-05-30  7:40                                 ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-29 17:07 UTC (permalink / raw)


On 29 May 2007 08:34:18 -0700, Maciej Sobczak wrote:

> On 29 Maj, 15:18, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> OK, now I see your point. I have nothing against following this path -
>>> assignment statement *is* special anyway. What could go wrong if we
>>> say that assignment is not inherited?
>>
>> Then you will have a messy bunch of overloaded ones.
> 
> If I need them and can reasonably implement them, yes.
> The design complexity of this will be somewhere there anyway.

And for the reason of complexity you drop any compiler support it might
provide you? (:-))
 
>> There are two variants
>> of:
>>
>> 1. Use of T'Class, I considered this in a previous post, it is ambiguous.
> 
> I would ban it. :-)

Sure

>> 2. Non-primitive operation (ugly hack). This will not work on class-wide
>> arguments:
>>
>>    X : T'Class := Y; -- Illegal, ":=" isn't defined on LHS T'Class
> 
> This is not assignment_statement. This is initialization and I have
> nothing against it. Actually, it is no different from initialization
> of subprogram parameters and as such is not only harmless, it is
> essential.
> 
> We are talking about real:
> 
> X := Y;

Huh, how are going to design a non-referential container of T'Class? You
need:

   procedure Insert (..., Element : T'Class) is
   begin
      ...
      Slot := new T'Class'(Element);
   -- Slot := Element; -- in a better Ada
      ...

>>>> And I don't see why it is a mess. What is wrong in assignment of
>>>> UTF8_String to Wide_String, both from String'Class?
>>
>>> Probably design issue.
> [...]
>> So? This is exactly the reason why I want to keep them all in one class.
> 
> That's what I'm talking about (but then, we might be using different
> terminology).
> I say that you need one type String, that possibly uses strategy
> internally to delegate details like encoding. You don't need encoding
> to "leak out" at the level of types that the final user operates on.

That would be indeed a mess. How would you pass an UTF-8 string to GTK+
which knows nothing about your fancy patterns? Why don't you use the
advantages of the types system? And anyway, let's forget about public
interfaces, if privately it is still one class, then where is a difference?
The only real alternative to classes is a time machine, back to 70s, back
to case-statements. (:-))

>> Encoding is a constraint put on the object. It is mapped to a type to be
>> able to implement string operations independently, for each encoding
>> through dispatching rather than by ugly nested case-statements.
> 
> You can (and should) have dispatching internally in the implementation
> of operations of String. I'm not proposing any case statements here!

Here you are. What is the difference between internally and externally
dispatching assignments?

>> And what about fixed vs. bounded vs. unbounded axis?
> 
> This is also interesting, but in a different way. :-)

Why? It is all same: a set of types considered equivalent, hence allowing
cross assignments...

>> Why a fixed string
>> shouldn't be assigned to an unbounded one and reverse?
> 
> Of course it should!

q.e.d.

> What about template methods? ;-)

Static polymorphism is exactly what I am trying to get rid of... (:-))

>> How are you going to
>> design such stuff without polymorphism?
> 
> Compile-time polymorphism works just fine and if you really need run-
> time parameterization, you can get it with internal strategies (again,
> think streambuf in streams in C++).

Static polymorphism does not allow mixing types. Further you cannot design
a library for formatting strings which would not be generic itself.
Generics is a dead end.
 
>> By cut'n'paste, as RM does? At some
>> point they too had got tired:
> [...]
> 
> Yes, I have noticed. :-)
> Looks like you guys need *real* templates. ;-)

Surely they have them ... for formatting RM texts. See the difference?
(:-))

>>> Another reason why they are special is that they are intuitively
>>> associated with some particular effects and these effects cannot be
>>> reasonably provided in an automated way. That's why I think that
>>> assignments of class-wide types should be forbidden.
>>
>> No, it is much simpler to provide multi-methods and make it consistent.
> 
> But then the compiler would need to either force you to implement the
> whole square of assignment operations, or use run-time checks to
> discover whether the assignment within a given pair of leaf types is
> provided.
> The former is unrealistic with evolving or open-ended hierarchies, the
> latter smells more like Python than Ada.

The latter is what Ada does now, and I agree that this is not Ada (TM).

The former is quite possible and IMO is the only right way to go. Note that
the language should also allow declaring symmetries of the methods to
reduce the number of independent variants. For example, by declaring an
operation commutative.

IMO, multi-methods is not a trick. What I really don't know how to do is
true multiple dispatch (on different types hierarchies). The requirement is
same: dispatch never fails to Constraint_Error.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-29 13:33                 ` Georg Bauhaus
@ 2007-05-29 17:29                   ` Dmitry A. Kazakov
  2007-05-29 20:46                     ` Georg Bauhaus
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-29 17:29 UTC (permalink / raw)


On Tue, 29 May 2007 15:33:54 +0200, Georg Bauhaus wrote:

> On Tue, 2007-05-29 at 14:05 +0200, Dmitry A. Kazakov wrote:
> 
>>>   In fact, this is happening. For example, timing properties of
>>> co-operating procedures are captured in mathematical models. This is
>>> different from the ubiquitously alleged mathematicality of programming:
>>> that programs model mathematical functions. Some programs do, but is this
>>> all that matters?
>> 
>> Yes, because application programming deals with mathematical models of the
>> reality. I doubt you could skip this abstraction layer.
> 
> Programming deals with models of reality and, empirically, most of the
> time these models have properties that can be described using
> mathematics. Which is a good thing.
> However, asking for *mathematical* models of reality is asking for
> a clean room definition of the physical model in terms of mathematics.

Any mathematical model is still an approximation. The reason why
mathematics is better here than ad-hocery of outsourced programmers, is
that the mathematical "hardware" is far more powerful than one of Intel.
Hence there is a far less constraints imposed upon you when you model it
mathematically. So even if you had a very good mathematical model it might
be quite difficult to implement it on the machine hardware. This is all
programming is about - porting mathematics. (:-)) To model the reality in
just one hop might be just impossible for a normal programmer. You cannot
rely on Nobel Price laureates, they are rare, expensive and uninterested in
our problems.

> Many programs just happen to be a model of reality, and they still
> work well, even though they were not mathematically designed.
> The programmers are hardly aware of every conceivable mathematical
> property of their model. Still, they write sound programs.

How can you know that? (:-)) Let's take the braking control system for your
next car...

>>> Shouldn't the relation between programs and mathematical
>>> functions be reversed? Wait, it is!
>> 
>> You can consider mathematics or parts of as programming on some "axiomatic
>> hardware".
> 
> What I want is the mathematics of program models, more than programming
> to satisfy mathematics. BTW, what is the best suited mathematical
> structure that (minimally) describes the loop
> 
>    while k < 100 loop
>      k := Integer'succ(k);
>    end loop;

Ordered set, mathematical induction etc.

> and how does it help?

A lot. For example it can tell the code reviewer that the above program is
equivalent to:

    if k < 100 then
      k := 100;
   end if;

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-29 17:29                   ` Dmitry A. Kazakov
@ 2007-05-29 20:46                     ` Georg Bauhaus
  2007-05-30  7:53                       ` Dmitry A. Kazakov
  2007-05-30 13:18                       ` Georg Bauhaus
  0 siblings, 2 replies; 81+ messages in thread
From: Georg Bauhaus @ 2007-05-29 20:46 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
>  This is all
> programming is about - porting mathematics. (:-)) To model the reality in
> just one hop might be just impossible for a normal programmer. You cannot
> rely on Nobel Price laureates, they are rare, expensive and uninterested in
> our problems.

OK. So why should a normal programmer like me consider it a cost effective
idea to try to construct a proven mathematical model for my daily work?
I do sometimes run Prolog or SETL to help me with higher level
specifications and find this quite helpful. OTOH, in these cases I am
drawing upon models that are different from, say, LSP. They are more like
general purpose mathematical building blocks. LSP is a formal
and well defined whole. Arguably, it isn't a good model from some points of
view, even though there is "mathematics" in it which, you say, programming
will port to a program.



>> Many programs just happen to be a model of reality, and they still
>> work well, even though they were not mathematically designed.
>> The programmers are hardly aware of every conceivable mathematical
>> property of their model. Still, they write sound programs.
> 
> How can you know that? (:-)) Let's take the braking control system for your
> next car...

I hear that Mercedes engineers do not yet want to replace
the steering wheel with a embedded computer joy stick thing ... :-)
I think the argument is that a car must make quicker moves in more
constraining environments than your average airliner. 



>> What I want is the mathematics of program models, more than programming
>> to satisfy mathematics. BTW, what is the best suited mathematical
>> structure that (minimally) describes the loop
>>
>>    while k < 100 loop
>>      k := Integer'succ(k);
>>    end loop;
> 
> Ordered set, mathematical induction etc.

Uhm, can we have less than a group?


>> and how does it help?
> 
> A lot. For example it can tell the code reviewer that the above program is
> equivalent to:
> 
>     if k < 100 then
>       k := 100;
>    end if;

Making assumptions about k ... This is how mathematics can make us prefer
default perspectives by moving all important points of view behind Formal
Mountains. The above change wouldn't have helped at all, on the contrary,

   for k'Address use ...;

What's the mathematics of that, then?

:-)



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-29 17:07                               ` Dmitry A. Kazakov
@ 2007-05-30  7:40                                 ` Maciej Sobczak
  2007-05-30  8:43                                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-30  7:40 UTC (permalink / raw)


On 29 Maj, 19:07, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > We are talking about real:
>
> > X := Y;
>
> Huh, how are going to design a non-referential container of T'Class?

I don't. :-)
Polymorphism and references come hand in hand if you need the ability
to reassign. Copy-initialization is the only place where you can
safely get away with "values" of T'Class.
I think that the mess has its source in the push to have T'Class
behaving like normal value.


> > I say that you need one type String, that possibly uses strategy
> > internally to delegate details like encoding. You don't need encoding
> > to "leak out" at the level of types that the final user operates on.
>
> That would be indeed a mess. How would you pass an UTF-8 string to GTK+
> which knows nothing about your fancy patterns?

Then it should know. Otherwise there is no way it can interpret
correctly what I pass as parameters, unless you want to have
"implicit" conversions for parameters.

> Why don't you use the
> advantages of the types system?

I do use it, I just don't elevate implementation details to the level
of type that is handled directly by the user.

> > You can (and should) have dispatching internally in the implementation
> > of operations of String. I'm not proposing any case statements here!
>
> Here you are. What is the difference between internally and externally
> dispatching assignments?

Assignment is an operation that is meaningful syntactically - that's
why it is so tempting. Internally you can have anything else,
including regular subprogram calls that will do necessary conversions.

> >> Why a fixed string
> >> shouldn't be assigned to an unbounded one and reverse?
>
> > Of course it should!
>
> q.e.d.
>
> > What about template methods? ;-)
>
> Static polymorphism is exactly what I am trying to get rid of... (:-))

Here you are. :-)
Then we will never get into any agreement.

> Static polymorphism does not allow mixing types.

?

> Further you cannot design
> a library for formatting strings which would not be generic itself.

1. So?
2. Yes, I can. Just use arbitrary string type for formatting and then
convert to the destination type.

> Generics is a dead end.

Hm...

> > Looks like you guys need *real* templates. ;-)
>
> Surely they have them ... for formatting RM texts. See the difference?
> (:-))

:-)

> > But then the compiler would need to either force you to implement the
> > whole square of assignment operations, or use run-time checks to
> > discover whether the assignment within a given pair of leaf types is
> > provided.
> > The former is unrealistic with evolving or open-ended hierarchies, the
> > latter smells more like Python than Ada.
>
> The latter is what Ada does now, and I agree that this is not Ada (TM).

Agreed.

> The former is quite possible and IMO is the only right way to go. Note that
> the language should also allow declaring symmetries of the methods to
> reduce the number of independent variants.

Yes, but that reduces the complexity by a constant only, the problem
is still fundamentally squared.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-29 20:46                     ` Georg Bauhaus
@ 2007-05-30  7:53                       ` Dmitry A. Kazakov
  2007-05-30 13:18                       ` Georg Bauhaus
  1 sibling, 0 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-30  7:53 UTC (permalink / raw)


On Tue, 29 May 2007 22:46:12 +0200, Georg Bauhaus wrote:

> Dmitry A. Kazakov wrote:

>> This is all
>> programming is about - porting mathematics. (:-)) To model the reality in
>> just one hop might be just impossible for a normal programmer. You cannot
>> rely on Nobel Price laureates, they are rare, expensive and uninterested in
>> our problems.
> 
> OK. So why should a normal programmer like me consider it a cost effective
> idea to try to construct a proven mathematical model for my daily work?

Why are you sure that your daily work isn't based on such models? You could
use them unconsciously.

>> How can you know that? (:-)) Let's take the braking control system for your
>> next car...
> 
> I hear that Mercedes engineers do not yet want to replace
> the steering wheel with a embedded computer joy stick thing ... :-)
> I think the argument is that a car must make quicker moves in more
> constraining environments than your average airliner. 

Come on, embedded controllers operate the valves and ignition of the motor
right now. Be sure burning is a lot faster than steering / braking.

But that is not the point. The point one is - how would you enjoy the
"spinal programming" model of things you do care? The second point is - why
to program anything we don't care?

>>> What I want is the mathematics of program models, more than programming
>>> to satisfy mathematics. BTW, what is the best suited mathematical
>>> structure that (minimally) describes the loop
>>>
>>>    while k < 100 loop
>>>      k := Integer'succ(k);
>>>    end loop;
>> 
>> Ordered set, mathematical induction etc.
> 
> Uhm, can we have less than a group?

Yes, as you don't mention the operation of.

>>> and how does it help?
>> 
>> A lot. For example it can tell the code reviewer that the above program is
>> equivalent to:
>> 
>>     if k < 100 then
>>       k := 100;
>>    end if;
> 
> Making assumptions about k ... This is how mathematics can make us prefer
> default perspectives by moving all important points of view behind Formal
> Mountains. The above change wouldn't have helped at all, on the contrary,
> 
>    for k'Address use ...;
> 
> What's the mathematics of that, then?

That k is a pair of functions mapping the system state to the value of k
and reverse:

   Get_k : S -> Integer
   Set_k : S x Integer -> S 

Thank you for making my point! What mathematics makes here is all the rest,
which could well be incomputable. Consider k a hardware random generator.
You could not describe it in any programming language, but you can in the
language of probability theory.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-30  7:40                                 ` Maciej Sobczak
@ 2007-05-30  8:43                                   ` Dmitry A. Kazakov
  2007-05-30 12:54                                     ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-30  8:43 UTC (permalink / raw)


On 30 May 2007 00:40:14 -0700, Maciej Sobczak wrote:

> On 29 Maj, 19:07, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> We are talking about real:
>>
>>> X := Y;
>>
>> Huh, how are going to design a non-referential container of T'Class?
> 
> I don't. :-)
> Polymorphism and references come hand in hand if you need the ability
> to reassign. Copy-initialization is the only place where you can
> safely get away with "values" of T'Class.

Are you going to sell me pointers, right here, in c.l.a? (:-))

Referential semantics is an implementation detail. You propose to expose it
to defend a fiction. But it would be in vain, because assigning class-wide
references in this context is semantically equivalent to assigning the
targets.

> I think that the mess has its source in the push to have T'Class
> behaving like normal value.

This is all meta-programming is about: dealing with polymorphic values =
programming in terms of sets of types.

>>> I say that you need one type String, that possibly uses strategy
>>> internally to delegate details like encoding. You don't need encoding
>>> to "leak out" at the level of types that the final user operates on.
>>
>> That would be indeed a mess. How would you pass an UTF-8 string to GTK+
>> which knows nothing about your fancy patterns?
> 
> Then it should know.

It cannot, it is ANSI C.

> Otherwise there is no way it can interpret
> correctly what I pass as parameters, unless you want to have
> "implicit" conversions for parameters.

To interpret, to convert etc, all this requires a distinct type. Which is
why different representations have to be mapped to different types.

>> Why don't you use the
>> advantages of the types system?
> 
> I do use it, I just don't elevate implementation details to the level
> of type that is handled directly by the user.

I don't see any handling required. But let it be, then how is it different
from your void * approach? When you create a void * you have to somehow
specify the hidden parameter of the case-statement:

   void * X = Create_UTF8 ("foo");

With types you just specify the type of the object instead:

   X : UTF8_String := "foo";

>>> You can (and should) have dispatching internally in the implementation
>>> of operations of String. I'm not proposing any case statements here!
>>
>> Here you are. What is the difference between internally and externally
>> dispatching assignments?
> 
> Assignment is an operation that is meaningful syntactically - that's
> why it is so tempting. Internally you can have anything else,
> including regular subprogram calls that will do necessary conversions.

But not assignments? The question is how do I do dispatching assignment?
Your point was that I shall not do it publicly. But, may I dispatch
privately? If yes then how? And where is any difference? If not, then the
only way left is a case-statement.

>> Static polymorphism does not allow mixing types.
> 
> ?

Instances from a statically polymorphic class of types are unrelated types.
You cannot have any polymorphic object from that class, only specific
objects. For the same reason you cannot have any class-wide operation from
that class.
 
>> Further you cannot design
>> a library for formatting strings which would not be generic itself.
> 
> 1. So?

Write an editor for such strings, store a string, send it over the network,
do anything after uninstalling the compiler ...

> 2. Yes, I can. Just use arbitrary string type for formatting and then
> convert to the destination type.

Why should I bother to have UTF-8 or ASCII strings if anything is
Wide_..._Wide_Unbounded anyway? What are you going to do if the endianess
of Wide x n Character does not fit your machine?

>> The former is quite possible and IMO is the only right way to go. Note that
>> the language should also allow declaring symmetries of the methods to
>> reduce the number of independent variants.
> 
> Yes, but that reduces the complexity by a constant only, the problem
> is still fundamentally squared.

It is how it is. No matter how you would handle them, you have to all of
them. Whatever pattern you use, you will have to deal with this number of
cases. Do you seriously propose to define some of the cases improperly,
just because there are too many of them? (:-))

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-30  8:43                                   ` Dmitry A. Kazakov
@ 2007-05-30 12:54                                     ` Maciej Sobczak
  2007-05-30 13:56                                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-30 12:54 UTC (permalink / raw)


On 30 Maj, 10:43, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > Polymorphism and references come hand in hand if you need the ability
> > to reassign. Copy-initialization is the only place where you can
> > safely get away with "values" of T'Class.
>
> Are you going to sell me pointers, right here, in c.l.a? (:-))

Don't you call them access variables? :-)

> Referential semantics is an implementation detail.

No, it is not. It gives you explicitly the possibility to "reseat" the
referer as well as sharing semantics. These are not details.
Even with strings, you might want to share the strategy for character
encoding.

> But it would be in vain, because assigning class-wide
> references in this context is semantically equivalent to assigning the
> targets.

Which I say should be banned, because the targets are not statically
known.

> >> That would be indeed a mess. How would you pass an UTF-8 string to GTK+
> >> which knows nothing about your fancy patterns?
>
> > Then it should know.
>
> It cannot, it is ANSI C.

Then you need to call it somehow - anyway. How is the proliferation of
string types supposed to help here?

> I don't see any handling required. But let it be, then how is it different
> from your void * approach?

When did I say void*? It is spelled "interface".

> When you create a void * you have to somehow
> specify the hidden parameter of the case-statement:
>
>    void * X = Create_UTF8 ("foo");
>
> With types you just specify the type of the object instead:
>
>    X : UTF8_String := "foo";

Which - again - is not an assignment.
Just a reminder - we are talking about:

X := Y;

> The question is how do I do dispatching assignment?

Just don't. :-)

> Your point was that I shall not do it publicly. But, may I dispatch
> privately?

Privately you can dispatch to your internal strategies to get
character conversions, buffers, etc.

> >> Static polymorphism does not allow mixing types.
>
> > ?
>
> Instances from a statically polymorphic class of types are unrelated types.
> You cannot have any polymorphic object from that class, only specific
> objects. For the same reason you cannot have any class-wide operation from
> that class.

So?

> >> Further you cannot design
> >> a library for formatting strings which would not be generic itself.
>
> > 1. So?
>
> Write an editor for such strings, store a string, send it over the network,
> do anything after uninstalling the compiler ...

Still don't see the problem.

> > 2. Yes, I can. Just use arbitrary string type for formatting and then
> > convert to the destination type.
>
> Why should I bother to have UTF-8 or ASCII strings if anything is
> Wide_..._Wide_Unbounded anyway?

The Wide_..._Wide_Unbounded can be useful as an intermediary format
for conversion between other types, which themselves might still be
very useful providing their own characteristics.

> What are you going to do if the endianess
> of Wide x n Character does not fit your machine?

And why should I bother with endianness here?

> Whatever pattern you use, you will have to deal with this number of
> cases.

Or I just delegate to locale and conversion library that is part of my
operating system.
On my system I can have LOTS of different locales:

$ locale -a | wc -l
502

Do you really expect me to have 502 classes in my program just for
strings?

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-29 20:46                     ` Georg Bauhaus
  2007-05-30  7:53                       ` Dmitry A. Kazakov
@ 2007-05-30 13:18                       ` Georg Bauhaus
  2007-05-31 10:27                         ` Dmitry A. Kazakov
  2007-05-31 11:44                         ` Georg Bauhaus
  1 sibling, 2 replies; 81+ messages in thread
From: Georg Bauhaus @ 2007-05-30 13:18 UTC (permalink / raw)


On Wed, 2007-05-30 at 09:53 +0200, Dmitry A. Kazakov wrote:

> > OK. So why should a normal programmer like me consider it a cost effective
> > idea to try to construct a proven mathematical model for my daily work?
> 
> Why are you sure that your daily work isn't based on such models? You could
> use them unconsciously.

Hm. If you are suggesting that we have a working model of unconscious
mathematics, then in a sense, empirical programming science would
try to observe its working patterns then.


> The point one is - how would you enjoy the
> "spinal programming" model of things you do care? The second point is - why
> to program anything we don't care?

I'm assuming programmers who work carefully.
Let them be guided by principles. The principles need not
be the best thing since sliced bread only because they have
been described standard math terms.


> >>> What I want is the mathematics of program models, more than programming
> >>> to satisfy mathematics. BTW, what is the best suited mathematical
> >>> structure that (minimally) describes the loop
> >>>
> >>>    while k < 100 loop
> >>>      k := Integer'succ(k);
> >>>    end loop;
> >> 
> >> Ordered set, mathematical induction etc.
> > 
> > Uhm, can we have less than a group?
> 
> Yes, as you don't mention the operation of.

I mean, what mathematical model (such as LSP) is helpful in describing
this particular loop, such that the math of the model rules out writing
   k := k + 1;
for example? I would start with a model that isn't originally inspired
by mathematics (because higher math typically frowns upon operations,
that is, the things that computers do).
My vague model has loop invariants, loop termination,
and the fact that the type Integer happens to include a successor
function in its interface.  Now, the type Integer offers much
more than that, e.g. "*". Still, it seems reasonable to start from
the mathematical structure that maps to a type like Integer,
even when I do not need either of the inverse,
the neutral element, or commutativity, which Integer types have
(mostly), among other things.


> >>> and how does it help?
> >> 
> >> A lot. For example it can tell the code reviewer that the above program is
> >> equivalent to:
> >> 
> >>     if k < 100 then
> >>       k := 100;
> >>    end if;
> > 
> > Making assumptions about k ... This is how mathematics can make us prefer
> > default perspectives by moving all important points of view behind Formal
> > Mountains. The above change wouldn't have helped at all, on the contrary,
> > 
> >    for k'Address use ...;
> > 
> > What's the mathematics of that, then?
> 
> That k is a pair of functions mapping the system state to the value of k
> and reverse:
> 
>    Get_k : S -> Integer
>    Set_k : S x Integer -> S 

That's not a mathematical model. It is a pair of functions that
can be mapped to some aspects of how k is supposedly operating,
when amended with sequencing. I bet that few programmers writing
the above loop will have functions in mind that map from and to
world state.

> Thank you for making my point! What mathematics makes here is all the rest,
> which could well be incomputable. Consider k a hardware random generator.
> You could not describe it in any programming language, but you can in the
> language of probability theory.

Thank you for making my point! :-) Probability theoretic constructs
can be mapped into executable computer constructs only in very limited
ways, some of them using clever bit shuffling, others relying on
something *outside* the reach of mathematics, such as /dev/random (as
opposed to /dev/urandom). Outside insofar as there is no practical
way of mapping noise to a precise, hence programmable, formula.
This doesn't make them any less useful. 





^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-30 12:54                                     ` Maciej Sobczak
@ 2007-05-30 13:56                                       ` Dmitry A. Kazakov
  2007-05-30 16:49                                         ` vgodunko
  2007-05-30 20:52                                         ` Maciej Sobczak
  0 siblings, 2 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-30 13:56 UTC (permalink / raw)


On 30 May 2007 05:54:02 -0700, Maciej Sobczak wrote:

> On 30 Maj, 10:43, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>> Referential semantics is an implementation detail.
> 
> No, it is not. It gives you explicitly the possibility to "reseat" the
> referer as well as sharing semantics. These are not details.

No shared semantics in this context. The values identify themselves,
otherwise the type shall be limited and no assignment would come in
question.

> Even with strings, you might want to share the strategy for character
> encoding.

I don't. String has a value, only this counts. You claim that these values
*semantically* cannot be assigned. This is obviously wrong. Semantically a
string is a chain of code positions. I can assign them, I want do it. But
even if that were semantically wrong, even so, why using pointer should
magically change anything here? What was wrong without pointers stay wrong
with them. Reverse is untrue.

>> But it would be in vain, because assigning class-wide
>> references in this context is semantically equivalent to assigning the
>> targets.
> 
> Which I say should be banned, because the targets are not statically
> known.

Why should I *statically* know string bounds and encoding? Any reason?

>> When you create a void * you have to somehow
>> specify the hidden parameter of the case-statement:
>>
>>    void * X = Create_UTF8 ("foo");
>>
>> With types you just specify the type of the object instead:
>>
>>    X : UTF8_String := "foo";
> 
> Which - again - is not an assignment.
> Just a reminder - we are talking about:
> 
> X := Y;

Remember, you have just allowed this, both are void *.

You will need to dereference the pointer. At that point you will face your
void. (:-)) It has to be a class to accommodate values of different
representation. There is no escape.

>> Your point was that I shall not do it publicly. But, may I dispatch
>> privately?
> 
> Privately you can dispatch to your internal strategies to get
> character conversions, buffers, etc.

How? To dispatch you need a class, which you have just scraped.

>>>> Static polymorphism does not allow mixing types.
>>
>>> ?
>>
>> Instances from a statically polymorphic class of types are unrelated types.
>> You cannot have any polymorphic object from that class, only specific
>> objects. For the same reason you cannot have any class-wide operation from
>> that class.
> 
> So?

Unrelated types cannot be mixed in a strongly typed language.
 
>>>> Further you cannot design
>>>> a library for formatting strings which would not be generic itself.
>>
>>> 1. So?
>>
>> Write an editor for such strings, store a string, send it over the network,
>> do anything after uninstalling the compiler ...
> 
> Still don't see the problem.

How to instantiate a template when the type is unknown?

>> What are you going to do if the endianess
>> of Wide x n Character does not fit your machine?
> 
> And why should I bother with endianness here?

Because of the number of possible permutations of the bytes in Wide x n
Character. I presume that Character, Wide x n Character are pointers to ...
mmm, don't know what. Anyway, have fun!

>> Whatever pattern you use, you will have to deal with this number of
>> cases.
> 
> Or I just delegate to locale and conversion library that is part of my
> operating system.

And to whom delegates the conversion library? (:-))

> On my system I can have LOTS of different locales:
> 
> $ locale -a | wc -l
> 502
> 
> Do you really expect me to have 502 classes in my program just for
> strings?

Yes, if you wanted to prevent locales from mixing, if you wanted to deal
with text orientation in different languages, if you wanted
locale-dependent sorting etc. There must be a deep elaborated hierarchy I
suppose.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-30 13:56                                       ` Dmitry A. Kazakov
@ 2007-05-30 16:49                                         ` vgodunko
  2007-05-30 20:52                                         ` Maciej Sobczak
  1 sibling, 0 replies; 81+ messages in thread
From: vgodunko @ 2007-05-30 16:49 UTC (permalink / raw)


On May 30, 5:56 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:
>
> Yes, if you wanted to prevent locales from mixing, if you wanted to deal
> with text orientation in different languages, if you wanted
> locale-dependent sorting etc. There must be a deep elaborated hierarchy I
> suppose.
>
If you need deal with text orientation, locale-independent and locale
specific sorting you may just to use Unicode standards. Unicode
address this and many others things. ;-) All you need is unified text
representation (use one of UTF-* encoding) inside your program.

Implementation of some Unicode algoriphms you may found at Ada-RU
site ;-)

http://www.ada-ru.org/src_ais.html
http://www.ada-ru.org/files/ais-0.0.1.tar.gz




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-30 13:56                                       ` Dmitry A. Kazakov
  2007-05-30 16:49                                         ` vgodunko
@ 2007-05-30 20:52                                         ` Maciej Sobczak
  2007-05-31  8:15                                           ` Dmitry A. Kazakov
  1 sibling, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-30 20:52 UTC (permalink / raw)


On 30 Maj, 15:56, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> >> Referential semantics is an implementation detail.
>
> > No, it is not. It gives you explicitly the possibility to "reseat" the
> > referer as well as sharing semantics. These are not details.
>
> No shared semantics in this context. The values identify themselves,
> otherwise the type shall be limited and no assignment would come in
> question.

When I think about it, it seems to me that you have just pinned down
the very essence of this problem.
There is no need to artificially banning assignments for class-wide
types.
Just force them all to be limited. Problem solved.

I'm not joking.

There is a distinction between value types and object types. These
names might not be meaningful within the Ada terminology, but the
border line is basically between types which instances represent
themselves and those which instances represent external concepts or
entities (but not necessarily). The latter often form hierarchies.
When I said that I've never seen reasonable assignment with a
hierarchy, it expressed exactly this distinction. Assignment is for
values, not for objects.

And guess what? You often need generics (templates, etc.) for value
types. Don't get rid of them yet. ;-)

> > Even with strings, you might want to share the strategy for character
> > encoding.
>
> I don't. String has a value, only this counts.

According to the above distinction, string is a value type.

> You claim that these values
> *semantically* cannot be assigned.

No. String can (and should) have assignment.
But its internal strategy for character encoding might not. It might
be replaceable (yes, we have references!), but the strategy object
itself is not necessarily assignable - and shouldn't be if it's class-
wide.

> Why should I *statically* know string bounds and encoding? Any reason?

You might simply want to. For example, to separate domains.
But you don't need to know and then you can have replaceable
strategies within a single string type.

> > Just a reminder - we are talking about:
>
> > X := Y;
>
> Remember, you have just allowed this, both are void *.

It is you who has introduced void* into this discussion. I have no
idea why.

> >> Your point was that I shall not do it publicly. But, may I dispatch
> >> privately?
>
> > Privately you can dispatch to your internal strategies to get
> > character conversions, buffers, etc.
>
> How? To dispatch you need a class, which you have just scraped.

Internal strategy can be a class. That's a good place for dispatch
(note: I use the term "strategy" from the OO design pattern with the
same name).

> >> Write an editor for such strings, store a string, send it over the network,
> >> do anything after uninstalling the compiler ...
>
> > Still don't see the problem.
>
> How to instantiate a template when the type is unknown?

You don't. What was the problem?

> >> What are you going to do if the endianess
> >> of Wide x n Character does not fit your machine?
>
> > And why should I bother with endianness here?
>
> Because of the number of possible permutations of the bytes in Wide x n
> Character. I presume that Character, Wide x n Character are pointers to ...
> mmm, don't know what. Anyway, have fun!

I still have no idea why you have introduced endianness into this
discussion.
What does it have to do with assigning class-wide types?

The concept of endianness is meaningful only for data marshalling
(when the data is in transit, not when it's stored), which is outside
of string itself. Again - "strategy" is the keyword here.

> >> Whatever pattern you use, you will have to deal with this number of
> >> cases.
>
> > Or I just delegate to locale and conversion library that is part of my
> > operating system.
>
> And to whom delegates the conversion library? (:-))

Why should I bother?
Does it bother you that the mechanics of writing to NFS file are
different from writing to FIFO pipe? Same Ada code can do both.

We have operating systems to provide services, right?

(Unless we write operating systems, that is. :-) )

> > On my system I can have LOTS of different locales:
>
> > $ locale -a | wc -l
> > 502
>
> > Do you really expect me to have 502 classes in my program just for
> > strings?
>
> Yes, if you wanted to prevent locales from mixing, if you wanted to deal
> with text orientation in different languages, if you wanted
> locale-dependent sorting etc. There must be a deep elaborated hierarchy I
> suppose.

Good luck, then. :-)

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-30 20:52                                         ` Maciej Sobczak
@ 2007-05-31  8:15                                           ` Dmitry A. Kazakov
  2007-05-31 13:46                                             ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-31  8:15 UTC (permalink / raw)


On 30 May 2007 13:52:16 -0700, Maciej Sobczak wrote:

> On 30 Maj, 15:56, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>>> Referential semantics is an implementation detail.
>>
>>> No, it is not. It gives you explicitly the possibility to "reseat" the
>>> referer as well as sharing semantics. These are not details.
>>
>> No shared semantics in this context. The values identify themselves,
>> otherwise the type shall be limited and no assignment would come in
>> question.
> 
> When I think about it, it seems to me that you have just pinned down
> the very essence of this problem.
> There is no need to artificially banning assignments for class-wide
> types. Just force them all to be limited. Problem solved.
> 
> I'm not joking.

You cannot make a class of non-limited types limited. It would be
inconsistent. A specific object is just a constrained instance of a
class-wide object. This is the model of what is going on. Whether the
objects from the class should or not have assignment or any other operation
depends solely on the problem domain. It is the programmer's choice.

> There is a distinction between value types and object types.

Between objects with and without identity.

> These
> names might not be meaningful within the Ada terminology, but the
> border line is basically between types which instances represent
> themselves and those which instances represent external concepts or
> entities (but not necessarily). The latter often form hierarchies.
> When I said that I've never seen reasonable assignment with a
> hierarchy, it expressed exactly this distinction. Assignment is for
> values, not for objects.

No. In fact, it is much simpler. There is no magic in identity, which is
just a mapping object->ID value. You cannot assign an object with identity
in terms of its "value" only. This is quite obvious, because such object is
a pair: (ID, Value). How to build a pair using only one component of? But
the pair itself is again a plain value which can be assigned, why not?

The source of confusion is only in an unsound type system people have in
mind. The types of a pair and its component are different. The value of a
polymorphic object is a pair (Type-ID, Specific-value).

When a type is made limited, this not because its class-wides will have
Type-ID, called Tag in Ada. It is because there is an identity of be it
plain or polymorphic object in the problem domain. These are independent
identities.

> And guess what? You often need generics (templates, etc.) for value
> types. Don't get rid of them yet. ;-)

I *never* need generics in the following sense. If a language L cannot be
used without some meta language M (templates), then scrap L and use M
instead:

  L := M;  -- (:-))

If neither L nor M is really usable alone, then guess what? Redesign one of
them!

>>> Even with strings, you might want to share the strategy for character
>>> encoding.
>>
>> I don't. String has a value, only this counts.
> 
> According to the above distinction, string is a value type.

As well as the polymorphic string from the class of:

(UTF-8, "abc") := (ASCII, "def");  -- Why is it a problem?

>> Why should I *statically* know string bounds and encoding? Any reason?
> 
> You might simply want to. For example, to separate domains.

If I wanted this I would put a corresponding constraint, not otherwise. I
don't want the language to impose arbitrary constraints on my design.

>>>> Your point was that I shall not do it publicly. But, may I dispatch
>>>> privately?
>>
>>> Privately you can dispatch to your internal strategies to get
>>> character conversions, buffers, etc.
>>
>> How? To dispatch you need a class, which you have just scraped.
> 
> Internal strategy can be a class. That's a good place for dispatch
> (note: I use the term "strategy" from the OO design pattern with the
> same name).

This is what I meant. Let's move to the internals. How the internal class
can be assigned? Can it?

>>>> Write an editor for such strings, store a string, send it over the network,
>>>> do anything after uninstalling the compiler ...
>>
>>> Still don't see the problem.
>>
>> How to instantiate a template when the type is unknown?
> 
> You don't. What was the problem?

That I can't. Show me an implementation of an editor based generic strings:

generic
   with type Char is private;
   Length : Natural;
package Mess is
   type String is array (1..Length) of Char;
   ...

>>>> Whatever pattern you use, you will have to deal with this number of
>>>> cases.
>>
>>> Or I just delegate to locale and conversion library that is part of my
>>> operating system.
>>
>> And to whom delegates the conversion library? (:-))
> 
> Why should I bother?

You should not, except that delegating is not about work, it is management.
I suppose, MS Project is the "language" for that... (:-))

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-30 13:18                       ` Georg Bauhaus
@ 2007-05-31 10:27                         ` Dmitry A. Kazakov
  2007-05-31 11:44                         ` Georg Bauhaus
  1 sibling, 0 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-05-31 10:27 UTC (permalink / raw)


On Wed, 30 May 2007 15:18:27 +0200, Georg Bauhaus wrote:

> I would start with a model that isn't originally inspired
> by mathematics (because higher math typically frowns upon operations,
> that is, the things that computers do).
> My vague model has loop invariants, loop termination,
> and the fact that the type Integer happens to include a successor
> function in its interface.  Now, the type Integer offers much
> more than that, e.g. "*". Still, it seems reasonable to start from
> the mathematical structure that maps to a type like Integer,
> even when I do not need either of the inverse,
> the neutral element, or commutativity, which Integer types have
> (mostly), among other things.

I don't see your point. You are saying that you don't need mathematics to
program, yet you illustrate your point using mathematical vocabulary. There
is something wrong with that. If programming should be based on, say,
mobile phone throwing, then why are you talking about "neutral elements"?

>> Thank you for making my point! What mathematics makes here is all the rest,
>> which could well be incomputable. Consider k a hardware random generator.
>> You could not describe it in any programming language, but you can in the
>> language of probability theory.
> 
> Thank you for making my point! :-) Probability theoretic constructs
> can be mapped into executable computer constructs only in very limited
> ways,

No, the point is that they cannot be mapped (implemented), this is why
mathematics is necessary to describe what is going on, because no machine
would be sufficient for that.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-30 13:18                       ` Georg Bauhaus
  2007-05-31 10:27                         ` Dmitry A. Kazakov
@ 2007-05-31 11:44                         ` Georg Bauhaus
  2007-06-01  7:37                           ` Dmitry A. Kazakov
  1 sibling, 1 reply; 81+ messages in thread
From: Georg Bauhaus @ 2007-05-31 11:44 UTC (permalink / raw)


On Thu, 2007-05-31 at 12:27 +0200, Dmitry A. Kazakov wrote:
> On Wed, 30 May 2007 15:18:27 +0200, Georg Bauhaus wrote:
> 
> > I would start with a model that isn't originally inspired
> > by mathematics (because higher math typically frowns upon operations,
> > that is, the things that computers do).
> > My vague model has loop invariants, loop termination,
> > and the fact that the type Integer happens to include a successor
> > function in its interface.  Now, the type Integer offers much
> > more than that, e.g. "*". Still, it seems reasonable to start from
> > the mathematical structure that maps to a type like Integer,
> > even when I do not need either of the inverse,
> > the neutral element, or commutativity, which Integer types have
> > (mostly), among other things.
> 
> I don't see your point. You are saying that you don't need mathematics to
> program, yet you illustrate your point using mathematical vocabulary.
>  There is something wrong with that. 

I'm saying that programmers do not necessarily write programs
with mathematical structures in their head, but they still succeed.
I don't call that unconscious mathematics, because we can't know
that. It doesn't matter. When they write,
  a := a + 1;
the may not be thinking about a commutative group of integers,
and never use "-" or "0" in their program text. We may suggest, and
many do (in particular in the non-Scheme FPL camp?), that program
design should start from established pure mathematical structures
only (or LSP, or ...). This way we will profit from the wealth of
mathematical knowledge but we might also ignore successful solutions
just because
(1) they do not usually appear on math radar screens, or 
(2) contradict beliefs in known models (see co/contravariance).


> >> Consider k a hardware random generator.
> >> You could not describe it in any programming language, but you can in the
> >> language of probability theory.
> > 
> > Thank you for making my point! :-) Probability theoretic constructs
> > can be mapped into executable computer constructs only in very limited
> > ways,

> No, the point is that they cannot be mapped (implemented), this is why
> mathematics is necessary to describe what is going on, because no machine
> would be sufficient for that.

But what is actually going on in /dev/random?





^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-31  8:15                                           ` Dmitry A. Kazakov
@ 2007-05-31 13:46                                             ` Maciej Sobczak
  2007-06-01  7:29                                               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-05-31 13:46 UTC (permalink / raw)


On 31 Maj, 10:15, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> You cannot make a class of non-limited types limited.

Why not? Let's just say so or write it in RM.

> It would be
> inconsistent.

Protected objects are limited even if they contain only Integers.
The inconsistencies are there anyway, so why fighting for unrealistic
purity?

> A specific object is just a constrained instance of a
> class-wide object.

Nothing prevents it from having additional operations (in the specific
view, not class-wide).

> This is the model of what is going on. Whether the
> objects from the class should or not have assignment or any other operation
> depends solely on the problem domain. It is the programmer's choice.

Exactly, but the language "helps" the programmer to make some choices.
In Ada most of the time the justification for these is "it's safer".
In my opinion it is safer to not have assignments in class-wide types
and I have nothing against the language to remind me.

> >>> Even with strings, you might want to share the strategy for character
> >>> encoding.
>
> >> I don't. String has a value, only this counts.
>
> > According to the above distinction, string is a value type.
>
> As well as the polymorphic string from the class of:
>
> (UTF-8, "abc") := (ASCII, "def");  -- Why is it a problem?

It assumes too much. To do this operation you need to dispatch to some
encoding or converting strategy anyway - but then, why elevate it so
high? Keep it internally:

declare
  X, Y : String; -- one String type is enough
begin
  X.setEncoding(ASCII);
  X := "def";
  Y.setEncoding(UTF8);
  Y := X;
end;

The above of course cannot work with the current semantics of
assignment in Ada. This is unfortunately broken.

> > Internal strategy can be a class. That's a good place for dispatch
> > (note: I use the term "strategy" from the OO design pattern with the
> > same name).
>
> This is what I meant. Let's move to the internals. How the internal class
> can be assigned? Can it?

You don't need to assign it. It is enough if you can replace it.
Yes, referential semantics is useful sometimes.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-31 13:46                                             ` Maciej Sobczak
@ 2007-06-01  7:29                                               ` Dmitry A. Kazakov
  2007-06-01 13:32                                                 ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-01  7:29 UTC (permalink / raw)


On 31 May 2007 06:46:51 -0700, Maciej Sobczak wrote:

> On 31 Maj, 10:15, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>> You cannot make a class of non-limited types limited.
> 
> Why not? Let's just say so or write it in RM.
>
>> It would be inconsistent.
> 
> Protected objects are limited even if they contain only Integers.
> The inconsistencies are there anyway, so why fighting for unrealistic
> purity?

Container /= what it occasionally contains. The identity of protected
object is essential for synchronization mechanism, for obvious reasons.
This is why the protected object has identity and consequently its type was
made limited. You cannot abstract Integer from a protected object of.

>> A specific object is just a constrained instance of a
>> class-wide object.
> 
> Nothing prevents it from having additional operations (in the specific
> view, not class-wide).

Not in the same package, where adding operations after the freezing point
is forbidden. The reason is same - inconsistency.

You are trying to invent some alternative meaning for class-wide. What for?
If you think that the concept of values from types sets is wrong, say why.

>> This is the model of what is going on. Whether the
>> objects from the class should or not have assignment or any other operation
>> depends solely on the problem domain. It is the programmer's choice.
> 
> Exactly, but the language "helps" the programmer to make some choices.
> In Ada most of the time the justification for these is "it's safer".
> In my opinion it is safer to not have assignments in class-wide types
> and I have nothing against the language to remind me.

It is safe, when it functions as I described earlier.

Again, whatever the compiler does, the code generated shall not render to
"raise Constraint_Error" or for that matter "format C: /q".

>>>>> Even with strings, you might want to share the strategy for character
>>>>> encoding.
>>
>>>> I don't. String has a value, only this counts.
>>
>>> According to the above distinction, string is a value type.
>>
>> As well as the polymorphic string from the class of:
>>
>> (UTF-8, "abc") := (ASCII, "def");  -- Why is it a problem?
> 
> It assumes too much.

I don't understand this. Is it semantically wrong?

>>> Internal strategy can be a class. That's a good place for dispatch
>>> (note: I use the term "strategy" from the OO design pattern with the
>>> same name).
>>
>> This is what I meant. Let's move to the internals. How the internal class
>> can be assigned? Can it?
> 
> You don't need to assign it. It is enough if you can replace it.

Care to explain difference? Doesn't assignment replace one value by
another?

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-31 11:44                         ` Georg Bauhaus
@ 2007-06-01  7:37                           ` Dmitry A. Kazakov
  2007-06-01 10:07                             ` Markus E Leypold
  2007-06-01 11:41                             ` Georg Bauhaus
  0 siblings, 2 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-01  7:37 UTC (permalink / raw)


On Thu, 31 May 2007 13:44:40 +0200, Georg Bauhaus wrote:

> I'm saying that programmers do not necessarily write programs
> with mathematical structures in their head, but they still succeed.
> I don't call that unconscious mathematics, because we can't know
> that. It doesn't matter. When they write,
>   a := a + 1;
> the may not be thinking about a commutative group of integers,

It is no matter what they think, it matters what they write.

[...]
> but we might also ignore successful solutions
> just because
> (1) they do not usually appear on math radar screens, or 
> (2) contradict beliefs in known models (see co/contravariance).

No solution is successful if not based on technological / scientific basis
which would make "success" reproducible. That's apart from the question of
measurement of "success".

We don't talk about consuming programs, but about designing them.

>> No, the point is that they cannot be mapped (implemented), this is why
>> mathematics is necessary to describe what is going on, because no machine
>> would be sufficient for that.
> 
> But what is actually going on in /dev/random?

Realization of a random variable.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-01  7:37                           ` Dmitry A. Kazakov
@ 2007-06-01 10:07                             ` Markus E Leypold
  2007-06-01 11:41                             ` Georg Bauhaus
  1 sibling, 0 replies; 81+ messages in thread
From: Markus E Leypold @ 2007-06-01 10:07 UTC (permalink / raw)



> On Thu, 31 May 2007 13:44:40 +0200, Georg Bauhaus wrote:

>>> No, the point is that they cannot be mapped (implemented), this is why
>>> mathematics is necessary to describe what is going on, because no machine
>>> would be sufficient for that.
>> 
>> But what is actually going on in /dev/random?
>
> Realization of a random variable.

But is that trivial or not?

- M




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-01  7:37                           ` Dmitry A. Kazakov
  2007-06-01 10:07                             ` Markus E Leypold
@ 2007-06-01 11:41                             ` Georg Bauhaus
  2007-06-01 13:07                               ` Dmitry A. Kazakov
  1 sibling, 1 reply; 81+ messages in thread
From: Georg Bauhaus @ 2007-06-01 11:41 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> On Thu, 31 May 2007 13:44:40 +0200, Georg Bauhaus wrote:
> 
>>  When they write,
>>   a := a + 1;
>> the may not be thinking about a commutative group of integers,
> 
> It is no matter what they think, it matters what they write.

This seems a contradiction to what you say below, about basing
solutions on technology/science.
OTOH, when we started from LSP as a design principle, we started
from a guiding principle, I think. This means programmers who
do not accidentally write following the principle. So what are
the principles they have actually been following when
producing a solution that works even though the math behind it
is not known/mainstream/acceptable?

> [...]
>> but we might also ignore successful solutions
>> just because
>> (1) they do not usually appear on math radar screens, or 
>> (2) contradict beliefs in known models (see co/contravariance).
> 
> No solution is successful if not based on technological / scientific basis
> which would make "success" reproducible. That's apart from the question of
> measurement of "success".
> 
> We don't talk about consuming programs, but about designing them.


>>> No, the point is that they cannot be mapped (implemented), this is why
>>> mathematics is necessary to describe what is going on, because no machine
>>> would be sufficient for that.
>> But what is actually going on in /dev/random?
> 
> Realization of a random variable.

What is realization in a machine if not an implementation?




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-01 11:41                             ` Georg Bauhaus
@ 2007-06-01 13:07                               ` Dmitry A. Kazakov
  0 siblings, 0 replies; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-01 13:07 UTC (permalink / raw)


On Fri, 01 Jun 2007 13:41:11 +0200, Georg Bauhaus wrote:

> Dmitry A. Kazakov wrote:
>> On Thu, 31 May 2007 13:44:40 +0200, Georg Bauhaus wrote:
>> 
>>>  When they write,
>>>   a := a + 1;
>>> the may not be thinking about a commutative group of integers,
>> 
>> It is no matter what they think, it matters what they write.
> 
> This seems a contradiction to what you say below, about basing
> solutions on technology/science.

Why? This basing is about an ability to communicate the solution = using
some formalism (like one of mathematics).

> OTOH, when we started from LSP as a design principle, we started
> from a guiding principle, I think.

Which indicates the actual problem...

> This means programmers who
> do not accidentally write following the principle. So what are
> the principles they have actually been following when
> producing a solution that works even though the math behind it
> is not known/mainstream/acceptable?

LSP as a vague principle is just useless and confusing. It results in
countless silly discussions about Circles and Ellipses. Similarly, one
could discuss designs of a perpetual-motion machine. A minimal formalism
would immediately clarify it.

>>>> No, the point is that they cannot be mapped (implemented), this is why
>>>> mathematics is necessary to describe what is going on, because no machine
>>>> would be sufficient for that.
>>> But what is actually going on in /dev/random?
>> 
>> Realization of a random variable.
> 
> What is realization in a machine if not an implementation?

Implementation of a realization is a number (stored/computed). Note the
difference between a number and a random variable, hence the
implementations of.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-01  7:29                                               ` Dmitry A. Kazakov
@ 2007-06-01 13:32                                                 ` Maciej Sobczak
  2007-06-01 14:53                                                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-06-01 13:32 UTC (permalink / raw)


On 1 Cze, 09:29, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> You are trying to invent some alternative meaning for class-wide.

Not really.
There is a difference between this:

X : T'Class := Y;

and this:

X := Y;  -- with X, Y : T'Class;

The difference is coming from the fact that T'Class gets bound at
initialization only and cannot change its binding (tag for you) later
on (X cannot change the actual type).
In other words, X can become equivalent to Y by initialization, but
not by assignment. The latter is already too late - you might be
assigning Triangles to Circles.
This is what makes T'Class different from T.

Of course, you can say that the meaning of assignment and equivalence
are both user-defined and can go together, but this way of thinking
usually subverts the regular meaning of :=. Not the Ada way.

> > You don't need to assign it. It is enough if you can replace it.
>
> Care to explain difference?

You can replace a Circle with a Triangle but you better not try to
assign them.

Note that you normally replace a Circle with a Triangle by
*assignments* of references of the appropriate interface type. ;-)
This indirection solves the problem, because references (pointers)
themselves are values.

No, hierarchies and values don't go together. I might lack the
formalism to prove it, but my observations are confirming: I've never
seen it in the wild.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-01 13:32                                                 ` Maciej Sobczak
@ 2007-06-01 14:53                                                   ` Dmitry A. Kazakov
  2007-06-01 20:31                                                     ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-01 14:53 UTC (permalink / raw)


On Fri, 01 Jun 2007 06:32:30 -0700, Maciej Sobczak wrote:

> On 1 Cze, 09:29, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>> You are trying to invent some alternative meaning for class-wide.
> 
> Not really.
> There is a difference between this:
> 
> X : T'Class := Y;
> 
> and this:
> 
> X := Y;  -- with X, Y : T'Class;
> 
> The difference is coming from the fact that T'Class gets bound at
> initialization only and cannot change its binding (tag for you) later
> on (X cannot change the actual type).

This is a constraint. It does not change the meaning of T'Class.

The pragmatic argument is that this constraint cannot be checked at compile
time, so you cannot make it illegal.

The formal argument is that values of T'Class are supposed to mimic ones of
the specific types from class T (generic programming etc). So IF T (the
root type of the class) has a primitive subprogram F then T'Class shall act
on it. This is the definition of class and primitive subprograms of. In
particular, if T has ":=" that is equivalent to polymorphic ":=" being
defined on T'Class. There is no obvious way to change this, otherwise than
by providing another definition of T'Class and class T and primitive
subprograms of or claiming that there is a semantic difference between X:=Y
and Assign(X,Y). I don't want a language with magical, semantically
non-decomposable assignments.

[Contravariant operations of T'Class have been discussed earlier]

> In other words, X can become equivalent to Y by initialization, but
> not by assignment. The latter is already too late - you might be
> assigning Triangles to Circles.
> This is what makes T'Class different from T.

No, it makes different construction from example and assignment. They are
indeed different, however one could be defined in terms of another. But
this by no means influences the semantics of T'Class.

>>> You don't need to assign it. It is enough if you can replace it.
>>
>> Care to explain difference?
> 
> You can replace a Circle with a Triangle but you better not try to
> assign them.

This is not an explanation. Show a semantic difference between changing a
name binding from one value to another by A) "replacement" and B)
"assignment."

Ah, wouldn't replacement double dispatching? Then let "assignment" :=
"replacement," and we are back where we started from. (:-))

> No, hierarchies and values don't go together. I might lack the
> formalism to prove it, but my observations are confirming: I've never
> seen it in the wild.

Lacking formalism is not an excuse, it is an indictment. (:-))

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-01 14:53                                                   ` Dmitry A. Kazakov
@ 2007-06-01 20:31                                                     ` Maciej Sobczak
  2007-06-02  8:19                                                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-06-01 20:31 UTC (permalink / raw)


On 1 Cze, 16:53, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> or claiming that there is a semantic difference between X:=Y
> and Assign(X,Y). I don't want a language with magical, semantically
> non-decomposable assignments.

You have them at the level of fundamental types.
You can treat X:=Y and Assign(X,Y) to be equivalent for *your* T (and
if you have complete control over overloading of assignment then that
might be actually the case), but at some level of detail they have to
be implemented in terms of *non-decomposable* assignments of
fundamental types anyway. Now, the difference between T and T'Class is
that operations with T can be statically decomposed down to this non-
decomposable bricks. With T'Class it's just impossible to do this
mechanically and it's unrealistic to expect it from the programmer for
any non-trivial hierarchy.

> > You can replace a Circle with a Triangle but you better not try to
> > assign them.
>
> This is not an explanation. Show a semantic difference between changing a
> name binding from one value to another by A) "replacement" and B)
> "assignment."

No problem. Replacement is when you just stop refering to X and start
refering to Y (or its clone if the objects are mutable). Assignment is
when you decompose down to real, hard-core-metal-and-concrete ':=' on
fundamental types. The difference is that (in Ada terms) replacement
allows you to change the tag. Assignment cannot do this.

> Ah, wouldn't replacement double dispatching?

No, it wouldn't and that's the second difference. Replacement just
gets rid of the current value before the new value is refered to,
which means that from the dispatching point of view this operation is
simply linear on right-hand-side - it's a pure single dispatch.
Assignment has to be '2D' with both axes, or O(n2) in terms of
implementation complexity. It has to be double-dispatching to make any
sense and this is unrealistic implementation-wise.

That's why T'Class, even though very interesting from the language
construction point of view, cannot entirely include all functionality
of access variable to T'Class (or pointer to base class in C++
jargon).

> Then let "assignment" :=
> "replacement,"

Do you mean:
- let's replace assignment by replacement, or
- let's assign replacement to assignment?

;-)

> > No, hierarchies and values don't go together. I might lack the
> > formalism to prove it, but my observations are confirming: I've never
> > seen it in the wild.
>
> Lacking formalism is not an excuse, it is an indictment. (:-))

I don't really think I will ever convince you, but this discussion is
an interesting exercise anyway. ;-)

T'Class should be limited.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-01 20:31                                                     ` Maciej Sobczak
@ 2007-06-02  8:19                                                       ` Dmitry A. Kazakov
  2007-06-02 16:49                                                         ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-02  8:19 UTC (permalink / raw)


On Fri, 01 Jun 2007 13:31:04 -0700, Maciej Sobczak wrote:

> On 1 Cze, 16:53, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>> or claiming that there is a semantic difference between X:=Y
>> and Assign(X,Y). I don't want a language with magical, semantically
>> non-decomposable assignments.
> 
> You have them at the level of fundamental types.

So what?

> You can treat X:=Y and Assign(X,Y) to be equivalent for *your* T (and
> if you have complete control over overloading of assignment then that
> might be actually the case), but at some level of detail they have to
> be implemented in terms of *non-decomposable* assignments of
> fundamental types anyway.

How a fundamental X:=Y differs from fundamental Assign(X,Y)? The question
is not about implementation of, but about semantic differences.
 
(It is the first time I meet somebody who tries to deny procedural
decomposition. You have to chance.)

> Now, the difference between T and T'Class is
> that operations with T can be statically decomposed down to this non-
> decomposable bricks. With T'Class it's just impossible to do this
> mechanically and it's unrealistic to expect it from the programmer for
> any non-trivial hierarchy.

The operations of T'Class are perfectly decomposable. There are two of them
(in Ada)

1. Class-wide operation has one body.

2. Primitive operation. The body is composed out for the bodies of the
operations defined for the specific types. This precisely means:

2.a. The specific body is explicitly overridden
2.b. It is inherited, and thus, it is built as a composition of a type view
conversion and the body of the parent type.

>>> You can replace a Circle with a Triangle but you better not try to
>>> assign them.
>>
>> This is not an explanation. Show a semantic difference between changing a
>> name binding from one value to another by A) "replacement" and B)
>> "assignment."
> 
> No problem. Replacement is when you just stop refering to X and start
> refering to Y (or its clone if the objects are mutable). Assignment is
> when you decompose down to real, hard-core-metal-and-concrete ':=' on
> fundamental types.

Mixing abstraction levels is a logical fallacy. You have to choose one,
which would define the semantics. Take any of above and show a difference:
either between "start to refer" and "start to have", or else between the
sequences of machine implementing "start to what."

> The difference is that (in Ada terms) replacement
> allows you to change the tag. Assignment cannot do this.

Neither can. But to show this we'd need to formalize it. Briefly: types
access T and T are different types. The semantic of assignment of access T
is not one of T, and neither is of the assignment of T'Class! It is a typed
language, after all...

>> Ah, wouldn't replacement double dispatching?
> 
> No, it wouldn't and that's the second difference. Replacement just
> gets rid of the current value before the new value is refered to,
> which means that from the dispatching point of view this operation is
> simply linear on right-hand-side - it's a pure single dispatch.

No, this does not work. Apart from being semantically wrong in general
case, it is technically wrong. You have to dispatch to finalize LHS. You
have to dispatch to re-construct it from RHS. See above, in Ada there is no
choice beyond class-wide and primitive operation. The latter dispatches
immediately, the former postpones the dispatch until its body. In both
cases it ultimately dispatches on both arguments. So semantically there is
no difference. Also see my earlier posts about ambiguity of the signatures
T x T'Class and T'Class x T in presence of derived types.

> Assignment has to be '2D' with both axes, or O(n2) in terms of
> implementation complexity. It has to be double-dispatching to make any
> sense and this is unrealistic implementation-wise.

It is semantically this way. There is nothing to do about it, but to scrap
either assignment or class. (We are going in circles)

> That's why T'Class, even though very interesting from the language
> construction point of view, cannot entirely include all functionality
> of access variable to T'Class (or pointer to base class in C++
> jargon).

This is irrelevant as they are different types. In fact an access type
could be treated as a member of the class, but then its assignment would
have a deep copy semantics and you are back where you have started from.

(C++ OO model is really poisoning. Don't mix types, just don't.)

>> Then let "assignment" :=
>> "replacement,"
> 
> Do you mean:
> - let's replace assignment by replacement, or
> - let's assign replacement to assignment?
> 
> ;-)

Take what you wish, but referential semantic is fundamentally insufficient,
in the sense that you cannot have a language without values, but only
references. This is the conceptual fault of Java et al. Once you had at
least one value at the end of the referential chains, you'd have to assign
(:-)) it and give a type to it. (It is about typed languages, right?)  Then
because your types algebra has classes one could create a class of. In the
end you will face the same question again: what is the assignment on the
class. All this referential stuff is just shifting subjects.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-02  8:19                                                       ` Dmitry A. Kazakov
@ 2007-06-02 16:49                                                         ` Maciej Sobczak
  2007-06-03  7:09                                                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-06-02 16:49 UTC (permalink / raw)


On 2 Cze, 10:19, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > The difference is that (in Ada terms) replacement
> > allows you to change the tag. Assignment cannot do this.
>
> Neither can.

Yes, replacement can change the tag. It's the tag of referred object
that can change. An access variable can point to Circle and then to
Triangle. This is the kind of replacement I'm talking about.
But you cannot assign Triangle to Circle.

> But to show this we'd need to formalize it. Briefly: types
> access T and T are different types.

Sure. It's just not the type of reference I'm interested in in a
regular program, but the type of referred object.

> The semantic of assignment of access T
> is not one of T, and neither is of the assignment of T'Class! It is a typed
> language, after all...

Of course. That's why it is useful to distinguish them. And since we
came here from the notion of strategies (in strings, but that was so
long ago that it barely matters now), then replacing one strategy with
another can be implemented in terms of assigning access variables. It
is just not the level of abstraction I'm interested in. I don't care
about access variables. What I care about is the fact that I can
replace one strategy with another.

I can also replace a wheel in my car but it's not assignment of
wheels.

Replacement and assignment are different things from the design point
of view, even if replacement for T is implemented in terms of
assignment for access T - that's just not the level of detail I care
about.

> >> Ah, wouldn't replacement double dispatching?
>
> > No, it wouldn't and that's the second difference. Replacement just
> > gets rid of the current value before the new value is refered to,
> > which means that from the dispatching point of view this operation is
> > simply linear on right-hand-side - it's a pure single dispatch.
>
> No, this does not work. Apart from being semantically wrong in general
> case, it is technically wrong.

Why is it semantically wrong?
Consider replacing wheels in your car.

> You have to dispatch to finalize LHS. You
> have to dispatch to re-construct it from RHS.

It doesn't change anything in my reasoning. Two linear dispatches
don't magically give you double dispatch! In terms of implementation
complexity, it is O(n+m) problem, not O(n*m).

The difference comes from the fact that finalizing LHS has no
influence on re-constructing from RHS.

> > Assignment has to be '2D' with both axes, or O(n2) in terms of
> > implementation complexity. It has to be double-dispatching to make any
> > sense and this is unrealistic implementation-wise.
>
> It is semantically this way. There is nothing to do about it, but to scrap
> either assignment or class. (We are going in circles)

That's exactly what I'm talking about from the very beginning -
T'Class should be limited.
Is it only my impression that we actually agree? :-)

> (C++ OO model is really poisoning. Don't mix types, just don't.)

In what way is the C++ OO model relevant here?

I'm talking about replacing wheels in my car. Twice a year I *replace*
summer wheels for winter ones and the other way round. I *don't
assign* them.


> Take what you wish, but referential semantic is fundamentally insufficient,
> in the sense that you cannot have a language without values, but only
> references.

Of course, I've never said that. You need both to do anything useful.

> Once you had at
> least one value at the end of the referential chains, you'd have to assign
> (:-)) it and give a type to it.

Yes.

> Then
> because your types algebra has classes one could create a class of. In the
> end you will face the same question again: what is the assignment on the
> class. All this referential stuff is just shifting subjects.

No, it's not shifting subjects. It's actually what makes it possible
to replace wheels in a car. Or encoding strategies in a string object.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-02 16:49                                                         ` Maciej Sobczak
@ 2007-06-03  7:09                                                           ` Dmitry A. Kazakov
  2007-06-03 22:04                                                             ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-03  7:09 UTC (permalink / raw)


On Sat, 02 Jun 2007 09:49:38 -0700, Maciej Sobczak wrote:

> On 2 Cze, 10:19, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> The difference is that (in Ada terms) replacement
>>> allows you to change the tag. Assignment cannot do this.
>>
>> Neither can.
> 
> Yes, replacement can change the tag. It's the tag of referred object
> that can change. An access variable can point to Circle and then to
> Triangle.

No, this is illegal. At least in Ada,: access Circle and access Triangle
are different types. They cannot be assigned to each other.

> I can also replace a wheel in my car but it's not assignment of
> wheels.

If you want to bring the issue of identity (the wheel) then that's again
subject shifting.

>>>> Ah, wouldn't replacement double dispatching?
>>
>>> No, it wouldn't and that's the second difference. Replacement just
>>> gets rid of the current value before the new value is refered to,
>>> which means that from the dispatching point of view this operation is
>>> simply linear on right-hand-side - it's a pure single dispatch.
>>
>> No, this does not work. Apart from being semantically wrong in general
>> case, it is technically wrong.
> 
> Why is it semantically wrong?

Because variables of T'Class can be assigned with the values of T'Class if
T has assignment.

> Consider replacing wheels in your car.

You should have annotated that example with types, values and variables.
 
>> You have to dispatch to finalize LHS. You
>> have to dispatch to re-construct it from RHS.
> 
> It doesn't change anything in my reasoning. Two linear dispatches
> don't magically give you double dispatch!

Of course it does. A function of two arguments is still a function of two
arguments. Decomposability of the function into a product is irrelevant to
the issue. It dispatches in both arguments.

>>> Assignment has to be '2D' with both axes, or O(n2) in terms of
>>> implementation complexity. It has to be double-dispatching to make any
>>> sense and this is unrealistic implementation-wise.
>>
>> It is semantically this way. There is nothing to do about it, but to scrap
>> either assignment or class. (We are going in circles)
> 
> That's exactly what I'm talking about from the very beginning -
> T'Class should be limited.
> Is it only my impression that we actually agree? :-)

Not at all. The point is:

limited T <=> limited T'Class

No more, no less.

> I'm talking about replacing wheels in my car. Twice a year I *replace*
> summer wheels for winter ones and the other way round. I *don't
> assign* them.

If you mean assignment of pointers, then pointers are typed in Ada. If the
pointers here have the same type (like P is access Wheel'Class) then there
is nothing to talk about. You assign P to P. That is just irrelevant to the
problem at hand. The issue is about assigning *different* types from a
class, like ones from Wheel'Class (Goodyear, Michelin), or like ones from
(access Wheel)'Class. Note brackets! The latter is illegal in Ada, but if
it were legal, you'd have exactly the same thing.

>> Then
>> because your types algebra has classes one could create a class of. In the
>> end you will face the same question again: what is the assignment on the
>> class. All this referential stuff is just shifting subjects.
> 
> No, it's not shifting subjects.

Of course it is, because the types are same.

The issue of identity / references you are trying to bring in is
irrelevant. Multiple dispatch assignment is fully applicable to wheel and
car objects. When you "replace" wheels, you could perform different tasks
depending on the types of the old and new wheels .How these tasks can be
encapsulated into one replacement action?

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-03  7:09                                                           ` Dmitry A. Kazakov
@ 2007-06-03 22:04                                                             ` Maciej Sobczak
  2007-06-04  8:08                                                               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-06-03 22:04 UTC (permalink / raw)


On 3 Cze, 09:09, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > Yes, replacement can change the tag. It's the tag of referred object
> > that can change. An access variable can point to Circle and then to
> > Triangle.
>
> No, this is illegal. At least in Ada,: access Circle and access Triangle
> are different types. They cannot be assigned to each other.

I was talking about access Object'Class with Circle and Triangle being
both derived from Object.
The access variable can point to object with different tag during its
lifetime.

> >>>> Ah, wouldn't replacement double dispatching?
>
> >>> No, it wouldn't and that's the second difference. Replacement just
> >>> gets rid of the current value before the new value is refered to,
> >>> which means that from the dispatching point of view this operation is
> >>> simply linear on right-hand-side - it's a pure single dispatch.
>
> >> No, this does not work. Apart from being semantically wrong in general
> >> case, it is technically wrong.
>
> > Why is it semantically wrong?
>
> Because variables of T'Class can be assigned with the values of T'Class if
> T has assignment.

We are going in circles. I say T'Class should be limited.
Even if T is not.

> >> You have to dispatch to finalize LHS. You
> >> have to dispatch to re-construct it from RHS.
>
> > It doesn't change anything in my reasoning. Two linear dispatches
> > don't magically give you double dispatch!
>
> Of course it does. A function of two arguments is still a function of two
> arguments. Decomposability of the function into a product is irrelevant to
> the issue. It dispatches in both arguments.

It doesn't change anything.
Think about extensibility of the system. One of the virtues of OO is
the ability of the system to be reused with new types. If you have a
hierarchy with N types then adding new type means you have to
implement 1 finalizer and 1 cloning (if you want them, of course) and
all replacement semantics in the system still works fine. In other
words, you don't have to involve all other types in the hierarchy when
implementing a new type.
With doubly-dispatching assignment, adding new type to the same
hierarchy means you have to implement N assignments for each potential
situation.
Or even 2*N.

Now think about the hierarchy that has many branches which are
extended independently...

You can theoretize as long as you want and you can say (even rightly)
that replacement is doubly-dispatching, but there *is* a difference
between O(n+m) and O(n*m) - and this difference is what makes
assignment of T'Class simply unrealistic.

> Not at all. The point is:
>
> limited T <=> limited T'Class
>
> No more, no less.

That's your point. Mine is T'Class should be limited.

> The issue of identity / references you are trying to bring in is
> irrelevant. Multiple dispatch assignment is fully applicable to wheel and
> car objects. When you "replace" wheels, you could perform different tasks
> depending on the types of the old and new wheels .How these tasks can be
> encapsulated into one replacement action?

They are not. That's the feature of replacement.

This, however, brings another point - if you want to execute different
assignment tasks depending on both LHS and RHS *types*, then let's
extend it a bit: I want to execute different tasks depending on
current *values* of both LHS and RHS. After all, if assignment is
supposed to be doubly-dispatching and if it's also supposed to be no
different than hypothetical Assign(X, Y), then I should be able to do
this, right?
Right?
Unfortunately, this is completely broken in Ada.
This is just another reason why doubly-dispatching assignment cannot
exist. Not only it's unrealistic to implement correctly (remember the
complexity), there is simply no reasonable structure to build upon.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-03 22:04                                                             ` Maciej Sobczak
@ 2007-06-04  8:08                                                               ` Dmitry A. Kazakov
  2007-06-04 17:02                                                                 ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-04  8:08 UTC (permalink / raw)


On Sun, 03 Jun 2007 15:04:00 -0700, Maciej Sobczak wrote:

> On 3 Cze, 09:09, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> Yes, replacement can change the tag. It's the tag of referred object
>>> that can change. An access variable can point to Circle and then to
>>> Triangle.
>>
>> No, this is illegal. At least in Ada,: access Circle and access Triangle
>> are different types. They cannot be assigned to each other.
> 
> I was talking about access Object'Class with Circle and Triangle being
> both derived from Object.

What is the difference between the types access T'Class and T'Class?

> We are going in circles. I say T'Class should be limited.
> Even if T is not.

If I'd say access T'Class should be limited even if T is not?
 
> You can theoretize as long as you want and you can say (even rightly)
> that replacement is doubly-dispatching, but there *is* a difference
> between O(n+m) and O(n*m) - and this difference is what makes
> assignment of T'Class simply unrealistic.

No, that makes it unrealistic to manage this complexity using crude
patterns instead of a consistent approach. The problem is here, the choice
is between language support and manual cascaded case-statements.
 
>> The issue of identity / references you are trying to bring in is
>> irrelevant. Multiple dispatch assignment is fully applicable to wheel and
>> car objects. When you "replace" wheels, you could perform different tasks
>> depending on the types of the old and new wheels .How these tasks can be
>> encapsulated into one replacement action?
> 
> They are not. That's the feature of replacement.
> 
> This, however, brings another point - if you want to execute different
> assignment tasks depending on both LHS and RHS *types*, then let's
> extend it a bit: I want to execute different tasks depending on
> current *values* of both LHS and RHS. After all, if assignment is
> supposed to be doubly-dispatching and if it's also supposed to be no
> different than hypothetical Assign(X, Y), then I should be able to do
> this, right?

Wrong. These are independent. Double dispatch controls the choice of the
specific body, it tells nothing about how this body has to be assembled.
There could be different ways of doing this, with advantages and
disadvantages. In some cases you might really want LHS being finalized
before the overridden part of the assignment, like when it holds an
expensive resource. Then you have an issue of enforcing finalization on
LHS.

My approach, not shared here, is that the programmer should have more
control over this, when he wants. The constructors, destructors,
assignments and aggregates are all polymorphic subroutines composed
differently from normal primitive and class-wide operations. In a better
language one should be able to describe all these decompositions uniformly,
with a higher-level mechanism of polymorphic subprograms.

Handling discriminants and types tags is a separate issue of constraint
description and propagation.

> Right?
> Unfortunately, this is completely broken in Ada.

It is not broken, it does not exist. Adjust is not an assignment, it is
hack to provide functionality without much rethinking.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-04  8:08                                                               ` Dmitry A. Kazakov
@ 2007-06-04 17:02                                                                 ` Maciej Sobczak
  2007-06-05  8:35                                                                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-06-04 17:02 UTC (permalink / raw)


On 4 Cze, 10:08, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > I was talking about access Object'Class with Circle and Triangle being
> > both derived from Object.
>
> What is the difference between the types access T'Class and T'Class?

Access T'Class can be reseated to point to some other object from
T'Class, even if that other object has different tag.
Thanks to this, access T'Class can be used to provide replacement
semantics for T'Class, where assignment wouldn't work.

I believe I get the Ada basics right.

> > We are going in circles. I say T'Class should be limited.
> > Even if T is not.
>
> If I'd say access T'Class should be limited even if T is not?

No, access Whatever should not be unconditionally limited, otherwise
there would be little justification for its existence in the type
system.
The raison d'etre for access T is the ability to *point* - and be
*reseated*.
Of course, there is a place for constant access Whatever, but this is
another story.

> > You can theoretize as long as you want and you can say (even rightly)
> > that replacement is doubly-dispatching, but there *is* a difference
> > between O(n+m) and O(n*m) - and this difference is what makes
> > assignment of T'Class simply unrealistic.
>
> No, that makes it unrealistic to manage this complexity using crude
> patterns instead of a consistent approach. The problem is here, the choice
> is between language support and manual cascaded case-statements.

No, there is no choice whatsoever. There is nothing that cascaded case-
statements can buy you that you couldn't do with dispatch (except
maybe static coverage tests - but these don't exist in open
hierarchies).
There are fundamental reasons for which assignment for T'Class doesn't
make sense (it would lead to objects that can change type at runtime -
you cannot get further away from Ada than that) and no matter what
magic you try, you will always hit the same wall.
Consider (again):

procedure Swap(X : in out Object'Class; X in out Object'Class)
begin
   -- whatever
end Swap;

and then:

declare
  X : Triangle;
  Y : Circle;
begin
  Swap(X, Y);
  -- oops
end;

It does not matter what is inside Swap. Double-dispatch, cascading
case, unchecked magic, whatever. These are all low-level details of
something that just doesn't fly anyway.

> > This, however, brings another point - if you want to execute different
> > assignment tasks depending on both LHS and RHS *types*, then let's
> > extend it a bit: I want to execute different tasks depending on
> > current *values* of both LHS and RHS. After all, if assignment is
> > supposed to be doubly-dispatching and if it's also supposed to be no
> > different than hypothetical Assign(X, Y), then I should be able to do
> > this, right?
>
> Wrong. These are independent. Double dispatch controls the choice of the
> specific body, it tells nothing about how this body has to be assembled.

Yes, but this shows that assignment in Ada cannot be modeled by any
hypothetical Assign subprogram. No analogies here. This in turn means
that introducing full double-dispatch to the discussion doesn't help
much, because implementing it would not be at all similar to anything.

> In some cases you might really want LHS being finalized
> before the overridden part of the assignment, like when it holds an
> expensive resource.

1. In *some* cases. In those cases I can take this decision on my own.

2. Actually, in those cases when LHS keeps expensive resource I would
very much welcome the ability to reuse it, if possible. Consider:

declare
   S1 : My_String_Type := "abcd";
   S2 : My_String_Type := "xyz";
begin
   S1 := S2;
end;

No need to finalize LHS here (and reallocate again to hold a copy of
RHS). Other examples abound.

Sorry to say this, but when I see things like *this*, I have an
impression that Ada is SbyC (Slow by Construction - you can quote
me :-) ). This is *obvious* optimization opportunity!

But that was aside, nothing about T'Class being limited.

> My approach, not shared here, is that the programmer should have more
> control over this, when he wants.

Hm... do we agree again? :-)

> The constructors, destructors,
> assignments and aggregates are all polymorphic subroutines composed
> differently from normal primitive and class-wide operations.

Agreed with exceptions:
- constructors cannot be polymorphic, since there is no tag yet (you
might dispatch on something different, though, but this is irrelevant)
- assignments are banned anyway ;-)

Destructors are obviously polymorphic.

> In a better
> language one should be able to describe all these decompositions uniformly,
> with a higher-level mechanism of polymorphic subprograms.

Not really. The problem is that these things work on the border of
object's life and death and for this reason they cannot be first-class
citizens in the world of polymorphic operations.

> > Unfortunately, this is completely broken in Ada.
>
> It is not broken, it does not exist. Adjust is not an assignment, it is
> hack to provide functionality without much rethinking.

Hacks make things broken.
Every language has its hacks, but this one is just too fundamental to
be easily forgiven. ;-)

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-04 17:02                                                                 ` Maciej Sobczak
@ 2007-06-05  8:35                                                                   ` Dmitry A. Kazakov
  2007-06-05 22:12                                                                     ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-05  8:35 UTC (permalink / raw)


On Mon, 04 Jun 2007 10:02:48 -0700, Maciej Sobczak wrote:

> On 4 Cze, 10:08, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> I was talking about access Object'Class with Circle and Triangle being
>>> both derived from Object.
>>
>> What is the difference between the types access T'Class and T'Class?
> 
> Access T'Class can be reseated to point to some other object from
> T'Class, even if that other object has different tag.

So what? According to you that is wrong because there exist n*n possible
combinations of such assignments for different tags. In what sense these
combinations are different for T'Class and access T'Class?

>>> We are going in circles. I say T'Class should be limited.
>>> Even if T is not.
>>
>> If I'd say access T'Class should be limited even if T is not?
> 
> No, access Whatever should not be unconditionally limited, otherwise
> there would be little justification for its existence in the type
> system.
> The raison d'etre for access T is the ability to *point* - and be
> *reseated*.

While for T'Class it is the ability to accommodate any specific T. Where is
a difference?

> There are fundamental reasons for which assignment for T'Class doesn't
> make sense (it would lead to objects that can change type at runtime -
> you cannot get further away from Ada than that) and no matter what
> magic you try, you will always hit the same wall.
> Consider (again):
> 
> procedure Swap(X : in out Object'Class; X in out Object'Class)
> begin
>    -- whatever
> end Swap;
> 
> and then:
> 
> declare
>   X : Triangle;
>   Y : Circle;
> begin
>   Swap(X, Y);

procedure Swap (X, Y : in out String);

declare
   X : String := "abc";
   Y : String := "klmnoprst";
begin
   Swap (X, Y);
   -- oops

Why your "fundamental" reasons do not apply here?

The only truly fundamental reason is that if Object was declared
non-limited, then its contract is to support assignment. It is then the
programmer responsibility to fulfill this contract for Triangle and Circle.
Don't blame the language for your own design faults.

>> Wrong. These are independent. Double dispatch controls the choice of the
>> specific body, it tells nothing about how this body has to be assembled.
> 
> Yes, but this shows that assignment in Ada cannot be modeled by any
> hypothetical Assign subprogram. No analogies here. This in turn means
> that introducing full double-dispatch to the discussion doesn't help
> much, because implementing it would not be at all similar to anything.

It is still independent. The thing is not fully decomposable into
subprograms because that would require type violation, which is impossible
in a typed language. Therefore some magic is needed to convert raw memory
to an object and back. This is irrelevant to dispatch. And if that were a
reason to forbid assignments, then *any* assignment would become illegal.

Because magic is needed, assignment, construction and destruction will
always be compiler-generated with some injections of user-defined
subprograms at the points where necessary [sub]objects are fully
constructed/destructed. This is no different from polymorphic subprograms,
they are also compiler-generated.

>> My approach, not shared here, is that the programmer should have more
>> control over this, when he wants.
> 
> Hm... do we agree again? :-)

No, because you want to disallow assignment altogether, others want to keep
it albeit sometimes inconsistent, but I want to change the language to have
a way to enforce its consistency.

> - constructors cannot be polymorphic, since there is no tag yet (you
> might dispatch on something different, though, but this is irrelevant)

There is the tag, it exists before the object and comes from the type of. A
constructor (actually a part of) dispatches on the bare tag. I posted a
description of my view on this some time ago:

http://groups.google.com/group/comp.lang.ada/browse_thread/thread/72c34c66b38e0e05/b4b6668d530912ac?lnk=gst&q=kazakov+construction&rnum=6#b4b6668d530912ac
 
>> In a better
>> language one should be able to describe all these decompositions uniformly,
>> with a higher-level mechanism of polymorphic subprograms.
> 
> Not really. The problem is that these things work on the border of
> object's life and death and for this reason they cannot be first-class
> citizens in the world of polymorphic operations.

The same applies to primitive operations. Dispatch happens per magic. I
suppose there is a more general mechanism based on types constraints. But
in any case it will be "magical." But that will be the only magic
necessary.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-05  8:35                                                                   ` Dmitry A. Kazakov
@ 2007-06-05 22:12                                                                     ` Maciej Sobczak
  2007-06-06  8:21                                                                       ` Dmitry A. Kazakov
  2007-06-06 15:32                                                                       ` Markus E Leypold
  0 siblings, 2 replies; 81+ messages in thread
From: Maciej Sobczak @ 2007-06-05 22:12 UTC (permalink / raw)


On 5 Cze, 10:35, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> >>> I was talking about access Object'Class with Circle and Triangle being
> >>> both derived from Object.
>
> >> What is the difference between the types access T'Class and T'Class?
>
> > Access T'Class can be reseated to point to some other object from
> > T'Class, even if that other object has different tag.
>
> So what? According to you that is wrong because there exist n*n possible
> combinations of such assignments for different tags. In what sense these
> combinations are different for T'Class and access T'Class?

In the sense that access T'Class has only one combination to cover and
since access is a fundamental type, this is handled by the language.
You don't have to do anything to make assignment for access T'Class
work!

> > No, access Whatever should not be unconditionally limited, otherwise
> > there would be little justification for its existence in the type
> > system.
> > The raison d'etre for access T is the ability to *point* - and be
> > *reseated*.
>
> While for T'Class it is the ability to accommodate any specific T. Where is
> a difference?

In assignment.

(We are really going in circles.)

> procedure Swap (X, Y : in out String);
>
> declare
>    X : String := "abc";
>    Y : String := "klmnoprst";
> begin
>    Swap (X, Y);
>    -- oops

OK, even better. Let's ban assignment for all unconstrained types. :-)

> Why your "fundamental" reasons do not apply here?

The "fundamental" reasons apply here as well. The problem is of a
general nature.

> The only truly fundamental reason is that if Object was declared
> non-limited, then its contract is to support assignment. It is then the
> programmer responsibility to fulfill this contract for Triangle and Circle.
> Don't blame the language for your own design faults.

No. Regular objects are declared as Triangles and Circles (and these
types may have reasonable assignments - after all, assigning one
Triangle to another makes sense). The problem is when you declare
something as T'Class.
T'Class /= T and this is one of the things that make them different.
I know that it shakes part of the concept of a class.

But you have the same problem with unconstrained types. They might not
support all operations of their constrained equivalents.

> > - constructors cannot be polymorphic, since there is no tag yet (you
> > might dispatch on something different, though, but this is irrelevant)
>
> There is the tag, it exists before the object and comes from the type of. A
> constructor (actually a part of) dispatches on the bare tag.

I don't agree on this.

X : T;
Y : T'Class := Whatever;

Do_Something(X); -- (1)
Do_Something(Y); -- (2)

Which of the two above are dispatching (assume Do_Something is
primitive)?
My understanding of the concepts is that only (2) is a dispatching
call, (1) is not.
The constructors are non-dispatching, no matter how much of the "fetus
object" is there when the call is made. Even if there is a tag, it's
known statically and then this is just overloading, not polymorphism
in the OO sense.

> > Not really. The problem is that these things work on the border of
> > object's life and death and for this reason they cannot be first-class
> > citizens in the world of polymorphic operations.
>
> The same applies to primitive operations. Dispatch happens per magic. I
> suppose there is a more general mechanism based on types constraints. But
> in any case it will be "magical." But that will be the only magic
> necessary.

Still, there is a difference between T and T'Class. As far as I
understand it, constructor calls are not dispatching.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-05 22:12                                                                     ` Maciej Sobczak
@ 2007-06-06  8:21                                                                       ` Dmitry A. Kazakov
  2007-06-06 14:46                                                                         ` Maciej Sobczak
  2007-06-06 15:32                                                                       ` Markus E Leypold
  1 sibling, 1 reply; 81+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-06  8:21 UTC (permalink / raw)


On Tue, 05 Jun 2007 15:12:29 -0700, Maciej Sobczak wrote:

> On 5 Cze, 10:35, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>>>> I was talking about access Object'Class with Circle and Triangle being
>>>>> both derived from Object.
>>
>>>> What is the difference between the types access T'Class and T'Class?
>>
>>> Access T'Class can be reseated to point to some other object from
>>> T'Class, even if that other object has different tag.
>>
>> So what? According to you that is wrong because there exist n*n possible
>> combinations of such assignments for different tags. In what sense these
>> combinations are different for T'Class and access T'Class?
> 
> In the sense that access T'Class has only one combination to cover and
> since access is a fundamental type, this is handled by the language.
> You don't have to do anything to make assignment for access T'Class
> work!

Hence you agree that when assignment is defined then it is no matter how
many combination of exists. Therefore your argument about the number of
combinations is irrelevant for any user- or compiler-generated assignment.

In our earlier discussion I assumed this obvious, as it follows from
separation of implementation and interface. Anyway, now, when the
implementation is finally left to the problem domain, what is the
*semantic* difference between access T'Class and T'Class beyond that?

>>> No, access Whatever should not be unconditionally limited, otherwise
>>> there would be little justification for its existence in the type
>>> system.
>>> The raison d'etre for access T is the ability to *point* - and be
>>> *reseated*.
>>
>> While for T'Class it is the ability to accommodate any specific T. Where is
>> a difference?
> 
> In assignment.
 
Nope, you cannot say that the difference is in assignment, because now we
are talking about "ability to point" and "ability to hold." What makes
"point" different to "hold", semantically I mean?

>> procedure Swap (X, Y : in out String);
>>
>> declare
>>    X : String := "abc";
>>    Y : String := "klmnoprst";
>> begin
>>    Swap (X, Y);
>>    -- oops
> 
> OK, even better. Let's ban assignment for all unconstrained types. :-)

My congratulations! But that's not all:

procedure Swap (X, Y : in out Integer);

declare
   X : Positive := 1;
   Y : Integer := -1;
begin
   Swap (X, Y);
    -- oops

I hope you see now, why your proposal is inconsistent with any type system
with constrained [sub]types (classes is just a specific case of)? Further,
it is incompatible with specialization and generic programming on sets of
specialized types. It can be easily shown, that it is also incompatible
with generalization and in the end with generic programming on any
non-trivial sets of types.

>> Why your "fundamental" reasons do not apply here?
> 
> The "fundamental" reasons apply here as well. The problem is of a
> general nature.

Huh, speaking of general natures, the problem is a misconception shared by
LSP-ers. The issue can be summarized in three lines:

1. Specialization breaks all out-methods of the base type
2. Generalization breaks all in-.methods of the base type
3. Variation breaks everything

The rest is consequences. This cannot be fixed and need not to.

>> The only truly fundamental reason is that if Object was declared
>> non-limited, then its contract is to support assignment. It is then the
>> programmer responsibility to fulfill this contract for Triangle and Circle.
>> Don't blame the language for your own design faults.
> 
> No. Regular objects are declared as Triangles and Circles (and these
> types may have reasonable assignments - after all, assigning one
> Triangle to another makes sense). The problem is when you declare
> something as T'Class.

Wrong. Assignment is a primitive operation <=> it is defined on T'Class.
Specific assignments are irrelevant here.

> T'Class /= T and this is one of the things that make them different.
> I know that it shakes part of the concept of a class.

Yep, it demolishes class and primitive operations of.

> But you have the same problem with unconstrained types. They might not
> support all operations of their constrained equivalents.

What does it mean "not support"? You have to translate this into illegal
("type error") / legal ("no type error"). See above, there is no way out.
Either you scrap the type system, by forbidding any intertype relations or
you have to live with the cross cases. In the middle there exists a wide
range of semi-consistent languages like C++ and, alas, Ada.

>>> - constructors cannot be polymorphic, since there is no tag yet (you
>>> might dispatch on something different, though, but this is irrelevant)
>>
>> There is the tag, it exists before the object and comes from the type of. A
>> constructor (actually a part of) dispatches on the bare tag.
> 
> I don't agree on this.
> 
> X : T;
> Y : T'Class := Whatever;
> 
> Do_Something(X); -- (1)
> Do_Something(Y); -- (2)
> 
> Which of the two above are dispatching (assume Do_Something is
> primitive)?

So? Following your argument destructor of X isn't dispatching either,
because it will not dispatch in this piece of code.

A part of the constructor of T'Class is certainly dispatching. The
constructor of T is specific for T. This makes constructor a primitive
operation. On the other hand, constructors are composed by extension, which
makes them class-wide operations as well (you have to construct T'Class for
a specific S derived from T). This controversy is the reason why
constructors aren't easy to get right. The idea of my proposal was to make
it typed and factor out specific and class-wide parts a constructors as
user-defined subprograms.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-06  8:21                                                                       ` Dmitry A. Kazakov
@ 2007-06-06 14:46                                                                         ` Maciej Sobczak
  2007-06-06 15:11                                                                           ` Maciej Sobczak
  0 siblings, 1 reply; 81+ messages in thread
From: Maciej Sobczak @ 2007-06-06 14:46 UTC (permalink / raw)


On 6 Cze, 10:21, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > In the sense that access T'Class has only one combination to cover and
> > since access is a fundamental type, this is handled by the language.
> > You don't have to do anything to make assignment for access T'Class
> > work!
>
> Hence you agree that when assignment is defined then it is no matter how
> many combination of exists.

No, you are jumping to wrong conclusions. If there exists exactly one
combination (for access T'Class), then you can define a clear meaning
for its implementation. In the case of access T'Class, the meaning is
referential replacement.

> Therefore your argument about the number of
> combinations is irrelevant for any user- or compiler-generated assignment.

It is very relevant. With the number of combinations in the order of
O(n*n) you are not going to make it right.

> what is the
> *semantic* difference between access T'Class and T'Class beyond that?

For example sharing. This is beyond the fundamental difference that
exists between replacement and assignment.

> Nope, you cannot say that the difference is in assignment, because now we
> are talking about "ability to point" and "ability to hold." What makes
> "point" different to "hold", semantically I mean?

Ability to share?

Let's keep sharing aside for the moment, though. The real difference
is that object is not a container and the "holding" doesn't work
there. Objects *have* values, they don't "hold" values. Containers can
"hold" objects that *have* some values themselves. And so on, up to
and including the fact that access variable can *point* to an object
(that *has* some value).

(yes, I know - you will now ask me what is the *semantic* difference
between holding and having... nevermind :-) )

Pointing and having value are different - ability to share is one of
the consequences, replacement-is-not-an-assignment is another.

> > OK, even better. Let's ban assignment for all unconstrained types. :-)
>
> My congratulations! But that's not all:
>
> procedure Swap (X, Y : in out Integer);
>
> declare
>    X : Positive := 1;
>    Y : Integer := -1;
> begin
>    Swap (X, Y);
>     -- oops

Yes, let's ban it too. Inout parameters should match exactly in terms
of constraints (see below).

> I hope you see now, why your proposal is inconsistent with any type system
> with constrained [sub]types (classes is just a specific case of)?

No, I don't see why it's inconsistent.
The above code gives CONSTRAINT_ERROR at run-time. It's obvious and
the code is just dangerous.

1. for "in" formal parameters the actual parameter can have stricter
constraints (it can be subrange, it can be subclass, etc.)
2. for "out" formal parameters (and return values) the actual
parameter can have looser constraints (it can be superrange, it can be
a superclass, etc.)
3. for "in out" formal parameters the actual parameter must have
matching constraints.

Nothing new. Just a regular pre- and post-condition stuff.
If this is not guaranteed at compile-time, it has to be checked at run-
time, but then why not writing everything in Python.

All our examples so far fell into pieces with point 3. above.

> Further,
> it is incompatible with specialization and generic programming on sets of
> specialized types.

No, there is no incompatibility. At least I don't see it (and you
didn't show any).

> Huh, speaking of general natures, the problem is a misconception shared by
> LSP-ers. The issue can be summarized in three lines:
>
> 1. Specialization breaks all out-methods of the base type
> 2. Generalization breaks all in-.methods of the base type
> 3. Variation breaks everything

Elaborate please.

> > No. Regular objects are declared as Triangles and Circles (and these
> > types may have reasonable assignments - after all, assigning one
> > Triangle to another makes sense). The problem is when you declare
> > something as T'Class.
>
> Wrong. Assignment is a primitive operation <=> it is defined on T'Class.

That's bad. And we are going in circles.

> > T'Class /= T and this is one of the things that make them different.
> > I know that it shakes part of the concept of a class.
>
> Yep, it demolishes class and primitive operations of.

You have just thrown assignment together with other (real) primitive
operations and then come to common conclusions. My point is that
assignment is *not* a regular primitive operation.

> > But you have the same problem with unconstrained types. They might not
> > support all operations of their constrained equivalents.
>
> What does it mean "not support"? You have to translate this into illegal
> ("type error") / legal ("no type error").

/ conditionally_legal ("let's raise CONSTRAINT_ERROR later")?

> Either you scrap the type system, by forbidding any intertype relations

One of your discussion strategies is to force others to believe that
they have only those choices that you arbitrariliy give them. :-)

> In the middle there exists a wide
> range of semi-consistent languages like C++ and, alas, Ada.

Yes, that's why we have this discussion. :-)


> > X : T;
> > Y : T'Class := Whatever;
>
> > Do_Something(X); -- (1)
> > Do_Something(Y); -- (2)
>
> > Which of the two above are dispatching (assume Do_Something is
> > primitive)?
>
> So? Following your argument destructor of X isn't dispatching either,
> because it will not dispatch in this piece of code.

It will dispatch with Unchecked_Deallocation on access T'Class.
And, basically, this is the only way to have dispatching destructor
call.

But there *is* a way to have polymorphic behavior for destructor,
whereas there is no way to have polymorphic constructor.

> A part of the constructor of T'Class is certainly dispatching.

No. There is nothing to dispatch on and with T'Class there is even
nothing to overload on:

function Make return Triangle;
function Make return Circle;

X : Object'Class := Make; -- ?

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-06 14:46                                                                         ` Maciej Sobczak
@ 2007-06-06 15:11                                                                           ` Maciej Sobczak
  0 siblings, 0 replies; 81+ messages in thread
From: Maciej Sobczak @ 2007-06-06 15:11 UTC (permalink / raw)


On 6 Cze, 16:46, Maciej Sobczak <see.my.homep...@gmail.com> wrote:

> > My congratulations! But that's not all:
>
> > procedure Swap (X, Y : in out Integer);
>
> > declare
> >    X : Positive := 1;
> >    Y : Integer := -1;
> > begin
> >    Swap (X, Y);
> >     -- oops
>
> Yes, let's ban it too. Inout parameters should match exactly in terms
> of constraints (see below).

Here I was confused by something different. This subject is unrelated
to assignment.

If we want class-wide types to behave in all aspects like
unconstrained types (or like constrained types that can have
additional constraints added), then indeed this example shows serious
problem with my reasoning.

I will come back to this in a while.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-06-05 22:12                                                                     ` Maciej Sobczak
  2007-06-06  8:21                                                                       ` Dmitry A. Kazakov
@ 2007-06-06 15:32                                                                       ` Markus E Leypold
  1 sibling, 0 replies; 81+ messages in thread
From: Markus E Leypold @ 2007-06-06 15:32 UTC (permalink / raw)



<... snipped ...>

> (We are really going in circles.)

Welcome to the Kazakov Continuum. :-). 

Regards -- Markus




^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Ada Interfaces and the Liskov Substitution Principle
  2007-05-24 22:08           ` Robert A Duff
@ 2007-07-01  1:00             ` David Thompson
  0 siblings, 0 replies; 81+ messages in thread
From: David Thompson @ 2007-07-01  1:00 UTC (permalink / raw)


On Thu, 24 May 2007 18:08:05 -0400, Robert A Duff
<bobduff@shell01.TheWorld.com> wrote:

> Well, actually, in Ada terminology, an initialization is an assignment.
> There are two kinds of assignment: initialization, and
> assignment_statement.  I don't particularly like that terminology, but
> it's what the RM says.
<snip>
> You're talking about an assignment_statement.  Best to stick to the
> terms "initialization" and "assignment_statement" to avoid confusion.
> And avoid the term "assignment" entirely.  ;-)
> 
Algol 68 called it 'assignation'. Sadly we didn't get rendezvous and
assignation in one language; that could have been popular indeed.

> I'm just nitpicking your terminology -- I agree with your point <snip>

- formerly david.thompson1 || achar(64) || worldnet.att.net



^ permalink raw reply	[flat|nested] 81+ messages in thread

end of thread, other threads:[~2007-07-01  1:00 UTC | newest]

Thread overview: 81+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-05-23 19:47 Ada Interfaces and the Liskov Substitution Principle Stefan Lucks
2007-05-23 20:32 ` Ludovic Brenta
2007-05-23 22:00   ` Randy Brukardt
2007-05-24  0:56     ` Anh Vo
2007-05-24 18:27     ` Pascal Obry
2007-05-24 18:39       ` Dmitry A. Kazakov
2007-05-24 18:51         ` Pascal Obry
2007-05-24 22:44         ` Randy Brukardt
2007-05-24  6:57   ` Stefan Lucks
2007-05-23 20:54 ` Maciej Sobczak
2007-05-23 21:58   ` Randy Brukardt
2007-05-24  7:29     ` Maciej Sobczak
2007-05-24  8:02       ` Dmitry A. Kazakov
2007-05-24 12:58         ` Maciej Sobczak
2007-05-24 13:42           ` Dmitry A. Kazakov
2007-05-24 22:08           ` Robert A Duff
2007-07-01  1:00             ` David Thompson
2007-05-24 22:58           ` Randy Brukardt
2007-05-25  7:52             ` Maciej Sobczak
2007-05-25  8:21               ` Dmitry A. Kazakov
2007-05-25 20:27                 ` Maciej Sobczak
2007-05-26  7:48                   ` Dmitry A. Kazakov
2007-05-27  8:30                     ` Maciej Sobczak
2007-05-27 10:04                       ` Dmitry A. Kazakov
2007-05-29  8:03                         ` Maciej Sobczak
2007-05-29 13:18                           ` Dmitry A. Kazakov
2007-05-29 13:32                             ` Dmitry A. Kazakov
2007-05-29 15:34                             ` Maciej Sobczak
2007-05-29 17:07                               ` Dmitry A. Kazakov
2007-05-30  7:40                                 ` Maciej Sobczak
2007-05-30  8:43                                   ` Dmitry A. Kazakov
2007-05-30 12:54                                     ` Maciej Sobczak
2007-05-30 13:56                                       ` Dmitry A. Kazakov
2007-05-30 16:49                                         ` vgodunko
2007-05-30 20:52                                         ` Maciej Sobczak
2007-05-31  8:15                                           ` Dmitry A. Kazakov
2007-05-31 13:46                                             ` Maciej Sobczak
2007-06-01  7:29                                               ` Dmitry A. Kazakov
2007-06-01 13:32                                                 ` Maciej Sobczak
2007-06-01 14:53                                                   ` Dmitry A. Kazakov
2007-06-01 20:31                                                     ` Maciej Sobczak
2007-06-02  8:19                                                       ` Dmitry A. Kazakov
2007-06-02 16:49                                                         ` Maciej Sobczak
2007-06-03  7:09                                                           ` Dmitry A. Kazakov
2007-06-03 22:04                                                             ` Maciej Sobczak
2007-06-04  8:08                                                               ` Dmitry A. Kazakov
2007-06-04 17:02                                                                 ` Maciej Sobczak
2007-06-05  8:35                                                                   ` Dmitry A. Kazakov
2007-06-05 22:12                                                                     ` Maciej Sobczak
2007-06-06  8:21                                                                       ` Dmitry A. Kazakov
2007-06-06 14:46                                                                         ` Maciej Sobczak
2007-06-06 15:11                                                                           ` Maciej Sobczak
2007-06-06 15:32                                                                       ` Markus E Leypold
2007-05-24 10:42       ` Georg Bauhaus
2007-05-24 13:41         ` Dmitry A. Kazakov
2007-05-25 16:59         ` Markus E Leypold
2007-05-28  9:52           ` Georg Bauhaus
2007-05-28 11:50             ` Dmitry A. Kazakov
2007-05-28 23:32               ` Georg Bauhaus
2007-05-29 12:05                 ` Dmitry A. Kazakov
2007-05-29 13:33                 ` Georg Bauhaus
2007-05-29 17:29                   ` Dmitry A. Kazakov
2007-05-29 20:46                     ` Georg Bauhaus
2007-05-30  7:53                       ` Dmitry A. Kazakov
2007-05-30 13:18                       ` Georg Bauhaus
2007-05-31 10:27                         ` Dmitry A. Kazakov
2007-05-31 11:44                         ` Georg Bauhaus
2007-06-01  7:37                           ` Dmitry A. Kazakov
2007-06-01 10:07                             ` Markus E Leypold
2007-06-01 11:41                             ` Georg Bauhaus
2007-06-01 13:07                               ` Dmitry A. Kazakov
2007-05-28 13:47             ` Markus E Leypold
2007-05-28 23:12               ` Georg Bauhaus
2007-05-28 13:56             ` Markus E Leypold
2007-05-28 23:00               ` Georg Bauhaus
2007-05-24  7:39 ` Dmitry A. Kazakov
2007-05-24 11:12   ` Stefan Lucks
2007-05-24 13:56     ` Dmitry A. Kazakov
2007-05-24 14:41       ` Stefan Lucks
2007-05-24 15:46         ` Dmitry A. Kazakov
2007-05-24 15:00       ` Georg Bauhaus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox