comp.lang.ada
 help / color / mirror / Atom feed
* Extension of non-limited type needs limited component
@ 2002-11-13 10:03 Mike
  2002-11-13 12:06 ` Jean-Pierre Rosen
  2002-11-13 14:28 ` Robert A Duff
  0 siblings, 2 replies; 33+ messages in thread
From: Mike @ 2002-11-13 10:03 UTC (permalink / raw)


How do I extend a non-limited tagged type to add a limited component?

Mike



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

* Re: Extension of non-limited type needs limited component
  2002-11-13 10:03 Extension of non-limited type needs limited component Mike
@ 2002-11-13 12:06 ` Jean-Pierre Rosen
  2002-11-14  9:26   ` Mike
  2002-11-13 14:28 ` Robert A Duff
  1 sibling, 1 reply; 33+ messages in thread
From: Jean-Pierre Rosen @ 2002-11-13 12:06 UTC (permalink / raw)


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


"Mike" <michael.jackson5@virgin.net> a �crit dans le message news:
2dbd76f3.0211130203.7d2d14fd@posting.google.com...
> How do I extend a non-limited tagged type to add a limited component?
>
You can't. Make the original type limited.
The whole hierarchy has to be limited (or not limited, excluding adding a
limited element). The reason is that otherwise, you could end up trying to
assign a variable with a limited component.

--
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr





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

* Re: Extension of non-limited type needs limited component
  2002-11-13 10:03 Extension of non-limited type needs limited component Mike
  2002-11-13 12:06 ` Jean-Pierre Rosen
@ 2002-11-13 14:28 ` Robert A Duff
  2002-11-14  9:33   ` Mike
  1 sibling, 1 reply; 33+ messages in thread
From: Robert A Duff @ 2002-11-13 14:28 UTC (permalink / raw)


michael.jackson5@virgin.net (Mike) writes:

> How do I extend a non-limited tagged type to add a limited component?

You don't.  ;-)  You can extend it with a pointer-to-limited component,
however.  But your best bet may be to make the non-limited type
limited.  Or make the component non-limited.

- Bob



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

* Re: Extension of non-limited type needs limited component
  2002-11-13 12:06 ` Jean-Pierre Rosen
@ 2002-11-14  9:26   ` Mike
  2002-11-14 11:43     ` David C. Hoos, Sr.
                       ` (2 more replies)
  0 siblings, 3 replies; 33+ messages in thread
From: Mike @ 2002-11-14  9:26 UTC (permalink / raw)


I wrote

> > How do I extend a non-limited tagged type to add a limited component?

Jean-Pierre Rosen replied

> You can't. Make the original type limited.
> The whole hierarchy has to be limited (or not limited, excluding adding a
> limited element). The reason is that otherwise, you could end up trying to
> assign a variable with a limited component.

Unfortunately I can't make the base type limited as it is a generic
gui dialog base 'class'.

I understand that I would need to make the extended type limited to
avoid the possible assignment to the limited component, but I cannot
see why I should have to make the whole hierarchy limited.

How can assignment by upcasting the extended type possibly affect the
limited component?

Regards,

Mike



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

* Re: Extension of non-limited type needs limited component
  2002-11-13 14:28 ` Robert A Duff
@ 2002-11-14  9:33   ` Mike
  2002-11-14  9:35     ` Lutz Donnerhacke
  2002-11-14 21:41     ` Robert A Duff
  0 siblings, 2 replies; 33+ messages in thread
From: Mike @ 2002-11-14  9:33 UTC (permalink / raw)


I wrote

> > How do I extend a non-limited tagged type to add a limited component?

Robert A Duff replied

> You don't.  ;-)  You can extend it with a pointer-to-limited component,
> however.  But your best bet may be to make the non-limited type
> limited.  Or make the component non-limited.

Unfortunately neither the base type nor the limited component are
under my control.
I have thought about the pointer-to-limited option but find that there
is no pointer type declared in the package that declares the limited
type and consequently there are no operations on the limited type that
take a pointer type.
Am I allowed to create my own pointer-to-limited type and de-reference
it for use later? Wouldn't the act of de-referenceing be an implicit
assignment?

Regards,
Mike.



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

* Re: Extension of non-limited type needs limited component
  2002-11-14  9:33   ` Mike
@ 2002-11-14  9:35     ` Lutz Donnerhacke
  2002-11-14 21:41     ` Robert A Duff
  1 sibling, 0 replies; 33+ messages in thread
From: Lutz Donnerhacke @ 2002-11-14  9:35 UTC (permalink / raw)


* Mike wrote:
> Am I allowed to create my own pointer-to-limited type and de-reference
> it for use later?

Yes. This enshures the locality of the pointer use. That's why it's Ada
style to not provide pointers in the base packets.

> Wouldn't the act of de-referenceing be an implicit assignment?

No.



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

* Re: Extension of non-limited type needs limited component
  2002-11-14  9:26   ` Mike
@ 2002-11-14 11:43     ` David C. Hoos, Sr.
  2002-11-14 12:33     ` Jean-Pierre Rosen
  2002-11-14 23:39     ` Robert A Duff
  2 siblings, 0 replies; 33+ messages in thread
From: David C. Hoos, Sr. @ 2002-11-14 11:43 UTC (permalink / raw)


----- Original Message ----- 
From: "Mike" <michael.jackson5@virgin.net>
Newsgroups: comp.lang.ada
To: <comp.lang.ada@ada.eu.org>
Sent: November 14, 2002 3:26 AM
Subject: Re: Extension of non-limited type needs limited component


> I wrote
> 
> > > How do I extend a non-limited tagged type to add a limited component?
> 
> Jean-Pierre Rosen replied
> 
> > You can't. Make the original type limited.
> > The whole hierarchy has to be limited (or not limited, excluding adding a
> > limited element). The reason is that otherwise, you could end up trying to
> > assign a variable with a limited component.
> 
> Unfortunately I can't make the base type limited as it is a generic
> gui dialog base 'class'.
> 
> I understand that I would need to make the extended type limited to
> avoid the possible assignment to the limited component, but I cannot
> see why I should have to make the whole hierarchy limited.
> 
> How can assignment by upcasting the extended type possibly affect the
> limited component?
> 
Since the purpose of "limited" is to prevent having multiple copies of the
same object (e.g. an object of Ada.Text_IO.File_Type) wherein changing the
state of one of the copies is changed (e.g. by closing the file in the
previous example) would leave the other copy in an incorrect state,
allowing limited components in a non-limited record would violate this
principle.

On the other hand, if multiple access objects are used to designate the
same limited object, then changes to the state by reference through one
of the access objects will be reflected in all of the access objects
designating that limited object.

Of course, the specifier of a limited type may provide a Copy procedure
(e.g., with a declaration like
procedure Copy (From : My_Limited_Type; To : out My_Limited_Type);
In that case, the fact that use of a Copy procedure is required, rather
than a simple assignment, makes the user of the type aware, that he
is creating a new distinct object, not a new reference to an existing
object.




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

* Re: Extension of non-limited type needs limited component
  2002-11-14  9:26   ` Mike
  2002-11-14 11:43     ` David C. Hoos, Sr.
@ 2002-11-14 12:33     ` Jean-Pierre Rosen
  2002-11-14 14:27       ` Dmitry A. Kazakov
  2002-11-14 23:39     ` Robert A Duff
  2 siblings, 1 reply; 33+ messages in thread
From: Jean-Pierre Rosen @ 2002-11-14 12:33 UTC (permalink / raw)


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


"Mike" <michael.jackson5@virgin.net> a �crit dans le message news:
2dbd76f3.0211140126.5d233e41@posting.google.com...
> How can assignment by upcasting the extended type possibly affect the
> limited component?
>
Consider:

   X : T'class := Some_Dynamic_Function (1);
   Y : T'class := Some_Dynamic_Function (2);
begin
   X := Y;

At compile time, we know nothing about the specific type of the values in X
and Y, but assuming that T is not limited, the assignment is allowed. If X
and Y happen to have different tags at run time, the assignment will raise
Constraint_Error, but that's all.

If you were allowed to extend T with limited components, you would
effectively copy the limited components!

--
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr





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

* Re: Extension of non-limited type needs limited component
  2002-11-14 12:33     ` Jean-Pierre Rosen
@ 2002-11-14 14:27       ` Dmitry A. Kazakov
  2002-11-14 19:25         ` Randy Brukardt
  2002-11-15  0:30         ` Robert A Duff
  0 siblings, 2 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2002-11-14 14:27 UTC (permalink / raw)


On Thu, 14 Nov 2002 13:33:07 +0100, "Jean-Pierre Rosen"
<rosen@adalog.fr> wrote:

>"Mike" <michael.jackson5@virgin.net> a �crit dans le message news:
>2dbd76f3.0211140126.5d233e41@posting.google.com...
>> How can assignment by upcasting the extended type possibly affect the
>> limited component?
>>
>Consider:
>
>   X : T'class := Some_Dynamic_Function (1);
>   Y : T'class := Some_Dynamic_Function (2);
>begin
>   X := Y;
>
>At compile time, we know nothing about the specific type of the values in X
>and Y, but assuming that T is not limited, the assignment is allowed. If X
>and Y happen to have different tags at run time, the assignment will raise
>Constraint_Error, but that's all.
>
>If you were allowed to extend T with limited components, you would
>effectively copy the limited components!

An LSP violation to put it short.

Which also raises an interesting question, whether T'Class should
always inherit "non-limitness" of T. Or more generally shouldn't one
have an ability to disallow primitive operations (like ":=" in case of
non-limited->limited mutation)?

Let we allow disallowing, then either

1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise
an exception and so refuse to copy the limited components.

2. ":=" is class-wide in the right parameter, then it will dispatch
somewhere within its body and again an exception will happen if an
attempt to copy a limited component will be made..

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



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

* Re: Extension of non-limited type needs limited component
  2002-11-14 14:27       ` Dmitry A. Kazakov
@ 2002-11-14 19:25         ` Randy Brukardt
  2002-11-15 10:04           ` Dmitry A. Kazakov
  2002-11-15 21:41           ` Robert A Duff
  2002-11-15  0:30         ` Robert A Duff
  1 sibling, 2 replies; 33+ messages in thread
From: Randy Brukardt @ 2002-11-14 19:25 UTC (permalink / raw)


Dmitry A. Kazakov wrote in message
<3vb7tug4h99mmalcn0l5ul18cu0ui6i458@4ax.com>...
>Which also raises an interesting question, whether T'Class should
>always inherit "non-limitness" of T. Or more generally shouldn't one
>have an ability to disallow primitive operations (like ":=" in case of
>non-limited->limited mutation)?


Of course, Ada has the capability to disallow ":=". It's called (drum
roll) "limited". :-)

This issue was discussed extensively during the Ada 95 design process.
It seems like some way to disallow ":=" is needed, but we kept coming
back to the point that that is what "limited" is for. We certainly don't
need two notions of no ":=".

>...
>1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise
>an exception and so refuse to copy the limited components.


I don't know why this wasn't chosen. It seems better on the surface.
Possibly because of the desire to catch errors at compile-time rather
than run-time.

However, that still doesn't solve the problem that we had in Claw. What
we wanted was a limited root window type with non-limited (thus
assignable) controls. That is, something like:

      Root_Window_Type (limited controlled)
           Basic_Window_Type (limited)
           Root_Dialog_Type (limited)
                Modal_Dialog_Type (limited)
          Root_Control_Type (non-limited)
                Edit_Type (non-limited)
                Checkbox_Type (non-limited)
                Static_Text_Type (non-limited)

[We want to be able to copy control objects because our goal was "no
visible pointers required" for the interface.]

This does not have the classwide assignment problem, because only
Root_Control_Type has ":=", so it isn't possible to dispatch to a
limited type's ":=".

We ended up making the whole hierarchy non-limited, but this means
implementing assignment for types for which is both a lot of work and
unneeded (such as application windows). Worse, we didn't meet our "no
pointers" goal, because we can't put limited objects into extentions of
application windows. (So you have to use pointers to do that.)

I don't recall why you are not allowed to make the extension of the
limited type non-limited. (I didn't find anything in the AARM on this
subject.)

                   Randy Brukardt







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

* Re: Extension of non-limited type needs limited component
  2002-11-14  9:33   ` Mike
  2002-11-14  9:35     ` Lutz Donnerhacke
@ 2002-11-14 21:41     ` Robert A Duff
  1 sibling, 0 replies; 33+ messages in thread
From: Robert A Duff @ 2002-11-14 21:41 UTC (permalink / raw)


michael.jackson5@virgin.net (Mike) writes:

> Am I allowed to create my own pointer-to-limited type and de-reference
> it for use later?

Yes.  You just need to say ".all" whenever you want to call the
preexisting procedures.

The only problem with using a pointer that then you have to worry about
storage management.  You'll probably end up allocating the thing in the
heap (with "new"), and then you have to worry about deallocating it.

>... Wouldn't the act of de-referenceing be an implicit
> assignment?

No.  "X.all" returns the heap object that the pointer points at.
It does not fetch the value out of that object.  The fetch operation is
really what limited types want to disallow.

When you say P(X.all), the heap object will be passed by reference if it
is really limited -- no copy is made.

- Bob



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

* Re: Extension of non-limited type needs limited component
  2002-11-14  9:26   ` Mike
  2002-11-14 11:43     ` David C. Hoos, Sr.
  2002-11-14 12:33     ` Jean-Pierre Rosen
@ 2002-11-14 23:39     ` Robert A Duff
  2002-11-15 21:51       ` Mike
  2 siblings, 1 reply; 33+ messages in thread
From: Robert A Duff @ 2002-11-14 23:39 UTC (permalink / raw)


michael.jackson5@virgin.net (Mike) writes:

> How can assignment by upcasting the extended type possibly affect the
> limited component?

If you have "type T2 is new T1 with...", then it is important that if T2
is limited, then T1'Class must also be limited, because ":=" on T1'Class
objects will copy the T2 part, if the objects' tag happens to be T2'Tag.

In Ada, T1'Class is limited if and only if T1 is limited.
So that means the whole hierarchy of tagged types has to be
either limited or nonlimited.  I'm not sure if it would cause semantic
troubles to allow a nonlimited T1 with a limited T1'Class (assuming one
could invent some syntax for saying so).  Interesting question.

- Bob



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

* Re: Extension of non-limited type needs limited component
  2002-11-14 14:27       ` Dmitry A. Kazakov
  2002-11-14 19:25         ` Randy Brukardt
@ 2002-11-15  0:30         ` Robert A Duff
  2002-11-15 10:22           ` Dmitry A. Kazakov
  1 sibling, 1 reply; 33+ messages in thread
From: Robert A Duff @ 2002-11-15  0:30 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

> Which also raises an interesting question, whether T'Class should
> always inherit "non-limitness" of T. Or more generally shouldn't one
> have an ability to disallow primitive operations (like ":=" in case of
> non-limited->limited mutation)?
> 
> Let we allow disallowing, then either
> 
> 1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise
> an exception and so refuse to copy the limited components.

Compile time errors are good.  Exceptions (run-time errors) are evil.
This is not SmallTalk, where you can dispatch to a method that does not
exist.

- Bob



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

* Re: Extension of non-limited type needs limited component
  2002-11-14 19:25         ` Randy Brukardt
@ 2002-11-15 10:04           ` Dmitry A. Kazakov
  2002-11-15 22:09             ` Robert A Duff
  2002-11-15 21:41           ` Robert A Duff
  1 sibling, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2002-11-15 10:04 UTC (permalink / raw)


On Thu, 14 Nov 2002 13:25:13 -0600, "Randy Brukardt"
<randy@rrsoftware.com> wrote:

>Dmitry A. Kazakov wrote in message
><3vb7tug4h99mmalcn0l5ul18cu0ui6i458@4ax.com>...
>>Which also raises an interesting question, whether T'Class should
>>always inherit "non-limitness" of T. Or more generally shouldn't one
>>have an ability to disallow primitive operations (like ":=" in case of
>>non-limited->limited mutation)?
>
>Of course, Ada has the capability to disallow ":=". It's called (drum
>roll) "limited". :-)
>
>This issue was discussed extensively during the Ada 95 design process.
>It seems like some way to disallow ":=" is needed, but we kept coming
>back to the point that that is what "limited" is for.

In an OO language like Ada 95 is, "limited" makes little sense,
because it covers only one of many useful alternatives.

>We certainly don't need two notions of no ":=".

But there are indeed multiple notions of ":=". Let ":=" is exposed as
a normal operation. Then two arguments would give us 4 different
variants [without much thinking about how useful are some of them]:

procedure ":=" (Left : in out T; Right : T);
procedure ":=" (Left : in out T'Class; Right : T);
procedure ":=" (Left : in out T; Right : T'Class);
procedure ":=" (Left : in out T'Class; Right : T'Class);

Same is valid for all operations with several parameters. For
instance, the predefined "=" (Left, Right : T), which cannot be
disallowed with a disastrous result that a user-defined "=" (Left : T;
Right : T'Class) gets overloaded with the predefined one.

>>1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise
>>an exception and so refuse to copy the limited components.

>I don't know why this wasn't chosen. It seems better on the surface.
>Possibly because of the desire to catch errors at compile-time rather
>than run-time.

Yep, LSP again. However, nobody cares about LSP in case of

   X : Positive;

which also shamefully violates LSP and leads to a run-time exception,
should -1 happen to be assigned to X.

>However, that still doesn't solve the problem that we had in Claw. What
>we wanted was a limited root window type with non-limited (thus
>assignable) controls. That is, something like:
>
>      Root_Window_Type (limited controlled)
>           Basic_Window_Type (limited)
>           Root_Dialog_Type (limited)
>                Modal_Dialog_Type (limited)
>          Root_Control_Type (non-limited)
>                Edit_Type (non-limited)
>                Checkbox_Type (non-limited)
>                Static_Text_Type (non-limited)
>
>[We want to be able to copy control objects because our goal was "no
>visible pointers required" for the interface.]

BTW. Why do not we have constant record members in Ada? Maybe because
there is no true contructors with parameters?

>This does not have the classwide assignment problem, because only
>Root_Control_Type has ":=", so it isn't possible to dispatch to a
>limited type's ":=".
>
>We ended up making the whole hierarchy non-limited, but this means
>implementing assignment for types for which is both a lot of work and
>unneeded (such as application windows). Worse, we didn't meet our "no
>pointers" goal, because we can't put limited objects into extentions of
>application windows. (So you have to use pointers to do that.)

This is an opposite this = defining new operations. It should be a
lesser problem (for LSP).

>I don't recall why you are not allowed to make the extension of the
>limited type non-limited. (I didn't find anything in the AARM on this
>subject.)

A need to generate some predefined assignment?

The whole idea of "limitness" is IMO wrong. Let's expose ":=", default
constructor, copy constructor to the programmer and let he have a
headache! (:-))

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



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

* Re: Extension of non-limited type needs limited component
  2002-11-15  0:30         ` Robert A Duff
@ 2002-11-15 10:22           ` Dmitry A. Kazakov
  2002-11-15 21:56             ` Robert A Duff
  0 siblings, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2002-11-15 10:22 UTC (permalink / raw)


On Fri, 15 Nov 2002 00:30:03 GMT, Robert A Duff
<bobduff@shell01.TheWorld.com> wrote:

>Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
>
>> Which also raises an interesting question, whether T'Class should
>> always inherit "non-limitness" of T. Or more generally shouldn't one
>> have an ability to disallow primitive operations (like ":=" in case of
>> non-limited->limited mutation)?
>> 
>> Let we allow disallowing, then either
>> 
>> 1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise
>> an exception and so refuse to copy the limited components.
>
>Compile time errors are good.  Exceptions (run-time errors) are evil.

Absolutely

>This is not SmallTalk, where you can dispatch to a method that does not
>exist.

Sure? And what about this:

type A is tagged ...
procedure Foo (L, R : A);

type B is new A with ....

X : A'Class := Some_A;
Y : A'Class := Some_B;

Foo (X, Y); -- Oops, dispatching to nowhere!

[ Not that I argue for SmallTalk, of course (:-)) ]

Then disallowing is already allowed for non-tagged types =
"is abstract". 

Further one can always override with a subroutine that throws
Program_Error. Is that better? IMO it is the same. The only real
difference is that one cannot get rid of overloading of the undesired
operation. What is actually required. I think that there could be
situations where it would be useful to disallow an operation in the
public interface and to override it with something working in the
private one.

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



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

* Re: Extension of non-limited type needs limited component
@ 2002-11-15 10:47 Grein, Christoph
  2002-11-15 12:12 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 33+ messages in thread
From: Grein, Christoph @ 2002-11-15 10:47 UTC (permalink / raw)


> >This is not SmallTalk, where you can dispatch to a method that does not
> >exist.
> 
> Sure? And what about this:
> 
> type A is tagged ...
> procedure Foo (L, R : A);
> 
> type B is new A with ....
> 
> X : A'Class := Some_A;
> Y : A'Class := Some_B;
> 
> Foo (X, Y); -- Oops, dispatching to nowhere!

Either compiler catches this and does not compile.
Or during runtime, tag check is performed and will raise Constraint_Error.

No dispatching to nowhere!



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

* Re: Extension of non-limited type needs limited component
  2002-11-15 10:47 Grein, Christoph
@ 2002-11-15 12:12 ` Dmitry A. Kazakov
  2002-11-15 13:29   ` Jean-Pierre Rosen
  0 siblings, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2002-11-15 12:12 UTC (permalink / raw)


On Fri, 15 Nov 2002 11:47:49 +0100 (MET), "Grein, Christoph"
<christoph.grein@eurocopter.com> wrote:

>> >This is not SmallTalk, where you can dispatch to a method that does not
>> >exist.
>> 
>> Sure? And what about this:
>> 
>> type A is tagged ...
>> procedure Foo (L, R : A);
>> 
>> type B is new A with ....
>> 
>> X : A'Class := Some_A;
>> Y : A'Class := Some_B;
>> 
>> Foo (X, Y); -- Oops, dispatching to nowhere!
>
>Either compiler catches this and does not compile.
>Or during runtime, tag check is performed and will raise Constraint_Error.
>
>No dispatching to nowhere!

Of course. Under dispatching to nowhere I just meant dispatching to a
non-existing method:

Foo (L : A; R: B);

Both Ada and SmallTalk [AFAIK] do not crash when such thing happens.
But this is not the problem. The problem is that though one could wish
to detect all such and similar cases at compile time, one cannot. This
does not mean that we should drop compile-time checks. [To put it
clear, Ada is right, SmallTalk is wrong! (:-))] It only means that the
argument, "this is not allowed, because it cannot be fully checked at
compile time" is wrong. Alas, there are many damn useful things
uncheckable at compile time.

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



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

* Re: Extension of non-limited type needs limited component
  2002-11-15 12:12 ` Dmitry A. Kazakov
@ 2002-11-15 13:29   ` Jean-Pierre Rosen
  2002-11-15 14:34     ` Dmitry A. Kazakov
  2002-11-15 21:26     ` Robert A Duff
  0 siblings, 2 replies; 33+ messages in thread
From: Jean-Pierre Rosen @ 2002-11-15 13:29 UTC (permalink / raw)


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


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> a �crit dans le message
news:
> Both Ada and SmallTalk [AFAIK] do not crash when such thing happens.
> But this is not the problem. The problem is that though one could wish
> to detect all such and similar cases at compile time, one cannot. This
> does not mean that we should drop compile-time checks. [To put it
> clear, Ada is right, SmallTalk is wrong! (:-))] It only means that the
> argument, "this is not allowed, because it cannot be fully checked at
> compile time" is wrong. Alas, there are many damn useful things
> uncheckable at compile time.

... with tagged types.

The benefit, and drawback, of tagged types is that they allow dynamic
typing, therefore requiring (isn't it surprising) dynamic checking. More
flexibility, less security. If you want full compile-time checking, don't
use tagged types.
At least in Ada, you have a choice!

--
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr





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

* Re: Extension of non-limited type needs limited component
  2002-11-15 13:29   ` Jean-Pierre Rosen
@ 2002-11-15 14:34     ` Dmitry A. Kazakov
  2002-11-15 21:26     ` Robert A Duff
  1 sibling, 0 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2002-11-15 14:34 UTC (permalink / raw)


On Fri, 15 Nov 2002 14:29:31 +0100, "Jean-Pierre Rosen"
<rosen@adalog.fr> wrote:

>"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> a �crit dans le message
>news:
>> Both Ada and SmallTalk [AFAIK] do not crash when such thing happens.
>> But this is not the problem. The problem is that though one could wish
>> to detect all such and similar cases at compile time, one cannot. This
>> does not mean that we should drop compile-time checks. [To put it
>> clear, Ada is right, SmallTalk is wrong! (:-))] It only means that the
>> argument, "this is not allowed, because it cannot be fully checked at
>> compile time" is wrong. Alas, there are many damn useful things
>> uncheckable at compile time.
>
>... with tagged types.
>
>The benefit, and drawback, of tagged types is that they allow dynamic
>typing, therefore requiring (isn't it surprising) dynamic checking. More
>flexibility, less security. If you want full compile-time checking, don't
>use tagged types.

You could also use a less restrictive "..., don't use class-wide
objects with tags unknown at compile-time."

>At least in Ada, you have a choice!

Right.

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



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

* Re: Extension of non-limited type needs limited component
  2002-11-15 13:29   ` Jean-Pierre Rosen
  2002-11-15 14:34     ` Dmitry A. Kazakov
@ 2002-11-15 21:26     ` Robert A Duff
  1 sibling, 0 replies; 33+ messages in thread
From: Robert A Duff @ 2002-11-15 21:26 UTC (permalink / raw)


"Jean-Pierre Rosen" <rosen@adalog.fr> writes:

> The benefit, and drawback, of tagged types is that they allow dynamic
> typing, therefore requiring (isn't it surprising) dynamic checking. More
> flexibility, less security. If you want full compile-time checking, don't
> use tagged types.

Well, it's not quite that bad.  Dmitry Kazakov posted the example of a
procedure with 2 controlling operands.  Yes, that requires a tag check.
Downward conversions require a tag check.  But normal dispatching on a
single controlling operand (which is by far the most common case)
requires no run-time check.  So, for most of your code, you can freely
use tagged and class-wide types, and *still* get full compile-time
checking.  That's the advantage of Ada (and C++ and Java) over Smalltalk
(and CLOS and ...).

In other words, "...don't use tagged types" is too strong.

> At least in Ada, you have a choice!

Yes.

- Bob



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

* Re: Extension of non-limited type needs limited component
  2002-11-14 19:25         ` Randy Brukardt
  2002-11-15 10:04           ` Dmitry A. Kazakov
@ 2002-11-15 21:41           ` Robert A Duff
  2002-11-16  3:54             ` Randy Brukardt
  1 sibling, 1 reply; 33+ messages in thread
From: Robert A Duff @ 2002-11-15 21:41 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> Dmitry A. Kazakov wrote in message
> >1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise
> >an exception and so refuse to copy the limited components.
> 
> I don't know why this wasn't chosen. It seems better on the surface.
> Possibly because of the desire to catch errors at compile-time rather
> than run-time.

Exactly.

> However, that still doesn't solve the problem that we had in Claw. What
> we wanted was a limited root window type with non-limited (thus
> assignable) controls. That is, something like:
> 
>       Root_Window_Type (limited controlled)
>            Basic_Window_Type (limited)
>            Root_Dialog_Type (limited)
>                 Modal_Dialog_Type (limited)
>           Root_Control_Type (non-limited)
>                 Edit_Type (non-limited)
>                 Checkbox_Type (non-limited)
>                 Static_Text_Type (non-limited)
> 
> [We want to be able to copy control objects because our goal was "no
> visible pointers required" for the interface.]
> 
> This does not have the classwide assignment problem, because only
> Root_Control_Type has ":=", so it isn't possible to dispatch to a
> limited type's ":=".
> 
> We ended up making the whole hierarchy non-limited, but this means
> implementing assignment for types for which is both a lot of work and
> unneeded (such as application windows). Worse, we didn't meet our "no
> pointers" goal, because we can't put limited objects into extentions of
> application windows. (So you have to use pointers to do that.)
> 
> I don't recall why you are not allowed to make the extension of the
> limited type non-limited. (I didn't find anything in the AARM on this
> subject.)

I don't think it would work, because ":=" on a derived type copies the
parent part, which is limited, and therefore not copyable:

    package Root_Windows is
        type Root_Window_Type is tagged limited private;
    private
        type Root_Window_Ptr is access all Root_Window_Type;
        type Root_Window_Type(Discrim: access Blah) is tagged limited
            record
                Self: Root_Window_Ptr := Root_Window_Type'Unchecked_Access;
                T: Some_Task_Type;
            end record;
    end Root_Windows;

    package Root_Controls is
        type Root_Control_Type is new Root_Window_Type with private
            is not limited; -- I'm inventing syntax here.
        ...
    end Root_Controls;

    X, Y: Root_Control_Type;

    ...

    X := Y; -- Bad.

The assignment above is copying a task, which is bad news.  It is also
copying an access discriminant, which is bad news.  Also, the component
Self of X is supposed to point at X, and the assignment defeats that.

I suppose it could work if all ancestor limited types are not private.
Then we could add a rule saying that deriving a new non-limited type is
OK if the ancestor types *could have been* non-limited -- that is, they
don't violate any of the rules for non-limited types (e.g., no access
discriminants allowed).

But that would be a rather severe restriction -- I *want* most of my
types to be private.

Here's another alternative: you could invent a new kind of type --
"pseudo-limited".  A pseudo-limited type disallows assignment
statements, but *also* disallows all the things disallowed for
non-limited types.  A pseudo-limited type can have pseudo-limited
components, and non-limited components, but not limited components.
Then you could have a hierarchy with the root of the tree
pseudo-limited, with some subbranches being limited and some non-limited
(and some pseudo-limited).

Sounds complicated.  I haven't thought it through, so I'm not at all
sure it even works.

- Bob



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

* Re: Extension of non-limited type needs limited component
  2002-11-14 23:39     ` Robert A Duff
@ 2002-11-15 21:51       ` Mike
  0 siblings, 0 replies; 33+ messages in thread
From: Mike @ 2002-11-15 21:51 UTC (permalink / raw)


I originally wrote:

> > How can assignment by upcasting the extended type possibly affect the
> > limited component?
> 

Bob replied:

> If you have "type T2 is new T1 with...", then it is important that if T2
> is limited, then T1'Class must also be limited, because ":=" on T1'Class
> objects will copy the T2 part, if the objects' tag happens to be T2'Tag.
> 
> In Ada, T1'Class is limited if and only if T1 is limited.
> So that means the whole hierarchy of tagged types has to be
> either limited or nonlimited.  I'm not sure if it would cause semantic
> troubles to allow a nonlimited T1 with a limited T1'Class (assuming one
> could invent some syntax for saying so).  Interesting question.

Aha. That is the reason!

Thanks Bob,

Mike



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

* Re: Extension of non-limited type needs limited component
  2002-11-15 10:22           ` Dmitry A. Kazakov
@ 2002-11-15 21:56             ` Robert A Duff
  2002-11-16 12:39               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 33+ messages in thread
From: Robert A Duff @ 2002-11-15 21:56 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

> On Fri, 15 Nov 2002 00:30:03 GMT, Robert A Duff
> <bobduff@shell01.TheWorld.com> wrote:
> 
> >Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

> Sure? And what about this:
> 
> type A is tagged ...
> procedure Foo (L, R : A);
> 
> type B is new A with ....
> 
> X : A'Class := Some_A;
> Y : A'Class := Some_B;
> 
> Foo (X, Y); -- Oops, dispatching to nowhere!

True.  But I'm not happy about it.  And it doesn't mean single-argument
dispatching should be made more dangerous to match double-arg
dispatching.  ;-)

> [ Not that I argue for SmallTalk, of course (:-)) ]

;-)

> Then disallowing is already allowed for non-tagged types =
> "is abstract". 
> 
> Further one can always override with a subroutine that throws
> Program_Error. Is that better? IMO it is the same.

Yes, it is the same.  I see no reason to add special syntax to make it
easy, though.

Note that Java more-or-less prevents this problem by making exceptions
part of the visible contract.  I think they got some of the details
wrong, but they are on the right track.  The Java rules are a pain,
but I think they could be modified to make them work nicely.

>... The only real
> difference is that one cannot get rid of overloading of the undesired
> operation. What is actually required. I think that there could be
> situations where it would be useful to disallow an operation in the
> public interface and to override it with something working in the
> private one.

Hmm.  What example?  It seems to me that hiding/disallowing the
operation for the derived type is dishonest, because a client can always
call that operation by converting to the parent type 'Class and
dispatching.

Note that you can say:

    type T is new A with private;
    ...
    type T is new B with record...

where B is derived from A, and has more operations.
This is a useful capability, and is similar to what you asked for above.
The "more operations" are visible only inside T package.
Clients can't convert to B, because they can't see that T is "really"
derived from B.

Here's an idea I've been thinking about for some years, which might
address your desire to "take away" operations:
Define two kinds of inheritance, "is a" inheritance, and "is like a"
inheritance.  When you use "is a" inheritance, you can only *add*
operations, and you can convert to the parent type.  When you use "is
like a" inheritance, you can also take away operations, but you are
forbidden from converting to the parent type.  With "is like a"
inheritance, you are defining a new abstraction that is similar to
the parent, but you don't claim that it "is a" parent, and you don't
want to view the new type *as* a parent.  What do you think?

- Bob



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

* Re: Extension of non-limited type needs limited component
  2002-11-15 10:04           ` Dmitry A. Kazakov
@ 2002-11-15 22:09             ` Robert A Duff
  2002-11-16 12:39               ` Dmitry A. Kazakov
                                 ` (3 more replies)
  0 siblings, 4 replies; 33+ messages in thread
From: Robert A Duff @ 2002-11-15 22:09 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

> In an OO language like Ada 95 is, "limited" makes little sense,
> because it covers only one of many useful alternatives.

But non-limited/limited does not just mean assignment
allowed/disallowed.  How do you propose to deal with all the other
things controlled by this distinction?  For example:

    Non-limited types can have unconstrained aliased components; limited
    types cannot.

    Limited types can have access discriminants; non-limited types
    cannot.

    Limited types can have limited components (like tasks and protected
    objects); non-limited types cannot.

    The current instance of a limited type is aliased, so you can say
    "T'Unchecked_Access" inside type T, to make a pointer to the current
    object of type T.  You can't do that for non-limited.

    (Most) limited types are guaranteed to be passed by reference;
    that's not true for non-limited.

    A function can construct a new object of a non-limited type, and
    return it.  You can't do that for (most) limited types.

The point is that there are some things you can do for limited that you
can't do for non-limited, and vice-versa, so neither is a subset of the
other.  Therefore, you can't derive a limited type from a non-limited
type, nor vice-versa.

By the way, have you read the AARM annotations that explain why we
didn't allow user-defined ":=" procedures?  We certainly wanted to,
but we couldn't figure out how to make it work, so we invented Adjust,
which is not as powerful.  I'd be interested in hearing better ideas
(even though it's probably too late).

- Bob



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

* Re: Extension of non-limited type needs limited component
  2002-11-15 21:41           ` Robert A Duff
@ 2002-11-16  3:54             ` Randy Brukardt
  0 siblings, 0 replies; 33+ messages in thread
From: Randy Brukardt @ 2002-11-16  3:54 UTC (permalink / raw)


Robert A Duff wrote in message ...
>"Randy Brukardt" <randy@rrsoftware.com> writes:
>> I don't recall why you are not allowed to make the extension of the
>> limited type non-limited. (I didn't find anything in the AARM on this
>> subject.)
>
>I don't think it would work, because ":=" on a derived type copies the
>parent part, which is limited, and therefore not copyable:
>...
>The assignment above is copying a task, which is bad news.  It is also
>copying an access discriminant, which is bad news.  Also, the component
>Self of X is supposed to point at X, and the assignment defeats that.


I knew there was a reason, I just couldn't figure out what it was. I'm
surprised that this discussion is not in the AARM, because it is such a
restrictive rule that you'd think that there would have been a
justification for it somewhere.

>I suppose it could work if all ancestor limited types are not private.
>Then we could add a rule saying that deriving a new non-limited type is
>OK if the ancestor types *could have been* non-limited -- that is, they
>don't violate any of the rules for non-limited types (e.g., no access
>discriminants allowed).
>
>But that would be a rather severe restriction -- I *want* most of my
>types to be private.


No, that's not going to work. And, of course, breaking privateness would
also be a bad idea (even though it would work in this case.

>Here's another alternative: you could invent a new kind of type --
>"pseudo-limited".  A pseudo-limited type disallows assignment
>statements, but *also* disallows all the things disallowed for
>non-limited types.  A pseudo-limited type can have pseudo-limited
>components, and non-limited components, but not limited components.
>Then you could have a hierarchy with the root of the tree
>pseudo-limited, with some subbranches being limited and some
non-limited
>(and some pseudo-limited).


That would work, I think.

>Sounds complicated.  I haven't thought it through, so I'm not at all
>sure it even works.


But I have to agree with the 'sounds complicated'. I doubt that this
problem is severe enough to justify a solution like this. (We've had
other problems with simpler solutions shot down, after all.)

            Randy.






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

* Re: Extension of non-limited type needs limited component
  2002-11-15 22:09             ` Robert A Duff
@ 2002-11-16 12:39               ` Dmitry A. Kazakov
  2002-11-16 16:15                 ` Robert A Duff
  2002-11-17 12:26               ` Dale Stanbrough
                                 ` (2 subsequent siblings)
  3 siblings, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2002-11-16 12:39 UTC (permalink / raw)


Robert A Duff wrote:

> Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
> 
>> In an OO language like Ada 95 is, "limited" makes little sense,
>> because it covers only one of many useful alternatives.
> 
> But non-limited/limited does not just mean assignment
> allowed/disallowed.  How do you propose to deal with all the other
> things controlled by this distinction?  For example:
> 
>     Non-limited types can have unconstrained aliased components; limited
>     types cannot.
> 
>     Limited types can have access discriminants; non-limited types
>     cannot.
> 
>     Limited types can have limited components (like tasks and protected
>     objects); non-limited types cannot.
> 
>     The current instance of a limited type is aliased, so you can say
>     "T'Unchecked_Access" inside type T, to make a pointer to the current
>     object of type T.  You can't do that for non-limited.
> 
>     (Most) limited types are guaranteed to be passed by reference;
>     that's not true for non-limited.
> 
>     A function can construct a new object of a non-limited type, and
>     return it.  You can't do that for (most) limited types.

All that are more or less decoupled things. Why should we tie all of them 
under one roof?

> The point is that there are some things you can do for limited that you
> can't do for non-limited, and vice-versa, so neither is a subset of the
> other.  Therefore, you can't derive a limited type from a non-limited
> type, nor vice-versa.
> 
> By the way, have you read the AARM annotations that explain why we
> didn't allow user-defined ":=" procedures?

Yes, however it was some 2 years ago, so will re-read it again.

> We certainly wanted to,
> but we couldn't figure out how to make it work, so we invented Adjust,
> which is not as powerful.  I'd be interested in hearing better ideas
> (even though it's probably too late).

I think that Adjust maybe is just fine. The actual problem is an attempt to 
hide everything from the programmer. Copy+Adjust is a copy constructor, 
fine, but why ":=" should be *always* generated out of it? In my view there 
should be a way to decouple them, i.e. to get rid of the predefined ":=", 
and to define a new one. If a programmer does it, it is now his 
responsibility to ensure that the semantics of ":=" be better close to 
Copy+Adjust. To diminish the consequent mess with inheritance of ":=", one 
could say that if the right parameter is not class-wide, then it is 
covariant, so ":=" has to be either overridden or else disallowed in any 
derived type. [However, I am afraid, that to correctly deal with it one 
would need multiple dispatch anyway.]

-- 
Regards,
Dmitry A. Kazakov
www.dmitry-kazakov.de



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

* Re: Extension of non-limited type needs limited component
  2002-11-15 21:56             ` Robert A Duff
@ 2002-11-16 12:39               ` Dmitry A. Kazakov
  0 siblings, 0 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2002-11-16 12:39 UTC (permalink / raw)


Robert A Duff wrote:

> Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
> 
>> On Fri, 15 Nov 2002 00:30:03 GMT, Robert A Duff
>> <bobduff@shell01.TheWorld.com> wrote:
>> 
>> >Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
> 
>> Sure? And what about this:
>> 
>> type A is tagged ...
>> procedure Foo (L, R : A);
>> 
>> type B is new A with ....
>> 
>> X : A'Class := Some_A;
>> Y : A'Class := Some_B;
>> 
>> Foo (X, Y); -- Oops, dispatching to nowhere!
> 
> True.  But I'm not happy about it.  And it doesn't mean single-argument
> dispatching should be made more dangerous to match double-arg
> dispatching.  ;-)

Of course not. However there is a difference. My example can be cured by 
introducing multiple dispatch. The case when Circle is derived from Ellipse 
and Resize (E : in out Ellipse; X_Size, Y_Size : Distance) has to be 
disallowed cannot be cured at all.

>> Further one can always override with a subroutine that throws
>> Program_Error. Is that better? IMO it is the same.
> 
> Yes, it is the same.  I see no reason to add special syntax to make it
> easy, though.

1. Earlier error detection. If you disallow an operation, then in a statical 
case, you will get a compile-time error

2. Getting rid of overloading contaminations

> Note that Java more-or-less prevents this problem by making exceptions
> part of the visible contract.  I think they got some of the details
> wrong, but they are on the right track.  The Java rules are a pain,
> but I think they could be modified to make them work nicely.

I agree. While developing large programs, tracking down the exceptions 
becomes a real pain. I have no idea how to do it properly, but surely the 
exceptions should be a part of the contract and another important thing, 
there should be a way to somehow tell to "exception when =>", what is the 
full list of the alternatives, so that it could work as safe as "case ... 
when =>" does.

>>... The only real
>> difference is that one cannot get rid of overloading of the undesired
>> operation. What is actually required. I think that there could be
>> situations where it would be useful to disallow an operation in the
>> public interface and to override it with something working in the
>> private one.
> 
> Hmm.  What example?  It seems to me that hiding/disallowing the
> operation for the derived type is dishonest, because a client can always
> call that operation by converting to the parent type 'Class and
> dispatching.

Ah, that is re-dispatch, it is a vicious thing. I wished it to be removed 
from Ada. Converting to Parent'Class should be more than just view change, 
at least in case of disallowing => breaking Parent's contract. It means 
that the result of Parent'Class (A_Child) should a NEW object which is 
really of Parent type and, lo, you can safely dispatch to any operation of 
Parent!

> Note that you can say:
> 
>     type T is new A with private;
>     ...
>     type T is new B with record...
> 
> where B is derived from A, and has more operations.
> This is a useful capability, and is similar to what you asked for above.
> The "more operations" are visible only inside T package.
> Clients can't convert to B, because they can't see that T is "really"
> derived from B.
> 
> Here's an idea I've been thinking about for some years, which might
> address your desire to "take away" operations:
> Define two kinds of inheritance, "is a" inheritance, and "is like a"
> inheritance.  When you use "is a" inheritance, you can only *add*
> operations, and you can convert to the parent type.  When you use "is
> like a" inheritance, you can also take away operations, but you are
> forbidden from converting to the parent type.  With "is like a"
> inheritance, you are defining a new abstraction that is similar to
> the parent, but you don't claim that it "is a" parent, and you don't
> want to view the new type *as* a parent.  What do you think?

It looks very close to my understanding of the problem.

Your "is a" inheritance is one when we inherit both the contract and the 
implementation of the parent type, i.e. we extend it. This is a sort of 
LSP-subtyping, however, not enforced.

"is like a" inheritance is when we inherit only the contract (at least in 
the public part, in the private part it could be still "is a"). For 
instance, let I have the type String, if I derive from it by "is like a", 
then I am absolutely free to implement it as a record.

Then you say that conversion to parent should be forbidden. Why? Because the 
compiler has no clue how to do it? So let's make it a part of the contract. 
I.e. if I derive My_String from String, I should also provide 
My_String->String conversion, if I wish to access in-methods of String. I 
should define My_String<-String if I wish to access out-methods of String. 
I should define both if I wish to access everything.

-- 
Regards,
Dmitry A. Kazakov
www.dmitry-kazakov.de



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

* Re: Extension of non-limited type needs limited component
  2002-11-16 12:39               ` Dmitry A. Kazakov
@ 2002-11-16 16:15                 ` Robert A Duff
  2002-11-17 11:14                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 33+ messages in thread
From: Robert A Duff @ 2002-11-16 16:15 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> All that are more or less decoupled things. Why should we tie all of them 
               ^^^^^^^^^^^^
> under one roof?

Less, I'd say.  ;-)

They are all closely related to whether you can copy the thing.
To answer my question properly, you would have to explain exactly
when each of the things I mentioned should be allowed.  That's not
easy.  No, I don't expect anybody to do all that work for an informal
usenet discussion.  ;-)

>...[However, I am afraid, that to correctly deal with it one 
> would need multiple dispatch anyway.]

I like the idea of multi-dispatch, but all of the languages I've seen
that support it seem confusing and/or error-prone.  You need a rule that
makes it predictable which method(s) will be called in every case.  Not
just predictable in a formal sense, but predictable by mere mortal
programmers -- i.e. the programmer's guess should match what the
compiler actually does.  And you need a way to prevent ambiguities --
cases where two different methods are "reasonable" should be forbidden,
preferably at compile time.  And you need a way to organize the code --
with single dispatch, you can put the "methods" with the "type" (or
"class" or whatever).

- Bob



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

* Re: Extension of non-limited type needs limited component
  2002-11-16 16:15                 ` Robert A Duff
@ 2002-11-17 11:14                   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2002-11-17 11:14 UTC (permalink / raw)


Robert A Duff wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> All that are more or less decoupled things. Why should we tie all of them
>                ^^^^^^^^^^^^
>> under one roof?
> 
> Less, I'd say.  ;-)
> 
> They are all closely related to whether you can copy the thing.

Here we are. Why copying should be tied with:

by-reference vs. not
an ability to have uninitialized objects
an ability to reference objects
inheritance
aggregation
...

All this big variety of possibilities surely influence each other, but this 
does not mean that you can break all this into a simple: 
limited/non-limited.

> To answer my question properly, you would have to explain exactly
> when each of the things I mentioned should be allowed.

I think that it would be better that the properties of an abstract type 
could be specified more directly. Currently we a doing it indirectly and 
very roughly, because the language has its own set of type properties which 
are not well mapped to ADT, for the programmer's point of view. To require 
all objects to be initialized is a damn simple thing. But to achieve this, 
one should make it discriminated! And then, no arrays of the type! Why all 
this? It is because of a wrong idea to control the program semantics. To 
put it very extremely, if a programmer wants to use the character sequence 
":=" for his type, let him do it. It is not the language responsibility to 
make this ":=" semantically correct. The only thing a good safe language 
should do is to make the programmer aware of the consequences. For 
instance, require overriding of the user-defined ":=", in case of 
inheritance. Clarify that ":=" in declarations is not an assignment, but a 
copy-constructor. That ":=" will never be imlicitly used by the compiler to 
copy the components of the type, so if ":=" is defined, then Adjust has to 
be overridden, etc.

> That's not
> easy.  No, I don't expect anybody to do all that work for an informal
> usenet discussion.  ;-)

(:-))

>>...[However, I am afraid, that to correctly deal with it one
>> would need multiple dispatch anyway.]
> 
> I like the idea of multi-dispatch, but all of the languages I've seen
> that support it seem confusing and/or error-prone.

There should be a consistent solution. Otherwise the whole idea of dispatch 
was wrong. [I do not exclude this possibility]

> You need a rule that
> makes it predictable which method(s) will be called in every case.  Not
> just predictable in a formal sense, but predictable by mere mortal
> programmers -- i.e. the programmer's guess should match what the
> compiler actually does.

The major problem I see is a geometric exposion of the methods to be 
overriden. In the case of binary operations it is three methods. If one 
gets overridden then all others shall be too. 

> And you need a way to prevent ambiguities --
> cases where two different methods are "reasonable" should be forbidden,
> preferably at compile time.

This could be done by a requirement of explicit overriding in all cases of 
potential ambiguities, but the consequence is the geometric explosion.

> And you need a way to organize the code --
> with single dispatch, you can put the "methods" with the "type" (or
> "class" or whatever).

Yes, the freezing rules. There is practically no other solution than Ada's 
one: all methods to be declared before the first use. However it is not so 
restrictive as it might look.

-- 
Regards,
Dmitry A. Kazakov
www.dmitry-kazakov.de



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

* Re: Extension of non-limited type needs limited component
  2002-11-15 22:09             ` Robert A Duff
  2002-11-16 12:39               ` Dmitry A. Kazakov
@ 2002-11-17 12:26               ` Dale Stanbrough
  2002-11-18 20:33                 ` Randy Brukardt
  2002-11-18 21:48               ` Eric
  2002-11-19 14:38               ` Eric
  3 siblings, 1 reply; 33+ messages in thread
From: Dale Stanbrough @ 2002-11-17 12:26 UTC (permalink / raw)


In article <wccbs4q8oys.fsf@shell01.TheWorld.com>,
 Robert A Duff <bobduff@shell01.TheWorld.com> wrote:

> By the way, have you read the AARM annotations that explain why we
> didn't allow user-defined ":=" procedures?  We certainly wanted to,
> but we couldn't figure out how to make it work, so we invented Adjust,
> which is not as powerful.  I'd be interested in hearing better ideas
> (even though it's probably too late).

It seemed to me that the main problem with with discriminants 
in the tagged types. Would it not have been simpler just to 
disallow them? Would this have allowed you to have a ":="
procedure?

Dale



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

* Re: Extension of non-limited type needs limited component
  2002-11-17 12:26               ` Dale Stanbrough
@ 2002-11-18 20:33                 ` Randy Brukardt
  0 siblings, 0 replies; 33+ messages in thread
From: Randy Brukardt @ 2002-11-18 20:33 UTC (permalink / raw)


Dale Stanbrough wrote in message ...
>In article <wccbs4q8oys.fsf@shell01.TheWorld.com>,
> Robert A Duff <bobduff@shell01.TheWorld.com> wrote:
>
>> By the way, have you read the AARM annotations that explain why we
>> didn't allow user-defined ":=" procedures?  We certainly wanted to,
>> but we couldn't figure out how to make it work, so we invented
Adjust,
>> which is not as powerful.  I'd be interested in hearing better ideas
>> (even though it's probably too late).
>
>It seemed to me that the main problem with with discriminants
>in the tagged types. Would it not have been simpler just to
>disallow them? Would this have allowed you to have a ":="
>procedure?


No, the main problem is components of controlled types used in untagged
variant records. We hardly could disallow discriminants on all records!
We can't disallow components of controlled types that are
discriminant-dependent, because that would be a generic contract
violation. (Tagged types match generic formal private types.)
Assume-the-worst here would be very incompatible.

So, to get a first-class ":=", you'd have to make seriously incompatible
changes to Ada 83. (Not to mention Ada 95.) That just doesn't work.

To show the problem in short, assume that 'Window' is a controlled type
with a user-defined ":=".

     type Prob (B : Boolean := True) is record
         case B is
              when True => W : Window;
              when False => null;
         end case;
    end record;

    Obj_False : Prob (False);
    Obj_True : Prob (True);
    Obj : Prob;

    Obj := Obj_False; -- Component W disappears in this assignment. (It
is Finalized only.)
    Obj := Obj_True; -- Component W appears in this assignment. (It is
Adjusted only.)

So, what are the parameters to a user-defined ":="??

The problem is even more fun when it happens in a discriminant-dependent
array.

One of the nice things (from an implementability perspective) about the
Adjust solution is that it composes nicely. User-defined ":=" does not
seem to have this property unless disappearing components are somehow
disallowed.

              Randy Brukardt.








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

* Re: Extension of non-limited type needs limited component
  2002-11-15 22:09             ` Robert A Duff
  2002-11-16 12:39               ` Dmitry A. Kazakov
  2002-11-17 12:26               ` Dale Stanbrough
@ 2002-11-18 21:48               ` Eric
  2002-11-19 14:38               ` Eric
  3 siblings, 0 replies; 33+ messages in thread
From: Eric @ 2002-11-18 21:48 UTC (permalink / raw)


"Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message
news:wccbs4q8oys.fsf@shell01.TheWorld.com...
[SNIP]>
> By the way, have you read the AARM annotations that explain why we
> didn't allow user-defined ":=" procedures?  We certainly wanted to,
> but we couldn't figure out how to make it work, so we invented Adjust,
> which is not as powerful.  I'd be interested in hearing better ideas
> (even though it's probably too late).
>
> - Bob

Hi,

(I have reproduced the relevant annotation at the end.)

The following solutions come to mind (I haven't gone through all the
possible ramifications and potential problems):

1. (The example in the AARM specifically refers to mutable,
   unconstrained record targets.)  Consider an 'operator' "<-"
   (which is the current Ada implemented 'move of value') to
   disambiguate the procedure ":=". So the present non-limited
   controlled implementation of procedure ":=" looks like:

        procedure ":="(Target : in out TYPE; Source : in TYPE) is
           [anonymous_object : TYPE <- Source;]
        begin
           Finalize(Target);
           Target <- anonymous_object;
           [Finalize(anonymous_object);]
          Adjust(Target);
        end ":=";

  Since finalization should (must) always be done before the
  target is overwritten, Finalize and "<-" (plus any other
  constraint checks) can be combined into the attribute
  Uncontrolled_Assign so that the above looks like:

        procedure ":="(Target : in out TYPE; Source : in TYPE) is
           [anonymous_object : TYPE <- Source;]
        begin
           Target'Uncontrolled_Assign(anonymous_object);
           [Finalize(anonymous_object);]
          Adjust(Target);
        end ":=";

  Thus: a user defined implementation of ":=" could be:

        procedure ":="(Target : in out TYPE; Source : in TYPE) is
           New_Source : TYPE [<- ...]; -- Finalized on procedure return
        begin

           -- Fiddle with New_Source based on both Target and
           -- Source (and constraints)
           Target'Uncontrolled_Assign(New_Source);
           -- Fiddle with Target (probably unneeded)
        end ":=";

  Note that this use of Uncontrolled_Assign would probably
  require a recheck of any constraints.

  The only problem of significance that I see is the initiation
  of New_Source and how to prevent an infinite loop if it is
  initiated (using ":=") to Source.

  Also, as ":=" is defaulted to call Adjust, current code would
  not need be rewritten.

2.  Change the assignment sequence from:

        anonymous_object <- Source
        Finalize(Target)
        Target <-anonymous_object;
        Finalize(anonymous_object)
        Adjust(Target)

  To:

        anonymous_object <- Source
        other_anonymous_object <- Target
        Finalize(Target)
        Target <- anonymous_object;
        Finalize(anonymous_object)
        Adjust(Target, other_anonymous_object) -- *****
        Finalize(other_anonymous_object)

  with Adjust taking a second 'in' argument.

  This would allow Adjust to make use of the original value of
  Target.  Not as useful as the above, but I have already met
  code where it would be useful.


Here is the annotation (reformatted from Section 7.6 of the AARM):

Reason: An alternative design for user-defined assignment might
involve an Assign operation instead of Adjust:

 procedure Assign(Target : in out Controlled;
                             Source : in out Controlled);

Or perhaps even a syntax like this:

 procedure ":="(Target : in out Controlled;
                        Source : in out Controlled);

Assign (or ":=") would have the responsibility of doing the copy,
as well as whatever else is necessary. This would have the
advantage that the Assign operation knows about both the target
and the source at the same time - it would be possible to do
things like reuse storage belonging to the target, for example,
which Adjust cannot do. However, this sort of design would not
work in the case of unconstrained discriminated variables,
because there is no way to change the discriminants
individually. For example:

type Mutable(D : Integer := 0) is
  record
    X : Array_Of_Controlled_Things(1..D);
    case D is when 17 => Y : Controlled_Thing;
              when others => null;
    end D;
  end record;

An assignment to an unconstrained variable of type Mutable can
cause some of the components of X, and the component Y, to appear
and/or disappear. There is no way to write the Assign operation
to handle this sort of case.  Forbidding such cases is not an
option - it would cause generic contract model violations.


Michael Borek "Death before Dishonour; Beer before Lunch"

Michael Borek Software Services
http://users.eastlink.ca/~borekking/professionalhome.html







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

* Re: Extension of non-limited type needs limited component
  2002-11-15 22:09             ` Robert A Duff
                                 ` (2 preceding siblings ...)
  2002-11-18 21:48               ` Eric
@ 2002-11-19 14:38               ` Eric
  3 siblings, 0 replies; 33+ messages in thread
From: Eric @ 2002-11-19 14:38 UTC (permalink / raw)


(Forgive me if this appears twice.  My ISP went down just after my first
submission and I haven't seen it posted after more than a day)

"Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message
news:wccbs4q8oys.fsf@shell01.TheWorld.com...
[SNIP]
>
> By the way, have you read the AARM annotations that explain why we
> didn't allow user-defined ":=" procedures?  We certainly wanted to,
> but we couldn't figure out how to make it work, so we invented Adjust,
> which is not as powerful.  I'd be interested in hearing better ideas
> (even though it's probably too late).
>
> - Bob

Hi,

(I have reproduced the relevant annotation at the end.)

The following come to mind (I haven't gone through all the
possible ramifications and potential problems):

1. (The example in the AARM specifically refers to mutable,
   unconstrained record targets.)  Consider an 'operator' "<-"
   (which is the current Ada implemented 'move of value') to
   disambiguate the procedure ":=". So the present non-limited
   controlled implementation of procedure ":=" looks like:

        procedure ":="(Target : in out TYPE; Source : in TYPE) is
          [anonymous_object : TYPE <- Source;]
        begin
          Finalize(Target);
          Target <- anonymous_object;
          [Finalize(anonymous_object);]
         Adjust(Target);
        end ":=";

  Since finalization should (must) always be done before the
  target is overwritten, Finalize and "<-" (plus any other
  constraint checks) can be combined into the attribute
  Uncontrolled_Assign so that the above looks like:

        procedure ":="(Target : in out TYPE; Source : in TYPE) is
          [anonymous_object : TYPE <- Source;]
        begin
          Target'Uncontrolled_Assign(anonymous_object);
          [Finalize(anonymous_object);]
         Adjust(Target);
        end ":=";

  Thus: a user defined implementation of ":=" could be:

        procedure ":="(Target : in out TYPE; Source : in TYPE) is
          New_Source : TYPE [<- ...]; -- Finalized on procedure return
        begin
          -- Fiddle with New_Source based on both Target and
          -- Source (and constraints)
          Target'Uncontrolled_Assign(New_Source);
          -- Fiddle with Target (probably unneeded)
        end ":=";

  Note that this use of Uncontrolled_Assign would probably
  require a recheck of any constraints.

  The only problem of significance that I see is the initiation
  of New_Source and how to prevent an infinite loop if it is
  initiated (using ":=") to Source.  What is needed is programmer
  access to the "not really assignment" assign as is found in
  passing arguments to/from procedures.  Perhaps:
  New_Source : TYPE'(<initial_value>)

  Also, as ":=" is defaulted to call Adjust, current code would
  not need be rewritten.


2.  Change the assignment sequence from:

        anonymous_object <- Source;
        Finalize(Target);
        Target <- anonymous_object;
        Finalize(anonymous_object)
        Adjust(Target);

  To:

        anonymous_object <- Source;
        other_anonymous_object <- Target;
        Finalize(Target);
        Target <- anonymous_object;
        Finalize(anonymous_object);
        Adjust(Target, other_anonymous_object);
        Finalize(other_anonymous_object)

  with Adjust taking a second 'in' argument.

  This would allow Adjust to make use of the original value of
  Target.  Not as useful as the above, but I have already met
  code where it would be useful.


Here is the annotation (from Section 7.6 of the AARM):

Reason: An alternative design for user-defined assignment might
involve an Assign operation instead of Adjust:

 procedure Assign(Target : in out Controlled;
                  Source : in out Controlled);

Or perhaps even a syntax like this:

 procedure ":="(Target : in out Controlled;
                Source : in out Controlled);

Assign (or ":=") would have the responsibility of doing the copy,
as well as whatever else is necessary. This would have the
advantage that the Assign operation knows about both the target
and the source at the same time - it would be possible to do
things like reuse storage belonging to the target, for example,
which Adjust cannot do. However, this sort of design would not
work in the case of unconstrained discriminated variables,
because there is no way to change the discriminants
individually. For example:

type Mutable(D : Integer := 0) is
  record
    X : Array_Of_Controlled_Things(1..D);
    case D is when 17 => Y : Controlled_Thing;
              when others => null;
    end D;
  end record;

An assignment to an unconstrained variable of type Mutable can
cause some of the components of X, and the component Y, to appear
and/or disappear. There is no way to write the Assign operation
to handle this sort of case.  Forbidding such cases is not an
option - it would cause generic contract model violations.






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

end of thread, other threads:[~2002-11-19 14:38 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-11-13 10:03 Extension of non-limited type needs limited component Mike
2002-11-13 12:06 ` Jean-Pierre Rosen
2002-11-14  9:26   ` Mike
2002-11-14 11:43     ` David C. Hoos, Sr.
2002-11-14 12:33     ` Jean-Pierre Rosen
2002-11-14 14:27       ` Dmitry A. Kazakov
2002-11-14 19:25         ` Randy Brukardt
2002-11-15 10:04           ` Dmitry A. Kazakov
2002-11-15 22:09             ` Robert A Duff
2002-11-16 12:39               ` Dmitry A. Kazakov
2002-11-16 16:15                 ` Robert A Duff
2002-11-17 11:14                   ` Dmitry A. Kazakov
2002-11-17 12:26               ` Dale Stanbrough
2002-11-18 20:33                 ` Randy Brukardt
2002-11-18 21:48               ` Eric
2002-11-19 14:38               ` Eric
2002-11-15 21:41           ` Robert A Duff
2002-11-16  3:54             ` Randy Brukardt
2002-11-15  0:30         ` Robert A Duff
2002-11-15 10:22           ` Dmitry A. Kazakov
2002-11-15 21:56             ` Robert A Duff
2002-11-16 12:39               ` Dmitry A. Kazakov
2002-11-14 23:39     ` Robert A Duff
2002-11-15 21:51       ` Mike
2002-11-13 14:28 ` Robert A Duff
2002-11-14  9:33   ` Mike
2002-11-14  9:35     ` Lutz Donnerhacke
2002-11-14 21:41     ` Robert A Duff
  -- strict thread matches above, loose matches on Subject: below --
2002-11-15 10:47 Grein, Christoph
2002-11-15 12:12 ` Dmitry A. Kazakov
2002-11-15 13:29   ` Jean-Pierre Rosen
2002-11-15 14:34     ` Dmitry A. Kazakov
2002-11-15 21:26     ` Robert A Duff

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox